Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

579 lines
12 KiB

  1. //
  2. /**
  3. *** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
  4. ***
  5. *** The information and source code contained herein is the exclusive
  6. *** property of Intel Corporation and may not be disclosed, examined
  7. *** or reproduced in whole or in part without explicit written authorization
  8. *** from the company.
  9. **/
  10. /*++
  11. Copyright (c) 1995 Intel Corporation
  12. Module Name:
  13. i64sxint.c copied from simsxint.c
  14. Abstract:
  15. This module implements the routines to manage the
  16. system interrupt and IRQL.
  17. Author:
  18. William K. Cheung (wcheung) 14-Apr-1995
  19. Bernard Lint
  20. M. Jayakumar (Muthurajan.Jayakumar@intel.com)
  21. Environment:
  22. Kernel mode
  23. Revision History:
  24. Todd Kjos (HP) (v-tkjos) 1-Jun-1998 : Added I/O Sapic support
  25. Thierry Fevrier (HP) (v-thief) 8-Feb-2000 : Profiling support
  26. --*/
  27. #include "halp.h"
  28. #include "iosapic.h"
  29. VOID HalpInitLINT(VOID);
  30. extern KSPIN_LOCK HalpIoSapicLock;
  31. extern PULONG_PTR *HalEOITable[];
  32. PULONG_PTR HalpEOITableP0[MAX_INTR_VECTOR];
  33. ULONG HalpNodeAffinity[MAX_NODES];
  34. ULONG HalpMaxNode = 1;
  35. VOID
  36. HalpInitializeInterrupts (
  37. VOID
  38. )
  39. /*++
  40. Routine Description:
  41. This function initializes interrupts for an IA64 system.
  42. Arguments:
  43. None.
  44. Return Value:
  45. None.
  46. Note:
  47. In KiInitializeKernel(), PCR.InterruptRoutine[] entries have been first initialized
  48. with the Unexpected Interrupt code then entries index-0, APC_VECTOR, DISPATCH_VECTOR
  49. have been initialized with their respective interrupt handlers.
  50. --*/
  51. {
  52. //
  53. // Turn off LINT0 LINT1 (disable 8259)
  54. //
  55. // __setReg(CV_IA64_SaLRR0, 0x10000);
  56. // __setReg(CV_IA64_SaLRR1, 0x10000);
  57. HalpInitLINT();
  58. __dsrlz();
  59. //
  60. // interval timer interrupt; 10ms by default
  61. //
  62. HalpInitializeClockInterrupts();
  63. //
  64. // Initialize SpuriousInterrupt
  65. //
  66. HalpSetHandlerAddressToVector
  67. (SAPIC_SPURIOUS_VECTOR, HalpSpuriousHandler);
  68. //
  69. // Initialize CMCI Interrupt
  70. //
  71. // Note that it is possible that HAL_CMC_PRESENT is not set.
  72. // With the current implementation, we always connect the vector to the ISR.
  73. //
  74. HalpSetHandlerAddressToVector
  75. (CMCI_VECTOR, HalpCMCIHandler);
  76. //
  77. // Initialize CPEI Interrupt
  78. //
  79. // Note that it is possible that HAL_CPE_PRESENT is not set.
  80. // With the current implementation, we always connect the vector to the ISR.
  81. //
  82. HalpSetHandlerAddressToVector
  83. (CPEI_VECTOR, HalpCPEIHandler);
  84. //
  85. // Initialiaze MC Rendezvous Interrupt
  86. //
  87. HalpSetHandlerAddressToVector
  88. (MC_RZ_VECTOR, HalpMcRzHandler);
  89. //
  90. // Initialize MC Wakeup Interrupt
  91. //
  92. HalpSetHandlerAddressToVector
  93. (MC_WKUP_VECTOR, HalpMcWkupHandler);
  94. //
  95. // IPI Interrupt
  96. //
  97. HalpSetHandlerAddressToVector(IPI_VECTOR, HalpIpiInterruptHandler);
  98. //
  99. // profile timer interrupt; turned off initially
  100. //
  101. HalpSetHandlerAddressToVector(PROFILE_VECTOR, HalpProfileInterrupt);
  102. //
  103. // Performance monitor interrupt
  104. //
  105. HalpSetHandlerAddressToVector(PERF_VECTOR, HalpPerfInterrupt);
  106. return;
  107. } // HalpInitializeInterrupts()
  108. VOID
  109. HalpInitIntiInfo(
  110. VOID
  111. )
  112. {
  113. USHORT Index;
  114. // Initialize the vector to INTi table
  115. for (Index=0; Index < ((1 + MAX_NODES)*256); Index++) {
  116. HalpVectorToINTI[Index] = (ULONG)-1;
  117. }
  118. }
  119. VOID
  120. HalpInitEOITable(
  121. VOID
  122. )
  123. {
  124. USHORT Index;
  125. ULONG ProcessorNumber;
  126. // Allocate and Initialize EOI table on current processor
  127. ProcessorNumber = PCR->Prcb->Number;
  128. if (ProcessorNumber == 0) {
  129. HalEOITable[ProcessorNumber] = HalpEOITableP0;
  130. } else {
  131. HalEOITable[ProcessorNumber] = ExAllocatePool(NonPagedPool,
  132. MAX_INTR_VECTOR*sizeof(HalEOITable[0]));
  133. }
  134. // For kernel access to eoi table
  135. PCR->EOITable = HalEOITable[ProcessorNumber];
  136. for (Index=0; Index < MAX_INTR_VECTOR; Index++) {
  137. HalEOITable[ProcessorNumber][Index] = 0;
  138. }
  139. }
  140. VOID
  141. HalpWriteEOITable(
  142. IN ULONG Vector,
  143. IN PULONG_PTR EoiAddress,
  144. IN ULONG Number
  145. )
  146. /*++
  147. Routine Description:
  148. This routine updates the EOI table for a processor
  149. Arguments:
  150. Vector - Entry to update (IDT entry)
  151. EoiAddress - Address to write (SAPIC address)
  152. Number - Logical (NT) processor number
  153. Return Value:
  154. None
  155. --*/
  156. {
  157. if (HalEOITable != NULL && HalEOITable[Number] != NULL) {
  158. HalEOITable[Number][Vector] = EoiAddress;
  159. }
  160. }
  161. BOOLEAN
  162. HalEnableSystemInterrupt (
  163. IN ULONG Vector,
  164. IN KIRQL Irql,
  165. IN KINTERRUPT_MODE InterruptMode
  166. )
  167. /*++
  168. Routine Description:
  169. This routine enables the specified system interrupt.
  170. N.B. This routine assumes that the caller has provided any required
  171. synchronization to enable a system interrupt.
  172. Arguments:
  173. Vector - Supplies the vector of the system interrupt that is enabled.
  174. Irql - Supplies the IRQL of the interrupting source.
  175. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  176. Latched.
  177. Return Value:
  178. TRUE if the system interrupt was enabled
  179. --*/
  180. {
  181. ULONG Entry, Destination;
  182. ULONG OldLevel;
  183. ULONG Inti;
  184. ULONG LevelAndPolarity;
  185. USHORT ThisCpuApicID;
  186. ULONG InterruptType;
  187. BOOLEAN RetVal = TRUE;
  188. UCHAR IDTEntry;
  189. ASSERT(Vector < (1+MAX_NODES)*0x100-1);
  190. ASSERT(Irql <= HIGH_LEVEL);
  191. HalDebugPrint(( HAL_VERBOSE, "HAL: HalpEnableSystemInterrupt - INTI=0x%x Vector=0x%x IRQL=0x%x\n",
  192. HalpVectorToINTI[Vector],
  193. Vector,
  194. Irql ));
  195. if ( (Inti = HalpVectorToINTI[Vector]) == (ULONG)-1 ) {
  196. //
  197. // There is no external device associated with this interrupt,
  198. // but it might be an internal interrupt i.e. one that never
  199. // involves the IOSAPIC.
  200. //
  201. return HalpIsInternalInterruptVector(Vector);
  202. }
  203. // Make sure the passed-in level matches our settings...
  204. if ((InterruptMode == LevelSensitive && !HalpIsLevelTriggered(Inti)) ||
  205. (InterruptMode != LevelSensitive && HalpIsLevelTriggered(Inti)) ) {
  206. // It doesn't match!
  207. HalDebugPrint(( HAL_INFO, "HAL: HalpEnableSystemInterrupt - Warning device interrupt mode overridden\n"));
  208. }
  209. LevelAndPolarity =
  210. (HalpIsLevelTriggered(Inti) ? LEVEL_TRIGGERED : EDGE_TRIGGERED) |
  211. (HalpIsActiveLow(Inti) ? ACTIVE_LOW : ACTIVE_HIGH);
  212. //
  213. // Block interrupts and synchronize until we're done
  214. //
  215. OldLevel = HalpAcquireHighLevelLock (&HalpIoSapicLock);
  216. ThisCpuApicID = (USHORT)KeGetPcr()->HalReserved[PROCESSOR_ID_INDEX];
  217. // Get Interrupt type
  218. HalpGetRedirEntry(Inti,&Entry,&Destination);
  219. InterruptType = Entry & INT_TYPE_MASK;
  220. IDTEntry = HalVectorToIDTEntry(Vector);
  221. switch (InterruptType) {
  222. case DELIVER_FIXED:
  223. case DELIVER_LOW_PRIORITY:
  224. //
  225. // Normal external interrupt...
  226. // Enable the interrupt in the I/O SAPIC redirection table
  227. //
  228. if (IDTEntry < 16) {
  229. // Reserved vectors: Extint, NMI, IntelReserved
  230. // No vectors in this range can be assigned
  231. ASSERT(0);
  232. RetVal = FALSE;
  233. break;
  234. }
  235. //
  236. // All external interrupts are delivered as Fixed interrupts
  237. // without the "redirectable" bit set (aka Lowest Priority). This
  238. // disallows hardware to redirect the interrupts using the XTP mechanism.
  239. //
  240. Entry = (ULONG)IDTEntry | LevelAndPolarity;
  241. HalpSetRedirEntry ( Inti, Entry, ThisCpuApicID );
  242. break;
  243. case DELIVER_EXTINT:
  244. //
  245. // This is an interrupt that uses the IO Sapic to route PIC
  246. // events. This configuration is not supported in IA64.
  247. //
  248. ASSERT(0);
  249. RetVal = FALSE;
  250. break;
  251. default:
  252. HalDebugPrint(( HAL_ERROR, "HAL: HalEnableSystemInterrupt - Unknown Interrupt Type: %d\n",
  253. InterruptType));
  254. RetVal = FALSE;
  255. break;
  256. } // switch (InterruptType)
  257. HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
  258. return(RetVal);
  259. }
  260. VOID
  261. HalDisableSystemInterrupt (
  262. IN ULONG Vector,
  263. IN KIRQL Irql
  264. )
  265. /*++
  266. Routine Description:
  267. This routine disables the specified system interrupt.
  268. In the simulation environment, this function does nothing and returns.
  269. N.B. This routine assumes that the caller has provided any required
  270. synchronization to disable a system interrupt.
  271. Arguments:
  272. Vector - Supplies the vector of the system interrupt that is disabled.
  273. Irql - Supplies the IRQL of the interrupting source.
  274. Return Value:
  275. None.
  276. --*/
  277. {
  278. ULONG Entry, Destination;
  279. ULONG OldLevel;
  280. ULONG Inti;
  281. ULONG LevelAndPolarity;
  282. ULONG ThisCpuApicID;
  283. ULONG InterruptType;
  284. ASSERT(Vector < (1+MAX_NODES)*0x100-1);
  285. ASSERT(Irql <= HIGH_LEVEL);
  286. HalDebugPrint(( HAL_INFO, "HAL: HalpDisableSystemInterrupt: INTI=%x Vector=%x IRQL=%x\n",
  287. HalpVectorToINTI[Vector],
  288. Vector,
  289. Irql));
  290. if ( (Inti = HalpVectorToINTI[Vector]) == (ULONG)-1 ) {
  291. //
  292. // There is no external device associated with this interrupt
  293. //
  294. return;
  295. }
  296. //
  297. // Block interrupts and synchronize until we're done
  298. //
  299. OldLevel = HalpAcquireHighLevelLock(&HalpIoSapicLock);
  300. ThisCpuApicID = (USHORT)KeGetPcr()->HalReserved[PROCESSOR_ID_INDEX];
  301. // Get Interrupt Type and Destination
  302. HalpGetRedirEntry(Inti, &Entry, &Destination);
  303. if (ThisCpuApicID != Destination) {
  304. // The interrupt is not enabled on this Cpu
  305. HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
  306. return;
  307. }
  308. InterruptType = Entry & INT_TYPE_MASK;
  309. switch (InterruptType) {
  310. case DELIVER_FIXED:
  311. //
  312. // Normal external interrupt...
  313. // Disable the interrupt in the I/O SAPIC redirection table
  314. //
  315. if (Vector < 16) {
  316. // Reserved vectors: Extint, NMI, IntelReserved
  317. // No vectors in this range can be assigned
  318. ASSERT(0);
  319. break;
  320. }
  321. HalpDisableRedirEntry (Inti);
  322. break;
  323. case DELIVER_EXTINT:
  324. //
  325. // This is an interrupt that uses the IO Sapic to route PIC
  326. // events. This configuration is not supported in IA64.
  327. //
  328. ASSERT(0);
  329. break;
  330. default:
  331. HalDebugPrint(( HAL_INFO, "HAL: HalDisableSystemInterrupt - Unknown Interrupt Type: %d\n",
  332. InterruptType ));
  333. break;
  334. } // switch (InterruptType)
  335. HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
  336. }
  337. UCHAR
  338. HalpNodeNumber(
  339. ULONG Number
  340. )
  341. /*++
  342. Routine Description:
  343. This routine divines the Node number for the CPU Number.
  344. Node numbers start at 1, and represent the granularity of interrupt
  345. routing decisions.
  346. Arguments:
  347. Number - Processor number
  348. Return Value:
  349. None.
  350. --*/
  351. {
  352. if (HalpMaxProcsPerCluster != 0) {
  353. // One Node per Cluster.
  354. return (UCHAR)(Number/HalpMaxProcsPerCluster + 1);
  355. } else {
  356. // One Node per machine.
  357. return(1);
  358. }
  359. }
  360. VOID
  361. HalpAddNodeNumber(
  362. ULONG Number
  363. )
  364. /*++
  365. Routine Description:
  366. This routine adds the current processor to the Node tables.
  367. Arguments:
  368. None
  369. Return Value:
  370. None.
  371. --*/
  372. {
  373. ULONG Node;
  374. //
  375. // Add the current processor to the Node tables.
  376. //
  377. Node = HalpNodeNumber(Number);
  378. if (HalpMaxNode < Node) {
  379. HalpMaxNode = Node;
  380. }
  381. HalpNodeAffinity[Node-1] |= 1 << Number;
  382. }
  383. ULONG
  384. HalpGetProcessorNumberByApicId(
  385. USHORT ApicId
  386. )
  387. /*++
  388. Routine Description:
  389. This routine returns the logical processor number for a given
  390. physical processor id (extended local sapic id)
  391. Arguments:
  392. ApicId -- Extended ID of processor (16 bit id)
  393. Return Value:
  394. Logical (NT) processor number
  395. --*/
  396. {
  397. ULONG index;
  398. for (index = 0; index < HalpMpInfo.ProcessorCount; index++) {
  399. if (ApicId == HalpProcessorInfo[index].LocalApicID) {
  400. return HalpProcessorInfo[index].NtProcessorNumber;
  401. }
  402. }
  403. ASSERT (index < HalpMpInfo.ProcessorCount);
  404. //
  405. // Note: The previous code returned an invalid index (HalpMpInfo.ProcessorCount
  406. // which is 1 greater than the number of processors) we should probably
  407. // just bugcheck here.
  408. //
  409. return 0;
  410. }