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.

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