Windows NT 4.0 source code leak
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

5 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Copyright (c) 1992, 1993 Digital Equipment Corporation
  4. Module Name:
  5. ebintsup.c
  6. Abstract:
  7. The module provides the interrupt support for EB66/Mustang systems.
  8. Author:
  9. Eric Rehm (DEC) 29-December-1993
  10. Revision History:
  11. Dick Bissen [DEC] 12-May-1994
  12. Removed all support of the EB66 pass1 module from the code.
  13. --*/
  14. #include "halp.h"
  15. #include "eisa.h"
  16. #include "ebsgdma.h"
  17. #include "eb66def.h"
  18. #include "pcrtc.h"
  19. #include "pintolin.h"
  20. //
  21. // Global to control interrupt handling for EB64+
  22. //
  23. UCHAR IntMask0, IntMask1, IntMask2;
  24. VOID
  25. HalpInitializePciInterrupts (
  26. VOID
  27. );
  28. BOOLEAN
  29. HalpPCIDispatch(
  30. IN PKINTERRUPT Interrupt,
  31. IN PVOID ServiceContext,
  32. IN PKTRAP_FRAME TrapFrame
  33. );
  34. //
  35. // Define the context structure for use by interrupt service routines.
  36. //
  37. typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
  38. PKINTERRUPT InterruptObject
  39. );
  40. //
  41. // The following is the interrupt object used for DMA controller interrupts.
  42. // DMA controller interrupts occur when a memory parity error occurs or a
  43. // programming error occurs to the DMA controller.
  44. //
  45. KINTERRUPT HalpEisaNmiInterrupt;
  46. //
  47. // The following function initializes NMI handling.
  48. //
  49. VOID
  50. HalpInitializeNMI(
  51. VOID
  52. );
  53. //
  54. // The following functions is called when an EISA NMI occurs.
  55. //
  56. BOOLEAN
  57. HalHandleNMI(
  58. IN PKINTERRUPT Interrupt,
  59. IN PVOID ServiceContext
  60. );
  61. VOID
  62. HalpDisableSioInterrupt(
  63. IN ULONG Vector
  64. );
  65. VOID
  66. HalpEnableSioInterrupt(
  67. IN ULONG Vector,
  68. IN KINTERRUPT_MODE InterruptMode
  69. );
  70. BOOLEAN
  71. HalpInitializePCIInterrupts (
  72. VOID
  73. )
  74. /*++
  75. Routine Description:
  76. This routine initializes the structures necessary for EISA & PCI operations
  77. and connects the intermediate interrupt dispatcher. It also initializes the
  78. EISA interrupt controller.
  79. Arguments:
  80. None.
  81. Return Value:
  82. If the second level interrupt dispatcher is connected, then a value of
  83. TRUE is returned. Otherwise, a value of FALSE is returned.
  84. --*/
  85. {
  86. UCHAR DataByte;
  87. KIRQL oldIrql;
  88. UCHAR *SystemType;
  89. //
  90. // Initialize the SIO NMI interrupt.
  91. //
  92. HalpInitializeNMI();
  93. //
  94. // Directly connect the ISA interrupt dispatcher to the level for
  95. // ISA bus interrupt.
  96. //
  97. // N.B. This vector is reserved for exclusive use by the HAL (see
  98. // interrupt initialization.
  99. //
  100. PCR->InterruptRoutine[PIC_VECTOR] = (PVOID)HalpPCIDispatch;
  101. HalEnableSystemInterrupt(PIC_VECTOR, DEVICE_LEVEL, LevelSensitive);
  102. if (SystemIsEB66P)
  103. (PVOID) HalpPCIPinToLineTable = (PVOID) EB66PPCIPinToLineTable;
  104. else
  105. (PVOID) HalpPCIPinToLineTable = (PVOID) EB66PCIPinToLineTable;
  106. //
  107. // Raise the IRQL while the PCI interrupt controller is initalized.
  108. //
  109. KeRaiseIrql(PCI_DEVICE_LEVEL, &oldIrql);
  110. //
  111. // Initialize the PCI interrupts.
  112. //
  113. HalpInitializePciInterrupts();
  114. //
  115. // Initialize SIO Programmable Interrupt Contoller
  116. //
  117. HalpInitializeSioInterrupts();
  118. //
  119. // Restore IRQL level.
  120. //
  121. KeLowerIrql(oldIrql);
  122. //
  123. // Initialize the DMA mode registers to a default value.
  124. // Disable all of the DMA channels except channel 4 which is the
  125. // cascade of channels 0-3.
  126. //
  127. WRITE_PORT_UCHAR(
  128. &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
  129. 0x0F
  130. );
  131. WRITE_PORT_UCHAR(
  132. &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
  133. 0x0E
  134. );
  135. return(TRUE);
  136. }
  137. BOOLEAN
  138. HalpPCIDispatch(
  139. IN PKINTERRUPT Interrupt,
  140. IN PVOID ServiceContext,
  141. IN PKTRAP_FRAME TrapFrame
  142. )
  143. /*++
  144. Routine Description:
  145. This routine is entered as the result of an interrupt being generated
  146. via the vector that is connected to an interrupt object that describes
  147. the PCI and ISA device interrupts. Its function is to call the second
  148. level interrupt dispatch routine and acknowledge the interrupt at the ISA
  149. controller.
  150. This service routine should be connected as follows:
  151. KeInitializeInterrupt(&Interrupt, HalpPCIDispatch,
  152. EISA_VIRTUAL_BASE,
  153. (PKSPIN_LOCK)NULL, PCI_LEVEL, PCI_LEVEL, PCI_LEVEL,
  154. LevelSensitive, TRUE, 0, FALSE);
  155. KeConnectInterrupt(&Interrupt);
  156. Arguments:
  157. Interrupt - Supplies a pointer to the interrupt object.
  158. ServiceContext - Supplies a pointer to the ISA interrupt acknowledge
  159. register.
  160. TrapFrame - Supplies a pointer to the trap frame for this interrupt.
  161. Return Value:
  162. Returns the value returned from the second level routine.
  163. --*/
  164. {
  165. UCHAR PciVector, IntNumber;
  166. ULONG PCRInOffset = 0xffff;
  167. KPCR *pcr;
  168. //
  169. // Read in the 1st interrupt register.
  170. //
  171. PciVector = READ_PORT_UCHAR(INTERRUPT_MASK0_QVA) & IntMask0;
  172. //
  173. // Was it an ISA (SIO) interrupt?
  174. //
  175. if (PciVector & SIO_INTERRUPT_MASK) {
  176. //
  177. // ISA interrupt - call HalpSioDispatch().
  178. //
  179. return HalpSioDispatch();
  180. }
  181. //
  182. // Which PCI interrupt was it?
  183. //
  184. if (PciVector) {
  185. for(IntNumber = 0; IntNumber < 8; IntNumber++) {
  186. if (PciVector & 1) {
  187. PCRInOffset = IntNumber;
  188. break;
  189. }
  190. PciVector >>= 1;
  191. }
  192. } else {
  193. PciVector = READ_PORT_UCHAR(INTERRUPT_MASK1_QVA) & IntMask1;
  194. if (PciVector) {
  195. for(IntNumber = 0; IntNumber < 8; IntNumber++) {
  196. if (PciVector & 1) {
  197. PCRInOffset = IntNumber + 8;
  198. break;
  199. }
  200. PciVector >>= 1;
  201. }
  202. } else if (INTERRUPT_MASK2_QVA != NULL) {
  203. PciVector = READ_PORT_UCHAR(INTERRUPT_MASK2_QVA) & IntMask2;
  204. if (PciVector)
  205. PCRInOffset = 0x10;
  206. }
  207. }
  208. if (PCRInOffset == 0xffff) {
  209. return FALSE;
  210. }
  211. PCRInOffset += PCI_VECTORS;
  212. PCRInOffset++;
  213. return ((PSECONDARY_DISPATCH)PCR->InterruptRoutine[PCRInOffset])(
  214. PCR->InterruptRoutine[PCRInOffset], TrapFrame);
  215. }
  216. VOID
  217. HalpDisablePCIInterrupt(
  218. IN ULONG Vector
  219. )
  220. /*++
  221. Routine Description:
  222. This function Disables the PCI bus specified PCI bus interrupt.
  223. Arguments:
  224. Vector - Supplies the vector of the PCI interrupt that is Disabled.
  225. Return Value:
  226. None.
  227. --*/
  228. {
  229. //
  230. // Calculate the PCI interrupt vector.
  231. //
  232. Vector -= PCI_VECTORS;
  233. Vector--;
  234. //
  235. // Clear the corresponding bit in the appropriate interrupt mask
  236. // shadow and write it out to the interrupt mask.
  237. //
  238. if (Vector >= 0 && Vector <= 7) {
  239. IntMask0 &= (UCHAR) ~(1 << Vector);
  240. WRITE_PORT_UCHAR(INTERRUPT_MASK0_QVA, ~IntMask0);
  241. } else if (Vector >= 8 && Vector <= 0xf) {
  242. IntMask1 &= (UCHAR) ~(1 << (Vector - 8));
  243. WRITE_PORT_UCHAR(INTERRUPT_MASK1_QVA, ~IntMask1);
  244. } else if ((Vector == 0x10) && (INTERRUPT_MASK2_QVA != NULL)) {
  245. IntMask2 = 0;
  246. WRITE_PORT_UCHAR(INTERRUPT_MASK2_QVA, ~IntMask2);
  247. } else {
  248. #ifdef HALDBG
  249. DbgPrint("HalpDisablePCIInterrupt: bad vector\n");
  250. #endif // HALDBG
  251. }
  252. }
  253. VOID
  254. HalpEnablePCIInterrupt(
  255. IN ULONG Vector
  256. )
  257. /*++
  258. Routine Description:
  259. This function enables the PCI bus specified PCI bus interrupt.
  260. PCI interrupts must be LevelSensitve. (PCI Spec. 2.2.6)
  261. Arguments:
  262. Vector - Supplies the vector of the ESIA interrupt that is enabled.
  263. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  264. Latched.
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. //
  270. // Calculate the PCI interrupt vector.
  271. //
  272. Vector -= PCI_VECTORS;
  273. Vector--;
  274. //
  275. // Set the corresponding bit in the appropriate interrupt mask
  276. // shadow and write it out to the interrupt mask.
  277. //
  278. if (Vector >= 0 && Vector <= 7) {
  279. IntMask0 |= (UCHAR) (1 << Vector);
  280. WRITE_PORT_UCHAR(INTERRUPT_MASK0_QVA, ~IntMask0);
  281. } else if (Vector >= 8 && Vector <= 0xf) {
  282. IntMask1 |= (UCHAR) (1 << (Vector - 8));
  283. WRITE_PORT_UCHAR(INTERRUPT_MASK1_QVA, ~IntMask1);
  284. } else if ((Vector == 0x10) && (INTERRUPT_MASK2_QVA != NULL)) {
  285. IntMask2 = 1;
  286. WRITE_PORT_UCHAR(INTERRUPT_MASK2_QVA, ~IntMask2);
  287. } else {
  288. #ifdef HALDBG
  289. DbgPrint("HalpEnablePCIInterrupt: bad vector\n");
  290. #endif // HALDBG
  291. }
  292. }
  293. VOID
  294. HalpInitializeNMI(
  295. VOID
  296. )
  297. /*++
  298. Routine Description:
  299. This function is called to intialize SIO NMI interrupts.
  300. Arguments:
  301. None.
  302. Return Value:
  303. None.
  304. --*/
  305. {
  306. UCHAR DataByte;
  307. //
  308. // Initialize the SIO NMI interrupt.
  309. //
  310. KeInitializeInterrupt( &HalpEisaNmiInterrupt,
  311. HalHandleNMI,
  312. NULL,
  313. NULL,
  314. EISA_NMI_VECTOR,
  315. EISA_NMI_LEVEL,
  316. EISA_NMI_LEVEL,
  317. LevelSensitive,
  318. FALSE,
  319. 0,
  320. FALSE
  321. );
  322. //
  323. // Don't fail if the interrupt cannot be connected.
  324. //
  325. KeConnectInterrupt( &HalpEisaNmiInterrupt );
  326. //
  327. // Clear the Eisa NMI disable bit. This bit is the high order of the
  328. // NMI enable register.
  329. //
  330. DataByte = 0;
  331. WRITE_PORT_UCHAR(
  332. &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
  333. DataByte
  334. );
  335. }
  336. BOOLEAN
  337. HalHandleNMI(
  338. IN PKINTERRUPT Interrupt,
  339. IN PVOID ServiceContext
  340. )
  341. /*++
  342. Routine Description:
  343. This function is called when an EISA NMI occurs. It print the appropriate
  344. status information and bugchecks.
  345. Arguments:
  346. Interrupt - Supplies a pointer to the interrupt object
  347. ServiceContext - Bug number to call bugcheck with.
  348. Return Value:
  349. Returns TRUE.
  350. --*/
  351. {
  352. UCHAR StatusByte;
  353. UCHAR EisaPort;
  354. ULONG port;
  355. ULONG AddressSpace = 1; // 1 = I/O address space
  356. BOOLEAN Status;
  357. PHYSICAL_ADDRESS BusAddress;
  358. PHYSICAL_ADDRESS TranslatedAddress;
  359. StatusByte =
  360. READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
  361. if (StatusByte & 0x80) {
  362. HalDisplayString ("NMI: Parity Check / Parity Error\n");
  363. }
  364. if (StatusByte & 0x40) {
  365. HalDisplayString ("NMI: Channel Check / IOCHK\n");
  366. }
  367. //
  368. // This is an Isa machine, no extnded nmi information, so just do it.
  369. //
  370. KeBugCheck(NMI_HARDWARE_FAILURE);
  371. return(TRUE);
  372. }
  373. UCHAR
  374. HalpAcknowledgeEisaInterrupt(
  375. PVOID ServiceContext
  376. )
  377. /*++
  378. Routine Description:
  379. Acknowledge the EISA interrupt from the programmable interrupt controller.
  380. Return the vector number of the highest priority pending interrupt.
  381. Arguments:
  382. ServiceContext - Service context of the interrupt service supplies
  383. a pointer to the EISA interrupt acknowledge register.
  384. Return Value:
  385. Return the value of the highest priority pending interrupt.
  386. --*/
  387. {
  388. UCHAR InterruptVector;
  389. //
  390. // Read the interrupt vector from the PIC.
  391. //
  392. InterruptVector = READ_PORT_UCHAR(ServiceContext);
  393. return( InterruptVector );
  394. }
  395. VOID
  396. HalpAcknowledgeClockInterrupt(
  397. VOID
  398. )
  399. /*++
  400. Routine Description:
  401. Acknowledge the clock interrupt from the interval timer. The interval
  402. timer for EB66 comes from the Dallas real-time clock.
  403. Arguments:
  404. None.
  405. Return Value:
  406. None.
  407. --*/
  408. {
  409. //
  410. // Acknowledge the clock interrupt by reading the control register C of
  411. // the Real Time Clock.
  412. //
  413. HalpReadClockRegister( RTC_CONTROL_REGISTERC );
  414. return;
  415. }
  416. VOID
  417. HalpInitializePciInterrupts (
  418. VOID
  419. )
  420. /*++
  421. Routine Description:
  422. This routine initializes the PCI device interrupt mask.
  423. Arguments:
  424. None.
  425. Return Value:
  426. None.
  427. --*/
  428. {
  429. //
  430. // Initialize the shadow copies of the interrupt masks to enable only
  431. // the SIO interrupt.
  432. //
  433. IntMask0 = (UCHAR)SIO_INTERRUPT_MASK;
  434. IntMask1 = 0;
  435. IntMask2 = 0;
  436. //
  437. // Write the masks.
  438. //
  439. WRITE_PORT_UCHAR(INTERRUPT_MASK0_QVA, ~IntMask0);
  440. WRITE_PORT_UCHAR(INTERRUPT_MASK1_QVA, ~IntMask1);
  441. if (INTERRUPT_MASK2_QVA != NULL) {
  442. WRITE_PORT_UCHAR(INTERRUPT_MASK2_QVA, ~IntMask2);
  443. }
  444. }