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

VxWorks

开发平台:

C/C++

  1. /* loApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01f,15may02,hdn  changed apicId 8 bit to 16 bit, added DBG_MSG.
  8.  added Error Status Register checking
  9. 01e,08mar02,hdn  updated loApicInit() and loApicIpi() 
  10.  added loApicEnable() for HTT (spr 73738)
  11. 01d,29nov01,hdn  doc update for 5.5
  12. 01c,21jun01,hdn  added support for Pentium4 Local xAPIC
  13.  moved show routines to loApicIntrShow.c
  14. 01b,25mar98,hdn  re-written.
  15. 01a,20jun97,sub  written.
  16. */
  17. /*
  18. DESCRIPTION
  19. This module is a driver for the local APIC/xAPIC (Advanced Programmable 
  20. Interrupt Controller) in P6 (PentiumPro, II, III) family processors
  21. and P7 (Pentium4) family processors.  The local APIC/xAPIC is included 
  22. in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
  23. Beginning with the P6 family processors, the presence or absence of an 
  24. on-chip local APIC can be detected using the CPUID instruction.  When the 
  25. CPUID instruction is executed, bit 9 of the feature flags returned in the 
  26. EDX register indicates the presence (set) or absence (clear) of an on-chip 
  27. local APIC.
  28. The local APIC performs two main functions for the processor:
  29.  - It processes local external interrupts that the processor receives at its
  30.    interrupt pins and local internal interrupts that software generates.
  31.  - In multiple-processor systems, it communicates with an external IO APIC
  32.    chip.  The external IO APIC receives external interrupt events from the 
  33.    system and interprocessor interrupts from the processors on the system bus 
  34.    and distributes them to the processors on the system bus.  The IO APIC is
  35.    part of Intel's system chip set.
  36. The local APIC controls the dispatching of interrupts (to its associated 
  37. processor) that it receives either locally or from the IO APIC.  It provides
  38. facilities for queuing, nesting and masking of interrupts.  It handles the 
  39. interrupt delivery protocol with its local processor and accesses to APIC 
  40. registers, and also manages interprocessor interrupts and remote APIC register
  41. reads.  A timer on the local APIC allows local generation of interrupts, and 
  42. local interrupt pins permit local reception of processor-specific interrupts.
  43. The local APIC can be disabled and used in conjunction with a standard 8259A
  44. style interrupt controller.  Disabling the local APIC can be done in hardware 
  45. for the Pentium processors or in software for the P6 and P7 (Pentium4) family
  46. processors.
  47. The local APIC in the Pentium4 processors (called the xAPIC) is an extension
  48. of the local APIC found in the P6 family processors.  The primary difference
  49. between the APIC architecture and xAPIC architecture is that with Pentium4
  50. processors, the local xAPICs and IO xAPIC communicate with one another through
  51. the processors system bus; whereas, with the P6 family processors, communication 
  52. between the local APICs and the IO APIC is handled through a dedicated 3-wire 
  53. APIC bus.  Also, some of the architectural features of the local APIC have been 
  54. extended and/or modified in the local xAPIC.
  55. The base address of the local APIC and IO APIC is taken from the MP configuration
  56. table (see Intel MP Specification Version 1.4) or the IA32_APIC_BASE MSR.   
  57. It uses LOAPIC_BASE and IOAPIC_INDEX_BASE defined in the BSP, if it is not able 
  58. to find the addresses.  This driver contains three routines for use.  They are:
  59. loApicInit() initializes the Local APIC for the interrupt mode chosen.
  60. loApicEnable() enables or disables the Local APIC.  
  61. loApicIpi() delivers the inter processor interrupt to the specified local APIC.
  62. Local APIC is used in the Virtual Wire Mode (define VIRTUAL_WIRE_MODE in the 
  63. BSP) and the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP), but not
  64. in the PIC Mode which is the default interrupt mode and uses 8259A PIC.
  65. Virtual Wire Mode is one of three interrupt modes defined by the MP 
  66. specification.  In this mode, interrupts are generated by the 8259A equivalent
  67. PICs, but delivered to the Boot Strap Processor by the local APIC that is
  68. programmed to act as a "virtual Wire"; that is, the local APIC is logically
  69. indistinguishable from a hardware connection.  This is a uniprocessor
  70. compatibility mode.
  71. Symmetric IO Mode is one of three interrupt modes defined by the MP
  72. specification.  In this mode, the local and IO APICs are fully functional, 
  73. and interrupts are generated and delivered to the processors by the APICs.
  74. Any interrupt can be delivered to any processor.  This is the only 
  75. multiprocessor interrupt mode.  
  76. The local and IO APICs support interrupts in the range of 32 to 255.
  77. Interrupt priority is implied by its vector, according to the following 
  78. relationship:  "priority = vector / 16".
  79. Here the quotient is rounded down to the nearest integer value to determine
  80. the priority, with 1 being the lowest and 15 is the highest.  Because vectors 
  81. 0 through 31 are reserved for exclusive use by the processor, the priority of
  82. user defined interrupts range from 2 to 15.  A value of 15 in the Interrupt 
  83. Class field of the Task Priority Register (TPR) will mask off all interrupts,
  84. which require interrupt service.
  85. The P6 family processor's local APIC includes an in-service entry and a holding
  86. entry for each priority level.  To avoid losing interrupts, software should 
  87. allocate no more than 2 interrupt vectors per priority.  The Pentium4 processor
  88. expands this support of all acceptance of two interrupts per vector rather than
  89. per priority level.
  90. INCLUDE FILES: loApic.h
  91. */
  92. /* includes */
  93. #include "drv/intrCtl/loApic.h"
  94. /* defines */
  95. #define LOAPIC_DBG
  96. #ifdef  LOAPIC_DBG
  97. #   define LOAPIC_DBG_MSG(STR,VALUE)   logMsg(STR,VALUE,0,0,0,0,0);
  98. #else
  99. #   define LOAPIC_DBG_MSG(STR,VALUE)
  100. #endif  /* IPI_DEBUG */
  101. /* externs */
  102. IMPORT CPUID sysCpuId; /* CPUID structure */
  103. IMPORT UINT sysProcessor; /* CPU family */
  104. IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
  105. /* globals */
  106. UINT32 loApicBase = LOAPIC_BASE; /* def Local APIC addr */
  107. UINT32 ioApicBase = IOAPIC_INDEX_BASE; /* def IO APIC select (index) addr */
  108. UINT32 ioApicData = IOAPIC_DATA_BASE; /* def IO APIC window (data) addr */
  109. UINT32 loApicId; /* local APIC Id */
  110. UINT32 loApicVersion; /* local APIC Version */
  111. UINT32 loApicMaxLvt; /* local APIC Max LVT */
  112. UINT32 loApicBusy = 0; /* counter for not sending IPI */
  113. UINT32 loApicNcpu = 0; /* number of CPUs (MP Table) */
  114. UINT32 loApicNioApic = 0; /* number of IO APICs (MP Table) */
  115. BOOL   loApicImcr = FALSE; /* TRUE if IMCR exist (MP Table) */
  116. /* locals */
  117. LOCAL UINT32 sysIntMaskLocalApic = 0;
  118. LOCAL UINT32 loApicOldSvr = 0; /* original SVR */
  119. LOCAL UINT32 loApicOldLint0 = 0; /* original LINT0 */
  120. LOCAL UINT32 loApicOldLint1 = 0; /* original LINT1 */
  121. /* forward declarations */
  122. LOCAL void loApicIntEoi (INT32 irq);
  123. LOCAL STATUS loApicMpConfigTableInit (void);
  124. LOCAL INT8 * loApicMpScan (INT8 * start, INT8 * end);
  125. /*******************************************************************************
  126. *
  127. * loApicInit - initialize the Local APIC or xAPIC
  128. *
  129. * This routine initializes Local APIC or xAPIC.
  130. *
  131. * RETURNS: N/A
  132. *
  133. */
  134. void loApicInit (void)
  135.     {
  136.     UINT32 apicBase[2];
  137.     /* override loApicBase from the MP Config Table */
  138.     (void) loApicMpConfigTableInit ();
  139.     
  140.     /* override loApicBase, sysBp from MSR if available */
  141.     if (sysCpuId.featuresEdx & CPUID_APIC)
  142. {
  143.         pentiumMsrGet (IA32_APIC_BASE, (long long int *)&apicBase);
  144.         loApicBase = apicBase[0] & LOAPIC_BASE_MASK; /* override */
  145.         sysBp = apicBase[0] & LOAPIC_BSP ? TRUE : FALSE; /* override */
  146.         /* enable the Local APIC explicitly */
  147.         apicBase[0] |= LOAPIC_GLOBAL_ENABLE; /* set E(nable) bit */
  148.         pentiumMsrSet (IA32_APIC_BASE, (long long int *)&apicBase);
  149. }
  150.     /* remember the original state : SVR, LINT0, LINT1 for now */
  151.     loApicOldSvr   = *(int *)(loApicBase + LOAPIC_SVR);
  152.     loApicOldLint0 = *(int *)(loApicBase + LOAPIC_LINT0);
  153.     loApicOldLint1 = *(int *)(loApicBase + LOAPIC_LINT1);
  154.     /* enable the Local APIC */
  155.     loApicEnable (TRUE);
  156.     *(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_FOCUS_DISABLE |
  157.  INT_NUM_LOAPIC_SPURIOUS;
  158.     /* get the Local APIC ID from Local APIC ID register */
  159.     loApicId = (*(int *)(loApicBase + LOAPIC_ID) & LOAPIC_ID_MASK) >> 24;
  160.     /* get the Local APIC Version from Local APIC Version register */
  161.     loApicVersion = *(int *)(loApicBase + LOAPIC_VER) & LOAPIC_VERSION_MASK;
  162.     loApicMaxLvt = (*(int *)(loApicBase + LOAPIC_VER) & LOAPIC_MAXLVT_MASK) 
  163.    >> 16;
  164.     /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
  165.     *(int *)(loApicBase + LOAPIC_DFR) = 0xffffffff;
  166.     *(int *)(loApicBase + LOAPIC_TPR) = 0x0;
  167.     *(int *)(loApicBase + LOAPIC_TIMER_CONFIG) = 0x0;
  168.     *(int *)(loApicBase + LOAPIC_TIMER_ICR) = 0x0;
  169. #if defined(VIRTUAL_WIRE_MODE)
  170.     /* program Local Vector Table for the Virtual Wire Mode */
  171.     if (sysBp)
  172. {
  173.         /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
  174.         *(int *)(loApicBase + LOAPIC_LINT0) = 
  175.                 (*(int *)(loApicBase + LOAPIC_LINT0) & 
  176.          ~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
  177.         (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE);
  178.         /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
  179.         *(int *)(loApicBase + LOAPIC_LINT1) = 
  180.                 (*(int *)(loApicBase + LOAPIC_LINT1) & 
  181.          ~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
  182.         (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE);
  183. }
  184.     else
  185. {
  186.         *(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
  187.         *(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
  188. }
  189. #elif defined(SYMMETRIC_IO_MODE)
  190.     /* program Local Vector Table for the Symmetric IO Mode */
  191.     *(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
  192.     *(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
  193.     
  194. #endif /* defined(VIRTUAL_WIRE_MODE) */
  195.     /* lock the Local APIC interrupts */
  196.     *(int *)(loApicBase + LOAPIC_TIMER) = LOAPIC_MASK;
  197.     *(int *)(loApicBase + LOAPIC_ERROR) = LOAPIC_MASK;
  198.     if (loApicMaxLvt >= LOAPIC_LVT_P6)
  199.         *(int *)(loApicBase + LOAPIC_PMC) = LOAPIC_MASK;
  200.     if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
  201.         *(int *)(loApicBase + LOAPIC_THERMAL) = LOAPIC_MASK;
  202.     
  203.     /* discard a pending interrupt if any */
  204.     *(int *)(loApicBase + LOAPIC_EOI) = 0;
  205.     }
  206. /*******************************************************************************
  207. *
  208. * loApicEnable - enable or disable the Local xAPIC
  209. *
  210. * This routine enables or disables the Local xAPIC.  If the parameter is TRUE, 
  211. * the Local xAPIC is enabled.  If the parameter is FALSE, the Local xAPIC
  212. * is disabled.
  213. *
  214. * RETURNS: N/A
  215. */
  216. void loApicEnable
  217.     (
  218.     BOOL enable /* enable the Local xAPIC */
  219.     )
  220.     {
  221.     INT32  oldLevel;
  222.     oldLevel = intLock (); /* LOCK INTERRUPTS */
  223.     /* enable or disable the Local APIC */
  224.     if (enable)
  225. {
  226. /* if the original mode is PIC mode, enable the Local APIC */
  227. if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
  228.     {
  229.             *(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_ENABLE;
  230.     }
  231. #if defined (SYMMETRIC_IO_MODE)
  232. /* switch to SYMMETRIC_IO mode from PIC/VIRTUAL_WIRE mode */
  233. if (loApicImcr)
  234.     {
  235.     sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
  236.     sysOutByte (IMCR_DATA, IMCR_IOAPIC_ON);
  237.     }
  238. #endif /* defined (SYMMETRIC_IO_MODE) */
  239. }
  240.     else
  241. {
  242. #if defined (SYMMETRIC_IO_MODE)
  243. /* switch from SYMMETRIC_IO mode to PIC/VIRTUAL_WIRE mode */
  244. if (loApicImcr)
  245.     {
  246.     sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
  247.     sysOutByte (IMCR_DATA, IMCR_IOAPIC_OFF);
  248.     }
  249. #endif /* defined (SYMMETRIC_IO_MODE) */
  250. /* if the original mode is PIC mode, disable the Local APIC */
  251. if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
  252.     {
  253.             *(int *)(loApicBase + LOAPIC_SVR) &= ~LOAPIC_ENABLE;
  254.     }
  255. else
  256.     {
  257.     /* restore the original value */
  258.          *(int *)(loApicBase + LOAPIC_SVR)   = loApicOldSvr;
  259.          *(int *)(loApicBase + LOAPIC_LINT0) = loApicOldLint0;
  260.          *(int *)(loApicBase + LOAPIC_LINT1) = loApicOldLint1;
  261.     }
  262. }
  263.     intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
  264.     }
  265. /*******************************************************************************
  266. *
  267. * loApicIntLock - lock out all Local APIC interrupts
  268. *
  269. * This routine locks out all Local APIC interrupts
  270. * It should be called in the interrupt disable state(IF bit is 0).
  271. *
  272. * RETURNS: N/A
  273. *
  274. * SEE ALSO: loApicIntUnlock()
  275. *
  276. * ARGSUSED0
  277. */
  278. LOCAL void loApicIntLock (void)
  279.     {
  280.     if (!(*(int *)(loApicBase + LOAPIC_TIMER) & LOAPIC_MASK))
  281. {
  282.         sysIntMaskLocalApic |= LOCKED_TIMER;
  283.         *(int *)(loApicBase + LOAPIC_TIMER) |= LOAPIC_MASK;
  284. }
  285.     if (!(*(int *)(loApicBase + LOAPIC_LINT0) & LOAPIC_MASK))
  286. {
  287.         sysIntMaskLocalApic |= LOCKED_LINT0;
  288.         *(int *)(loApicBase + LOAPIC_LINT0) |= LOAPIC_MASK;
  289. }
  290.     if (!(*(int *)(loApicBase + LOAPIC_LINT1) & LOAPIC_MASK))
  291. {
  292.         sysIntMaskLocalApic |= LOCKED_LINT1;
  293.         *(int *)(loApicBase + LOAPIC_LINT1) |= LOAPIC_MASK;
  294. }
  295.     if (!(*(int *)(loApicBase + LOAPIC_ERROR) & LOAPIC_MASK))
  296. {
  297.         sysIntMaskLocalApic |= LOCKED_ERROR;
  298.         *(int *)(loApicBase + LOAPIC_ERROR) |= LOAPIC_MASK;
  299. }
  300.     if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
  301.         (!(*(int *)(loApicBase + LOAPIC_PMC) & LOAPIC_MASK)))
  302. {
  303.         sysIntMaskLocalApic |= LOCKED_PMC;
  304.         *(int *)(loApicBase + LOAPIC_PMC)   |= LOAPIC_MASK;
  305. }
  306.     if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
  307.         (!(*(int *)(loApicBase + LOAPIC_THERMAL) & LOAPIC_MASK)))
  308. {
  309.         sysIntMaskLocalApic |= LOCKED_THERMAL;
  310.         *(int *)(loApicBase + LOAPIC_THERMAL) |= LOAPIC_MASK;
  311. }
  312.     }
  313. /*******************************************************************************
  314. *
  315. * loApicIntUnlock - unlock the Local APIC interrupts
  316. *
  317. * This routine unlocks the Local APIC interrupts
  318. * It should be called in the interrupt disable state(IF bit is 0).
  319. *
  320. * RETURNS: N/A
  321. *
  322. * SEE ALSO: loApicIntLock()
  323. *
  324. * ARGSUSED0
  325. */
  326. LOCAL void loApicIntUnlock (void)
  327.     {
  328.     if (sysIntMaskLocalApic & LOCKED_TIMER)
  329.         *(int *)(loApicBase + LOAPIC_TIMER) &= ~LOAPIC_MASK;
  330.     if (sysIntMaskLocalApic & LOCKED_LINT0)
  331.         *(int *)(loApicBase + LOAPIC_LINT0) &= ~LOAPIC_MASK;
  332.     if (sysIntMaskLocalApic & LOCKED_LINT1)
  333.         *(int *)(loApicBase + LOAPIC_LINT1) &= ~LOAPIC_MASK;
  334.     if (sysIntMaskLocalApic & LOCKED_ERROR)
  335.         *(int *)(loApicBase + LOAPIC_ERROR) &= ~LOAPIC_MASK;
  336.     if ((loApicMaxLvt >= LOAPIC_LVT_P6) && 
  337. (sysIntMaskLocalApic & LOCKED_PMC))
  338.         *(int *)(loApicBase + LOAPIC_PMC)   &= ~LOAPIC_MASK;
  339.     if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) && 
  340. (sysIntMaskLocalApic & LOCKED_THERMAL))
  341.         *(int *)(loApicBase + LOAPIC_THERMAL) &= ~LOAPIC_MASK;
  342.     sysIntMaskLocalApic = 0; /* reset the flags */
  343.     }
  344. /*******************************************************************************
  345. *
  346. * loApicIntEoi -  send EOI (End Of Interrupt) signal to Local APIC
  347. *
  348. * This routine sends an EOI signal to the Local APIC's interrupting source.
  349. *
  350. * RETURNS: N/A
  351. */
  352. LOCAL void loApicIntEoi
  353.     (
  354.     INT32 irqNo /* INIIN number to send EOI */
  355.     )
  356.     {
  357. #ifdef SYS_INT_DEBUG
  358.     extern UINT32 sysIntCount [];
  359.     sysIntCount [irqNo]++;
  360. #endif /* SYS_INT_DEBUG */
  361.     *(int *)(loApicBase + LOAPIC_EOI) = 0;
  362.     }
  363. /*******************************************************************************
  364. *
  365. * loApicMpConfigTableInit -  initialize pointers to MP configuration table
  366. *
  367. * This routine scans the memory areas specified in MP ver1.4, to find the
  368. * MP signature and initializes pointers to MP configuration tables.  This
  369. * is not comprehensive and the only data used by VxWorks is the 
  370. * APIC IDs and APIC base addresses.
  371. *
  372. * RETURNS: OK, or ERROR if not MP compliant
  373. *
  374. */
  375. LOCAL STATUS loApicMpConfigTableInit (void)
  376.     {
  377.     MP_FPS * pFps = NULL;
  378.     MP_HEADER * mpHdr;
  379.     MP_CPU * mpCpu;
  380.     MP_IOAPIC * mpIOApic;
  381.     INT8 * p;
  382.     INT32 ix;
  383.     /* scan for the MP Floating Point Structure */
  384.     pFps = (MP_FPS *)loApicMpScan ((char *)EBDA_START, (char *)EBDA_END);
  385.     if (pFps == NULL)
  386.         pFps = (MP_FPS *)loApicMpScan ((char *)BIOS_ROM_START, 
  387.        (char *)BIOS_ROM_END);
  388.     if (pFps == NULL)
  389. return (ERROR);
  390.     
  391.     /* 
  392.      * If featurebyte1 (array element 0) is non-zero, then we use 
  393.      * standard configuration return ERROR and let the error handle use
  394.      * standard addresses and Local and IO APIC ID's.
  395.      */
  396.     if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
  397. return (ERROR);
  398.     /* check if the IMCR exists or not */
  399.     loApicImcr = (pFps->featureByte[1] & 0x80) ? TRUE : FALSE;
  400.     /* get MP header pointer */
  401.     mpHdr = (MP_HEADER *) pFps->configTableAddr;
  402.     /* get Local APIC Base Address  */
  403.     loApicBase = (UINT32)(mpHdr->localApicBaseAddr);
  404.     /* We only need CPU and IO APIC entries, ignore the rest */
  405.     p =  (char *)mpHdr + sizeof(MP_HEADER);
  406.     for(ix = 0; ix < mpHdr->entryCount; ix++)
  407. {
  408. switch(*p)
  409.     {
  410.     case MP_ENTRY_CPU: /* Processor Configuration Entry */
  411. mpCpu = (MP_CPU *)p;
  412. loApicNcpu++; /* increment the CPU counter */
  413. p += sizeof (MP_CPU);
  414. break;
  415.     case MP_ENTRY_IOAPIC: /* IO Apic Configuration Entry  */
  416. mpIOApic = (MP_IOAPIC *)p;
  417. loApicNioApic++; /* increment the IO APIC counter */
  418. p += sizeof (MP_IOAPIC);
  419. break;
  420.     default: /* Others..ignore, for now  */
  421. p += 8; /* wild guess */
  422.     }
  423. }
  424.     return(OK);
  425.     }
  426. /*******************************************************************************
  427. *
  428. * loApicMpScan -  scans given memory range for the string "_MP_"
  429. *
  430. * This routine scans the memory areas specified in its argument for the
  431. * Intel MP signature string "_MP_".  
  432. *
  433. * RETURNS: pointer to "_MP_"  in the range , or NULL
  434. *
  435. */
  436. LOCAL INT8 * loApicMpScan 
  437.     (
  438.     INT8 * start, /* start address to scan */
  439.     INT8 * end /* end address to scan */
  440.     )
  441.     {
  442.     INT8 * p;
  443.     for (p = start; (p+3) < end; p++)
  444. {
  445. if (strncmp (p, "_MP_", 4) == 0)
  446.     return (p);
  447. }
  448.     return (NULL);
  449.     }
  450. /******************************************************************************
  451. *
  452. * loApicIpi - generate a Inter Processor Interrupt
  453. *
  454. * This routine delivers an Inter-Processor interrupt to the specified CPU
  455. * in the specified mode, with the specified vectorNo.  Level should always
  456. * be 1 except INIT De-assert mode.
  457. *
  458. * RETURNS: OK, or ERROR if the delivery status is not idle
  459. */
  460. STATUS loApicIpi
  461.     (
  462.     INT32 apicId, /* APIC ID number to send the interrupt */
  463.     INT32 shortHand, /* destination short hand */
  464.     INT32 trigger, /* trigger mode. 0: edge or 1: level */
  465.     INT32 level, /* level. 0: de-assert or 1: assert */
  466.     INT32 destMode, /* destination mode. 0: physical or 1: logical */
  467.     INT32 deliMode, /* delivery mode. 000: fixed ... 110: startup */
  468.     INT32 vectorNo /* vector number */
  469.     )
  470.     {
  471.     UINT32 icrHi = (*(int *)(loApicBase + LOAPIC_ICRHI)) & 0xf0ffffff;
  472.     UINT32 icrLo = (*(int *)(loApicBase + LOAPIC_ICRLO)) & 0xfff33000;
  473.  
  474.     /* ShortHand, Trigger, Level, DeliveryMode and Vector */
  475.     icrLo |= ((shortHand << 18) & 0xc0000) | 
  476.      ((trigger << 15) & 0x8000) | 
  477.      ((level << 14) & 0x4000) |
  478.      ((destMode << 11) & 0x800) | 
  479.      ((deliMode << 8) & 0x700) | 
  480.      (vectorNo & 0xff);
  481.  
  482.     /* Destination Apic Id */
  483.     icrHi |= (apicId << 24) & 0xff000000;
  484.  
  485.     /* is the interrupt idle? */
  486.     if (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
  487.         {
  488. loApicBusy++;
  489. LOAPIC_DBG_MSG ("ipi: LOAPIC busy 0x%xn", 
  490. *(int *)(loApicBase + LOAPIC_ESR))
  491.         return (ERROR);
  492. }
  493.     /* reset the error status register */
  494.     *(int *)(loApicBase + LOAPIC_ESR) = 0;
  495.     *(int *)(loApicBase + LOAPIC_ESR) = 0;
  496.         if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
  497.     {
  498.     LOAPIC_DBG_MSG ("ipi: 0. ESR=0x%xn", 
  499.     *(int *)(loApicBase + LOAPIC_ESR))
  500.     return (ERROR);
  501.     }
  502.     /* Send it! */
  503.     *(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
  504.     *(int *)(loApicBase + LOAPIC_ICRLO) = icrLo;
  505.  
  506.     /* Wait till interrupt is sent */
  507.     while (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
  508.         if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
  509.     {
  510.     LOAPIC_DBG_MSG ("ipi: 1. ESR=0x%xn", 
  511.     *(int *)(loApicBase + LOAPIC_ESR))
  512.     return (ERROR);
  513.     }
  514.  
  515.     return(OK);
  516.     }