Leaked source code of windows server 2003
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.

598 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. i64sapic.c
  5. Abstract:
  6. Implements I/O Sapic functionality
  7. Author:
  8. Todd Kjos (HP) (v-tkjos) 1-Jun-1998
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "halp.h"
  14. #include "iosapic.h"
  15. #include <ntacpi.h>
  16. VOID
  17. IoSapicMaskEntry(
  18. PIO_INTR_CONTROL IoUnit,
  19. ULONG RteNumber
  20. );
  21. VOID
  22. IoSapicSetEntry(
  23. PIO_INTR_CONTROL IoUnit,
  24. ULONG RteNumber
  25. );
  26. VOID
  27. IoSapicEnableEntry(
  28. PIO_INTR_CONTROL IoUnit,
  29. ULONG RteNumber
  30. );
  31. //
  32. // Method structure for control of IO Sapic Hardware
  33. //
  34. INTR_METHODS HalpIoSapicMethods = {
  35. IoSapicMaskEntry,
  36. IoSapicSetEntry,
  37. IoSapicEnableEntry
  38. };
  39. VOID
  40. HalpInti2InterruptController (
  41. IN ULONG InterruptInput,
  42. OUT PIO_INTR_CONTROL *InterruptController,
  43. OUT PULONG ControllerInti
  44. )
  45. /*++
  46. Routine Description:
  47. Convert InterruptInput to an interrupt controller
  48. structure and input number
  49. Arguments:
  50. InterruptInput - System Global Interrupt Input
  51. InterruptController - Pointer to Interupt controller structure
  52. ControllerInti - Redirection Table Entry on this interrupt controller
  53. Return Value:
  54. --*/
  55. {
  56. PIO_INTR_CONTROL IoUnit;
  57. for (IoUnit=HalpIoSapicList; IoUnit; IoUnit=IoUnit->flink) {
  58. if (InterruptInput <= IoUnit->IntiMax) {
  59. if (IoUnit->IntiBase > InterruptInput) {
  60. //
  61. // If there are holes in the list of Global System Vectors AND
  62. // someone specifies one of the non-existant GSVs, make sure we
  63. // return an error rather than getting horribly confused about
  64. // which IOAPIC contains the Inti.
  65. //
  66. IoUnit = NULL;
  67. }
  68. break;
  69. }
  70. }
  71. *InterruptController = IoUnit;
  72. if (IoUnit) {
  73. *ControllerInti = InterruptInput-IoUnit->IntiBase;
  74. }
  75. }
  76. BOOLEAN
  77. HalpGetSapicInterruptDesc (
  78. IN INTERFACE_TYPE BusType,
  79. IN ULONG BusNumber,
  80. IN ULONG BusInterruptLevel,
  81. OUT PULONG Inti,
  82. OUT PKAFFINITY InterruptAffinity
  83. )
  84. /*++
  85. Routine Description:
  86. This procedure gets a "Inti" describing the requested interrupt
  87. Arguments:
  88. BusType - The Bus type as known to the IO subsystem
  89. BusNumber - The number of the Bus we care for
  90. BusInterruptLevel - IRQ on the Bus
  91. Return Value:
  92. TRUE if AcpiInti found; otherwise FALSE.
  93. Inti - Global system interrupt input
  94. --*/
  95. {
  96. PIO_INTR_CONTROL IoUnit;
  97. ULONG RteNumber;
  98. HalpInti2InterruptController(BusInterruptLevel, &IoUnit, &RteNumber);
  99. // Make sure Inti is not out of range
  100. if (IoUnit == NULL) {
  101. return FALSE;
  102. }
  103. // It's in range, just give back the same value as was passed in
  104. *Inti = BusInterruptLevel;
  105. //
  106. // The Interrupt affinity is the intersection of the global affinity mask
  107. // (HalpDefaultInterruptAffinity) and any additional restrictions due to the
  108. // location of the Io Sapic (IoUnit->InterruptAffinity).
  109. //
  110. *InterruptAffinity = IoUnit->InterruptAffinity & HalpDefaultInterruptAffinity;
  111. return(TRUE);
  112. }
  113. ULONG
  114. HalpINTItoVector(
  115. ULONG Inti
  116. )
  117. // Returns the Vector associated with this global interrupt input
  118. // Vector is node and IDT entry
  119. {
  120. PIO_INTR_CONTROL IoUnit;
  121. ULONG RteNumber;
  122. HalpInti2InterruptController( Inti, &IoUnit, &RteNumber );
  123. ASSERT(IoUnit);
  124. return (IoUnit->Inti[RteNumber].GlobalVector);
  125. }
  126. VOID
  127. HalpSetINTItoVector(
  128. ULONG Inti,
  129. ULONG Vector
  130. )
  131. // Sets the vector for this global interrupt input
  132. // Vector is node and IDT entry
  133. {
  134. PIO_INTR_CONTROL IoUnit;
  135. ULONG RteNumber;
  136. HalpInti2InterruptController( Inti, &IoUnit, &RteNumber );
  137. ASSERT(IoUnit);
  138. // .Vector (IDTEntry) is set in SetRedirEntry
  139. IoUnit->Inti[RteNumber].GlobalVector = Vector;
  140. }
  141. VOID
  142. HalpSetRedirEntry (
  143. IN ULONG InterruptInput,
  144. IN ULONG Entry,
  145. IN USHORT ThisCpuApicID
  146. )
  147. /*++
  148. Routine Description:
  149. This procedure sets a IO Unit Redirection Table Entry
  150. Must be called with the HalpAccountingLock held
  151. Arguments:
  152. Return Value:
  153. None.
  154. --*/
  155. {
  156. PIO_INTR_CONTROL IoUnit;
  157. ULONG RteNumber;
  158. HalpInti2InterruptController( InterruptInput, &IoUnit, &RteNumber );
  159. ASSERT(IoUnit);
  160. ASSERT(IoUnit->Inti[RteNumber].GlobalVector);
  161. ASSERT((UCHAR)(IoUnit->Inti[RteNumber].GlobalVector) == (UCHAR)Entry);
  162. IoUnit->Inti[RteNumber].Vector = Entry;
  163. IoUnit->Inti[RteNumber].Destination = ThisCpuApicID << 16;
  164. IoUnit->FreeVectors[Entry >> 4] &= ~(1 << (Entry & 0x0F));
  165. IoUnit->IntrMethods->SetEntry(IoUnit, RteNumber);
  166. }
  167. VOID
  168. HalpWriteRedirEntry (
  169. IN ULONG GlobalInterrupt,
  170. IN UCHAR SapicVector,
  171. IN USHORT DestinationCPU,
  172. IN ULONG Flags,
  173. IN ULONG InterruptType
  174. )
  175. {
  176. ULONG rteNumber;
  177. PIO_INTR_CONTROL ioUnit;
  178. HalpInti2InterruptController( GlobalInterrupt, &ioUnit, &rteNumber );
  179. ASSERT(ioUnit);
  180. ioUnit->Inti[rteNumber].Vector = SapicVector;
  181. //
  182. // Set the delivery mode
  183. //
  184. switch (InterruptType) {
  185. case PLATFORM_INT_PMI:
  186. ioUnit->Inti[rteNumber].Vector &= ~INT_TYPE_MASK; // first clear the field
  187. ioUnit->Inti[rteNumber].Vector |= DELIVER_SMI;
  188. break;
  189. case PLATFORM_INT_CPE:
  190. ioUnit->Inti[rteNumber].Vector &= ~INT_TYPE_MASK; // first clear the field
  191. ioUnit->Inti[rteNumber].Vector |= DELIVER_LOW_PRIORITY;
  192. break;
  193. case PLATFORM_INT_INIT:
  194. ioUnit->Inti[rteNumber].Vector &= ~INT_TYPE_MASK; // first clear the field
  195. ioUnit->Inti[rteNumber].Vector |= DELIVER_INIT;
  196. break;
  197. }
  198. //
  199. // So we honor the flags passed into this function.
  200. //
  201. if (IS_LEVEL_TRIGGERED_MPS(Flags)) {
  202. ioUnit->Inti[rteNumber].Vector |= LEVEL_TRIGGERED;
  203. } else {
  204. ioUnit->Inti[rteNumber].Vector &= ~LEVEL_TRIGGERED;
  205. }
  206. if (IS_ACTIVE_LOW_MPS(Flags)) {
  207. ioUnit->Inti[rteNumber].Vector |= ACTIVE_LOW;
  208. } else {
  209. ioUnit->Inti[rteNumber].Vector &= ~ACTIVE_LOW;
  210. }
  211. ioUnit->Inti[rteNumber].Destination = DestinationCPU << 16;
  212. ioUnit->FreeVectors[SapicVector >> 4] &= ~(1 << (SapicVector & 0x0F));
  213. ioUnit->IntrMethods->SetEntry(ioUnit, rteNumber);
  214. } // HalpWriteRedirEntry()
  215. VOID
  216. HalpGetRedirEntry (
  217. IN ULONG InterruptInput,
  218. IN PULONG Entry,
  219. IN PULONG Destination
  220. )
  221. /*++
  222. Routine Description:
  223. Arguments:
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PIO_INTR_CONTROL IoUnit;
  229. ULONG RteNumber;
  230. HalpInti2InterruptController( InterruptInput,&IoUnit,&RteNumber );
  231. ASSERT(IoUnit);
  232. *Entry = IoUnit->Inti[RteNumber].Vector;
  233. *Destination = IoUnit->Inti[RteNumber].Destination;
  234. }
  235. VOID
  236. HalpGetFreeVectors(
  237. IN ULONG InterruptInput,
  238. OUT PUSHORT *FreeVectors
  239. )
  240. {
  241. ULONG rteNumber;
  242. PIO_INTR_CONTROL ioUnit;
  243. HalpInti2InterruptController( InterruptInput, &ioUnit, &rteNumber );
  244. ASSERT(ioUnit);
  245. *FreeVectors = ioUnit->FreeVectors;
  246. }
  247. VOID
  248. HalpSetVectorAllocated(
  249. IN ULONG InterruptInput,
  250. IN UCHAR Vector
  251. )
  252. {
  253. ULONG rteNumber;
  254. PIO_INTR_CONTROL ioUnit;
  255. HalpInti2InterruptController( InterruptInput, &ioUnit, &rteNumber );
  256. ASSERT(ioUnit);
  257. ioUnit->FreeVectors[Vector >> 4] &= ~(1 << (Vector & 0xF));
  258. }
  259. VOID
  260. HalpEnableRedirEntry(
  261. IN ULONG InterruptInput
  262. )
  263. /*++
  264. Routine Description:
  265. This procedure enables a IO Unit Redirection Table Entry
  266. by setting the mask bit in the Redir Entry.
  267. Arguments:
  268. InterruptInput - The input line we're interested in
  269. Return Value:
  270. None.
  271. --*/
  272. {
  273. PIO_INTR_CONTROL IoUnit;
  274. ULONG RteNumber;
  275. HalpInti2InterruptController( InterruptInput, &IoUnit, &RteNumber );
  276. ASSERT(IoUnit);
  277. IoUnit->IntrMethods->EnableEntry(IoUnit, RteNumber);
  278. }
  279. VOID
  280. HalpDisableRedirEntry(
  281. IN ULONG InterruptInput
  282. )
  283. /*++
  284. Routine Description:
  285. This procedure disables a IO Unit Redirection Table Entry
  286. by setting the mask bit in the Redir Entry.
  287. Arguments:
  288. InterruptInput - The input line we're interested in
  289. Return Value:
  290. None.
  291. --*/
  292. {
  293. PIO_INTR_CONTROL IoUnit;
  294. ULONG RteNumber;
  295. HalpInti2InterruptController( InterruptInput, &IoUnit, &RteNumber );
  296. ASSERT(IoUnit);
  297. IoUnit->IntrMethods->MaskEntry(IoUnit, RteNumber);
  298. }
  299. VOID
  300. IoSapicMaskEntry(
  301. PIO_INTR_CONTROL IoUnit,
  302. ULONG RteNumber
  303. )
  304. {
  305. PIO_SAPIC_REGS IoSapicPtr = IoUnit->RegBaseVirtual;
  306. IoSapicPtr->RegisterSelect = RteNumber * 2 + IO_REDIR_00_LOW;
  307. IoSapicPtr->RegisterWindow |= INTERRUPT_MASKED;
  308. HalDebugPrint(( HAL_VERBOSE, "HAL: IoSapicMaskEntry - %d [%#p]: Dest=%#x Vec=%#x\n",
  309. RteNumber,IoSapicPtr,
  310. IoUnit->Inti[RteNumber].Destination,
  311. IoUnit->Inti[RteNumber].Vector
  312. ));
  313. }
  314. VOID
  315. IoSapicEnableEntry(
  316. PIO_INTR_CONTROL IoUnit,
  317. ULONG RteNumber
  318. )
  319. {
  320. PIO_SAPIC_REGS IoSapicPtr = IoUnit->RegBaseVirtual;
  321. IoSapicPtr->RegisterSelect = RteNumber * 2 + IO_REDIR_00_LOW;
  322. IoSapicPtr->RegisterWindow &= (~INTERRUPT_MASKED);
  323. HalDebugPrint(( HAL_VERBOSE, "HAL: IoSapicEnableEntry: %d [%#p]: Dest=%#x Vec=%#x\n",
  324. RteNumber, IoSapicPtr,
  325. IoUnit->Inti[RteNumber].Destination,
  326. IoUnit->Inti[RteNumber].Vector
  327. ));
  328. }
  329. VOID
  330. IoSapicSetEntry(
  331. PIO_INTR_CONTROL IoUnit,
  332. ULONG RteNumber
  333. )
  334. {
  335. PIO_SAPIC_REGS IoSapicPtr = IoUnit->RegBaseVirtual;
  336. ULONG RedirRegister;
  337. PULONG_PTR EoiValue;
  338. USHORT ApicId;
  339. // Only SetEntry sets the eoi table because set entry is the only
  340. // one that sets the destination CPU.
  341. EoiValue = (PULONG_PTR)(IoUnit->Inti[RteNumber].Vector & LEVEL_TRIGGERED ? &IoSapicPtr->Eoi : 0 );
  342. ApicId = (USHORT)((IoUnit->Inti[RteNumber].Destination & SAPIC_XID_MASK) >> SAPIC_XID_SHIFT);
  343. HalpWriteEOITable(
  344. IoUnit->Inti[RteNumber].Vector & INT_VECTOR_MASK,
  345. EoiValue,
  346. HalpGetProcessorNumberByApicId(ApicId));
  347. RedirRegister = RteNumber * 2 + IO_REDIR_00_LOW;
  348. IoSapicPtr->RegisterSelect = RedirRegister+1;
  349. IoSapicPtr->RegisterWindow = IoUnit->Inti[RteNumber].Destination;
  350. IoSapicPtr->RegisterSelect = RedirRegister;
  351. IoSapicPtr->RegisterWindow = IoUnit->Inti[RteNumber].Vector; // Enable
  352. HalDebugPrint(( HAL_VERBOSE, "HAL: IoSapicSetEntry: %d [%#p]: Dest=%#x Vec=%#x Eoi=%#p\n",
  353. RteNumber, IoSapicPtr,
  354. IoUnit->Inti[RteNumber].Destination,
  355. IoUnit->Inti[RteNumber].Vector,
  356. EoiValue
  357. ));
  358. }
  359. BOOLEAN
  360. HalpIsActiveLow(
  361. ULONG Inti
  362. )
  363. {
  364. PIO_INTR_CONTROL IoUnit;
  365. ULONG RteNumber;
  366. HalpInti2InterruptController (
  367. Inti,&IoUnit,&RteNumber
  368. );
  369. return( (IoUnit->Inti[RteNumber].Vector & ACTIVE_LOW) == ACTIVE_LOW);
  370. }
  371. BOOLEAN
  372. HalpIsLevelTriggered(
  373. ULONG Inti
  374. )
  375. {
  376. PIO_INTR_CONTROL IoUnit;
  377. ULONG RteNumber;
  378. HalpInti2InterruptController (
  379. Inti,&IoUnit,&RteNumber
  380. );
  381. ASSERT(IoUnit);
  382. return( (IoUnit->Inti[RteNumber].Vector & LEVEL_TRIGGERED) == LEVEL_TRIGGERED);
  383. }
  384. VOID
  385. HalpSetPolarity(
  386. ULONG Inti,
  387. BOOLEAN ActiveLow
  388. )
  389. {
  390. PIO_INTR_CONTROL IoUnit;
  391. ULONG RteNumber;
  392. HalpInti2InterruptController (
  393. Inti,&IoUnit,&RteNumber
  394. );
  395. ASSERT(IoUnit);
  396. if (ActiveLow) {
  397. IoUnit->Inti[RteNumber].Vector |= ACTIVE_LOW;
  398. } else {
  399. IoUnit->Inti[RteNumber].Vector &= ~ACTIVE_LOW;
  400. }
  401. }
  402. VOID
  403. HalpSetLevel(
  404. ULONG Inti,
  405. BOOLEAN LevelTriggered
  406. )
  407. {
  408. PIO_INTR_CONTROL IoUnit;
  409. ULONG RteNumber;
  410. HalpInti2InterruptController (
  411. Inti,&IoUnit,&RteNumber
  412. );
  413. ASSERT(IoUnit);
  414. if (LevelTriggered) {
  415. IoUnit->Inti[RteNumber].Vector |= LEVEL_TRIGGERED;
  416. } else {
  417. IoUnit->Inti[RteNumber].Vector &= ~LEVEL_TRIGGERED;
  418. }
  419. }
  420. VOID
  421. HalpSpuriousHandler (
  422. IN PKINTERRUPT_ROUTINE Interrupt,
  423. IN PKTRAP_FRAME TrapFrame
  424. )
  425. /*++
  426. Routine Description:
  427. Spurious Interrupt handler. Dummy return or we can count number of
  428. occurance of spurious interrupts. Right now, we will do a dummy return.
  429. Arguements:
  430. Return Parameters:
  431. --*/
  432. {
  433. }