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

VxWorks

开发平台:

C/C++

  1. /* ioApicIntr.c - Intel IO APIC/xAPIC driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01g,08mar02,hdn  updated ioApicInit(), added ioApicEnable()
  8.  removed redTable, added ioApicRedS/Get() for HTT (spr 73738)
  9. 01f,29nov01,hdn  doc update for 5.5
  10. 01e,07nov01,hdn  updated the interrupt delivery type setting
  11.  added new routine ioApicIrqMove ()
  12. 01d,26jun01,hdn  added support for Pentium4 IO xAPIC
  13.  moved show routine to ioApicIntrShow.c
  14. 01c,17nov00,mks  importing loApicBase and loApicId for successful compilation,
  15.                  added redTablePtr and made redTableNumEnt global. SPR 35733.
  16. 01b,25mar98,hdn  re-written.
  17. 01a,20jun97,sub  written.
  18. */
  19. /*
  20. DESCRIPTION
  21. This module is a driver for the IO APIC/xAPIC (Advanced Programmable 
  22. Interrupt Controller) for P6 (PentiumPro, II, III) family processors
  23. and P7 (Pentium4) family processors.  The IO APIC/xAPIC is included 
  24. in the Intel's system chip set, such as ICH2.  Software intervention 
  25. may be required to enable the IO APIC/xAPIC in some chip sets.
  26. The 8259A interrupt controller is intended for use in a uni-processor
  27. system, IO APIC can be used in either a uni-processor or multi-processor
  28. system.  The IO APIC handles interrupts very differently than the 8259A.
  29. Briefly, these differences are:
  30.  - Method of Interrupt Transmission. The IO APIC transmits interrupts 
  31.    through a 3-wire bus and interrupts are handled without the need for
  32.    the processor to run an interrupt acknowledge cycle.
  33.  - Interrupt Priority. The priority of interrupts in the IO APIC is 
  34.    independent of the interrupt number.  For example, interrupt 10 can 
  35.    be given a higher priority than interrupt 3.
  36.  - More Interrupts. The IO APIC supports a total of 24 interrupts.
  37. The IO APIC unit consists of a set of interrupt input signals, a 24-entry
  38. by 64-bit Interrupt Redirection Table, programmable registers, and a message
  39. unit for sending and receiving APIC messages over the APIC bus or the 
  40. Front-Side (system) bus.  IO devices inject interrupts into the system by 
  41. asserting one of the interrupt lines to the IO APIC.  The IO APIC selects the 
  42. corresponding entry in the Redirection Table and uses the information in that 
  43. entry to format an interrupt request message.  Each entry in the Redirection 
  44. Table can be individually programmed to indicate edge/level sensitive interrupt 
  45. signals, the interrupt vector and priority, the destination processor, and how 
  46. the processor is selected (statically and dynamically).  The information in 
  47. the table is used to transmit a message to other APIC units (via the APIC bus
  48. or the Front-Side (system) bus).
  49. IO APIC is used in the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP).
  50. The base address of IO APIC is determined in loApicInit() and stored in the
  51. global variable ioApicBase and ioApicData.  ioApicInit() initializes the IO 
  52. APIC with information stored in ioApicRed0_15 and ioApicRed16_23.
  53. The ioApicRed0_15 is the default lower 32 bit value of the redirection table 
  54. entries for IRQ 0 to 15 that are edge triggered positive high, and
  55. the ioApicRed16_23 is for IRQ 16 to 23 that are level triggered positive low.
  56. ioApicRedSet() and ioApicRedGet() are used to access the redirection table.
  57. ioApicEnable() enables the IO APIC or xAPIC.  ioApicIrqSet() set the specific
  58. IRQ to be delivered to the specific Local APIC.
  59. This implementation doesn't support multiple IO APIC configuration.
  60. INCLUDE FILES: loApic.h, ioApic.h
  61. SEE ALSO: loApicIntr.c
  62. */
  63. /* includes */
  64. #include "intLib.h"
  65. #include "drv/intrCtl/loApic.h"
  66. #include "drv/intrCtl/ioApic.h"
  67. /* externs */
  68. IMPORT UINT32 ioApicBase; /* IO APIC register select (index) address */
  69. IMPORT UINT32 ioApicData; /* IO APIC window (data) addr */
  70. IMPORT UINT32 loApicBase; /* addr of Local APIC */
  71. IMPORT UINT32 loApicId; /* local APIC Id */
  72. IMPORT UINT32 sysProcessor; /* 0=386, 1=486, 2=P5, 4=P6, 5=P7 */
  73. IMPORT INT8   excCallTbl []; /* table of Calls in excALib.s */
  74. IMPORT INT32  sysCsInt; /* CS for interrupt */
  75. IMPORT VOIDFUNCPTR intEoiGet;   /* function used in intConnect() for B/EOI */
  76. IMPORT UINT32 sysIntIdtType; /* IDT entry type */
  77. IMPORT BOOL   sysBp; /* TRUE(default) for BP, FALSE for AP */
  78. IMPORT void   sysPciIoApicEnable(); /* enable/disable the IO APIC */
  79. IMPORT void   sysPciPirqEnable();   /* enable/disable the PCI PIRQ */
  80. /* globals */
  81. UINT32 ioApicVersion; /* IO APIC version register */
  82. UINT32 ioApicRedEntries = 24; /* default IO APIC redirection table entries */
  83. UINT32 ioApicRed0_15 = IOAPIC_EDGE | IOAPIC_HIGH | IOAPIC_FIXED;
  84. UINT32 ioApicRed16_23 = IOAPIC_LEVEL | IOAPIC_LOW | IOAPIC_FIXED;
  85. /* locals */
  86. LOCAL UINT32 * ioApicIntTable;
  87. /* forward declarations */
  88. STATUS ioApicIrqMove (INT32 srcIrq, INT32 dstIrq); /* not published yet */
  89. /*******************************************************************************
  90. *
  91. * ioApicInit - initialize the IO APIC or xAPIC
  92. *
  93. * This routine initializes the IO APIC or xAPIC.
  94. *
  95. */
  96. STATUS ioApicInit (void)
  97.     {
  98.     INT32 ix;
  99.     INT32 offset;
  100.     /* enable the IOAPIC */
  101.     if (sysBp)
  102.         ioApicEnable (TRUE);
  103.     /* get the IOAPIC version */
  104.     ioApicVersion = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
  105.     /* get a number of redirection table entries */
  106.     ioApicRedEntries = ((ioApicVersion & IOAPIC_MRE_MASK) >> 16) + 1;
  107.     /* allocate memory for saving the interrupt mask bit */
  108.     ioApicIntTable = (UINT32 *) memalign (_CACHE_ALIGN_SIZE,
  109.      ioApicRedEntries * sizeof (UINT32));
  110.     /* return if it is not the Boot Processor (BP) */
  111.     if (sysBp == FALSE)
  112.         return (OK);
  113.     /* set the IOAPIC bus arbitration ID */
  114.     ioApicSet (ioApicBase, ioApicData, IOAPIC_ID,
  115.             ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
  116.     /* set the int-delivery type to Front Side Bus, not APIC Serial Bus */
  117.     if (sysProcessor == X86CPU_PENTIUM4)
  118.         ioApicSet (ioApicBase, ioApicData, IOAPIC_BOOT, IOAPIC_DT_FS);
  119.     /* initialize the redirection table with the default value */
  120.     for (ix = 0; ix < ioApicRedEntries; ix++)
  121. {
  122. offset = IOAPIC_REDTBL + (ix * 2);
  123. if (ix < 16)
  124.     {
  125.     ioApicSet (ioApicBase, ioApicData, offset,
  126.         IOAPIC_INT_MASK | IOAPIC_PHYSICAL |
  127.         ioApicRed0_15 | sysInumTbl[ix]);
  128.     }
  129. else
  130.     {
  131.     ioApicSet (ioApicBase, ioApicData, offset,
  132.         IOAPIC_INT_MASK | IOAPIC_PHYSICAL |
  133.         ioApicRed16_23 | sysInumTbl[ix]);
  134.     }
  135.         ioApicSet (ioApicBase, ioApicData, offset + 1, (loApicId  << 24));
  136. }
  137.     return (OK);
  138.     }
  139. /*******************************************************************************
  140. *
  141. * ioApicEnable - enable or disable the IO xAPIC in ICHx
  142. *
  143. * This routine enables or disables the IO xAPIC in ICHx.  If the parameter is 
  144. * TRUE, the IO xAPIC in ICHx is enabled and the default ISA IRQ routing 
  145. * information is saved in the table.  If the parameter is FALSE, the IO xAPIC
  146. * in ICHx is disabled.
  147. *
  148. * RETURNS: N/A
  149. */
  150. void ioApicEnable
  151.     (
  152.     BOOL enable /* enable the IO xAPIC in ICHx */
  153.     )
  154.     {
  155.     /* enables or disables the IO APIC */
  156.     sysPciIoApicEnable (enable);
  157.     /* enables or disables the PIRQ direct handling */
  158.     
  159.     sysPciPirqEnable (enable);
  160.     }
  161. /*******************************************************************************
  162. *
  163. * ioApicIntEoi -  send EOI (End Of Interrupt) signal to IO APIC
  164. *
  165. * This routine sends an EOI signal to the IO APIC's interrupting source.
  166. *
  167. * RETURNS: N/A
  168. */
  169. LOCAL void ioApicIntEoi 
  170.     (
  171.     INT32 irqNo /* INTIN number to send EOI */
  172.     )
  173.     {
  174. #ifdef SYS_INT_DEBUG
  175.     extern UINT32 sysIntCount [];
  176.     sysIntCount [irq]++;
  177. #endif /* SYS_INT_DEBUG */
  178. #if FALSE /* don't need it for now */
  179.     if (ioApicVersion & IOAPIC_PRQ)
  180.         *(int *)(ioApicBase + IOAPIC_EOI) = INT_NUM_GET(irq);
  181. #endif
  182.     *(int *)(loApicBase + LOAPIC_EOI) = 0;
  183.     }
  184. /*******************************************************************************
  185. *
  186. * ioApicIntEnable - enable a specified APIC interrupt input line
  187. *
  188. * This routine enables a specified APIC interrupt input line.
  189. *
  190. * RETURNS: OK or ERROR if the interrupt input line number is invalid 
  191. *
  192. * SEE ALSO: ioApicIntDisable()
  193. *
  194. * ARGSUSED0
  195. */
  196. LOCAL STATUS ioApicIntEnable
  197.     (
  198.     INT32 irqNo /* INTIN number to enable */
  199.     )
  200.     {
  201.     INT32 offset = IOAPIC_REDTBL + (irqNo * 2);
  202.     /* check if IRQ is within range */
  203.     if (irqNo >= ioApicRedEntries)
  204. return (ERROR);
  205.     /* set the destination address (my APIC ID), and enable the interrupt */
  206.     ioApicSet (ioApicBase, ioApicData, offset + 1, (loApicId << 24));
  207.     ioApicSet (ioApicBase, ioApicData, offset, 
  208.        ioApicGet (ioApicBase, ioApicData, offset) & ~IOAPIC_INT_MASK);
  209.     return (OK);
  210.     }
  211. /*******************************************************************************
  212. *
  213. * ioApicIntDisable - disable a specified APIC interrupt input line
  214. *
  215. * This routine disables a specified APIC interrupt input line.
  216. *
  217. * RETURNS: OK or ERROR if the interrupt input line number is invalid 
  218. *
  219. * SEE ALSO: ioApicIntEnable()
  220. *
  221. * ARGSUSED0
  222. */
  223. LOCAL STATUS ioApicIntDisable
  224.     (
  225.     INT32 irqNo /* INTIN number to disable */
  226.     )
  227.     {
  228.     INT32 offset = IOAPIC_REDTBL + (irqNo * 2);
  229.     /* check if IRQ is within range */
  230.     if (irqNo >= ioApicRedEntries)
  231. return (ERROR);
  232.     /* disable the interrupt */
  233.     ioApicSet (ioApicBase, ioApicData, offset, 
  234.        ioApicGet (ioApicBase, ioApicData, offset) | IOAPIC_INT_MASK);
  235.     return (OK);
  236.     }
  237. /*******************************************************************************
  238. *
  239. * ioApicIntLock - lock out all IO APIC interrupts
  240. *
  241. * This routine saves the mask and locks out all IO APIC interrupts.
  242. * It should be called in the interrupt disable state(IF bit is 0).
  243. *
  244. * RETURNS: N/A 
  245. *
  246. * SEE ALSO: ioApicIntUnlock()
  247. *
  248. * ARGSUSED0
  249. */
  250. LOCAL VOID ioApicIntLock (void)
  251.     {
  252.     INT32 ix;
  253.     INT32 upper32;
  254.     INT32 lower32;
  255.     for (ix = 0; ix < ioApicRedEntries; ix++) 
  256. {
  257.      ioApicRedGet (ix, &upper32, &lower32);
  258. /* lock if the destination is my Local APIC and unlocked */
  259. if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId) &&
  260.     ((lower32 & IOAPIC_INT_MASK) == 0))
  261.     {
  262.          ioApicSet (ioApicBase, ioApicData, IOAPIC_REDTBL + (ix *2),
  263.                     lower32 | IOAPIC_INT_MASK);
  264.     *(ioApicIntTable + ix) = lower32; /* save the old state */
  265.     }
  266. }
  267.     }
  268. /*******************************************************************************
  269. *
  270. * ioApicIntUnlock - unlock the IO APIC interrupts
  271. *
  272. * This routine restores the mask and unlocks the IO APIC interrupts
  273. * It should be called in the interrupt disable state(IF bit is 0).
  274. *
  275. * RETURNS: N/A 
  276. *
  277. * SEE ALSO: ioApicIntLock()
  278. *
  279. * ARGSUSED0
  280. */
  281. LOCAL VOID ioApicIntUnlock (void)
  282.     {
  283.     INT32 ix;
  284.     INT32 upper32;
  285.     INT32 lower32;
  286.     for (ix = 0; ix < ioApicRedEntries; ix++)
  287. {
  288.      ioApicRedGet (ix, &upper32, &lower32);
  289. /* unlock if the destination is my Local APIC and unlocked */
  290. if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId) &&
  291.     ((*(ioApicIntTable + ix) & IOAPIC_INT_MASK) == 0))
  292.     {
  293.          ioApicSet (ioApicBase, ioApicData, IOAPIC_REDTBL + (ix *2),
  294.                     lower32 & ~IOAPIC_INT_MASK);
  295.     }
  296. }
  297.     }
  298. /*******************************************************************************
  299. *
  300. * ioApicGet - get a value from the IO APIC register.
  301. *
  302. * This routine gets a value from the IO APIC register.
  303. *
  304. * RETURNS: A value of the IO APIC register.
  305. */
  306. INT32 ioApicGet
  307.     (
  308.     UINT32 index, /* IO register select (index) */
  309.     UINT32 data, /* IO window (data) */
  310.     INT32  offset /* offset to the register */
  311.     )
  312.     {
  313.     INT32 value;
  314.     INT32 oldLevel;
  315.     oldLevel = intLock (); /* LOCK INTERRUPT */
  316.     *(char *)index = (char)offset; /* select the register */
  317.     value = *(int *)data; /* must be a 32bit read */
  318.     intUnlock (oldLevel); /* UNLOCK */
  319.     return (value);
  320.     }
  321. /*******************************************************************************
  322. *
  323. * ioApicSet - set a value into the IO APIC register.
  324. *
  325. * This routine sets a value into the IO APIC register.
  326. *
  327. * RETURNS: N/A
  328. */
  329. void ioApicSet
  330.     (
  331.     UINT32 index, /* IO register select (index) */
  332.     UINT32 data, /* IO window (data) */
  333.     INT32  offset, /* offset to the register */
  334.     INT32  value /* value to set the register */
  335.     )
  336.     {
  337.     INT32 oldLevel;
  338.     oldLevel = intLock (); /* LOCK INTERRUPT */
  339.     *(char *)index = (char)offset; /* select the register */
  340.     *(int *)data = value; /* must be a 32bit write */
  341.     intUnlock (oldLevel); /* UNLOCK */
  342.     }
  343. /*******************************************************************************
  344. *
  345. * ioApicRedGet - get a specified entry in the Redirection Table
  346. *
  347. * This routine gets a specified entry in the Redirection Table
  348. *
  349. * RETURNS: OK, or ERROR if intNum is out of range
  350. */
  351. STATUS ioApicRedGet
  352.     (
  353.     INT32 irq, /* index of the table */
  354.     INT32 * pUpper32, /* upper 32 bit (MS LONG) */
  355.     INT32 * pLower32 /* lower 32 bit (LS LONG) */
  356.     )
  357.     {
  358.     INT32 offset = IOAPIC_REDTBL + (irq * 2);
  359.     if (irq >= ioApicRedEntries)
  360. return (ERROR);
  361.     *pLower32 = ioApicGet (ioApicBase, ioApicData, offset);
  362.     *pUpper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
  363.     return (OK);
  364.     }
  365. /*******************************************************************************
  366. *
  367. * ioApicRedSet - set a specified entry in the Redirection Table
  368. *
  369. * This routine sets a specified entry in the Redirection Table
  370. *
  371. * RETURNS: OK, or ERROR if intNum is out of range
  372. */
  373. STATUS ioApicRedSet
  374.     (
  375.     INT32 irq, /* index of the table */
  376.     INT32 upper32, /* upper 32 bit (MS LONG) */
  377.     INT32 lower32 /* lower 32 bit (LS LONG) */
  378.     )
  379.     {
  380.     INT32 offset = IOAPIC_REDTBL + (irq * 2);
  381.     if (irq >= ioApicRedEntries)
  382. return (ERROR);
  383.     ioApicSet (ioApicBase, ioApicData, offset, lower32);
  384.     ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
  385.     return (OK);
  386.     }
  387. /*******************************************************************************
  388. *
  389. * ioApicIrqMove - move interrupt handler from source IRQ to destination IRQ
  390. *
  391. * This routine moves the interrupt handler from the source IRQ to the 
  392. * destination IRQ.  If the source IRQ's interrupt handler is the default 
  393. * handler, it just returns.  Otherwise it is moved and the destination IRQ's 
  394. * vector table entry will be overridden.  This routine is for the chipset
  395. * that have programmable IRQ capability.  This routine should be called at
  396. * the initialization time, otherwise there are no guarantee for losing 
  397. * interrupts.  The polarity and the trigger mode of the IRQ is not changed.
  398. *
  399. * RETURNS: OK, or ERROR if the source intHandler is the default handler.
  400. */
  401. STATUS ioApicIrqMove
  402.     (
  403.     INT32 srcIrq, /* source IRQ moving from */
  404.     INT32 dstIrq /* destination IRQ moving to */
  405.     )
  406.     {
  407.     FUNCPTR intHandler; /* interrupt handler */
  408.     INT32 idtType; /* IDT type */
  409.     INT32 selector; /* code selector */
  410.     INT32 srcInum = INT_NUM_GET (srcIrq);
  411.     INT32 dstInum = INT_NUM_GET (dstIrq);
  412.     INT8 * pCode; /* pointer to intConnect code */
  413.     INT32 oldLevel;
  414.     /* lock interrupts */
  415.     oldLevel = intLock (); /* LOCK INTERRUPTS */
  416.     ioApicIntDisable (srcIrq);
  417.     ioApicIntDisable (dstIrq);
  418.     /* get the info from the source IRQ vector table entry */
  419.     intVecGet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum), &intHandler, 
  420. &idtType, &selector);
  421.     /* return if the intHandler is the default handler */
  422.     if (intHandler == (FUNCPTR)&excCallTbl[srcInum * 5])
  423.         return (ERROR);
  424.     /* set the info to the destination IRQ vector table entry */
  425.     intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (dstInum), intHandler, 
  426. idtType, selector);
  427.     /* update the IRQ (parameter of EOI routine) in the intConnect code */
  428.     if (intEoiGet != NULL)
  429. {
  430. pCode = (INT8 *)intHandler;
  431. *(INT32 *)(pCode + ICC_EOI_PARAM) = dstIrq;
  432. }
  433.     /* set the default interrupt handler to the source IRQ */
  434.     intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum), 
  435. (FUNCPTR)&excCallTbl[srcInum * 5],
  436. sysIntIdtType, sysCsInt);
  437.     /* unlock interrupts */
  438.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  439.     ioApicIntEnable (dstIrq);
  440.     return (OK);
  441.     }
  442.     
  443. /*******************************************************************************
  444. *
  445. * ioApicIrqSet - set the Local APIC ID of the specified IRQ
  446. *
  447. * This routine sets the Local APIC ID of the specified IRQ in the IO APIC
  448. * Redirection Table.
  449. *
  450. * RETURNS: OK, or ERROR if the IRQ is out of bound
  451. */
  452. STATUS ioApicIrqSet
  453.     (
  454.     INT32 irq, /* IRQ */
  455.     INT32 apicId /* Local APIC ID */
  456.     )
  457.     {
  458.     INT32 upper32;
  459.     INT32 oldLevel;
  460.     INT32 offset = IOAPIC_REDTBL + (irq * 2);
  461.     if (irq >= ioApicRedEntries)
  462. return (ERROR);
  463.     /* lock interrupts */
  464.     oldLevel = intLock (); /* LOCK INTERRUPTS */
  465.     ioApicIntDisable (irq);
  466.     /* set the loApicId */
  467.     upper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
  468.     upper32 = (upper32 & ~IOAPIC_DESTINATION) | (apicId << 24);
  469.     ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
  470.     /* unlock interrupts */
  471.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  472.     ioApicIntEnable (irq);
  473.     return (OK);
  474.     }