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.

786 lines
18 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. axebsup.c
  5. Abstract:
  6. The module provides the EISA bus support for Alpha/Jensen systems.
  7. Author:
  8. Jeff Havens (jhavens) 19-Jun-1991
  9. Miche Baker-Harvey (miche) 13-May-1992
  10. Jeff McLeman (DEC) 1-Jun-1992
  11. Revision History:
  12. 11-Mar-1993 Joe Mitchell (DEC)
  13. Added support for NMI interrupts: Added interrupt service routine
  14. HalHandleNMI. Added code to HalpCreateEisaStructures to initialize
  15. NMI interrupts.
  16. 22-Jul-1992 Jeff McLeman (mcleman)
  17. Removed eisa xfer routines, since this is done in JXHWSUP
  18. 02-Jul-92 Jeff McLeman (mcleman)
  19. Removed alphadma.h header file. This file was not needed since
  20. the DMA structure is described in the eisa header. Also add
  21. a note describing eisa references in this module.
  22. 13-May-92 Stole file jxebsup.c and converted for Alpha/Jensen
  23. --*/
  24. // ** note **
  25. // This module has routines that manipulate eisa on alpha machines. On
  26. // the jensen machine, this is done in jxhwsup.c . These routines
  27. // would be used for an alpha machine that had a local bus and an
  28. // eisa bus.
  29. //
  30. #include "halp.h"
  31. #include "jnsndef.h"
  32. #include "jnsnint.h"
  33. #include "eisa.h"
  34. //
  35. // Define the context structure for use by the interrupt routine.
  36. //
  37. typedef BOOLEAN (*PSECONDARY_DISPATCH)(
  38. PVOID InterruptRoutine,
  39. PKTRAP_FRAME TrapFrame
  40. );
  41. //
  42. // Declare the interupt structure and spinlock for the intermediate EISA
  43. // interrupt dispachter.
  44. //
  45. KINTERRUPT HalpEisaInterrupt;
  46. /* [jrm 3/8/93] Add support for NMI interrupts */
  47. //
  48. // The following is the interrupt object used for DMA controller interrupts.
  49. // DMA controller interrupts occur when a memory parity error occurs or a
  50. // programming error occurs to the DMA controller.
  51. //
  52. KINTERRUPT HalpEisaNmiInterrupt;
  53. UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n";
  54. //
  55. // The following function is called when an EISA NMI occurs.
  56. //
  57. BOOLEAN
  58. HalHandleNMI(
  59. IN PKINTERRUPT Interrupt,
  60. IN PVOID ServiceContext
  61. );
  62. //
  63. // Define save area for ESIA adapter objects.
  64. //
  65. PADAPTER_OBJECT HalpEisaAdapter[8];
  66. //
  67. // Define save area for EISA interrupt mask registers and level\edge control
  68. // registers.
  69. //
  70. UCHAR HalpEisaInterrupt1Mask;
  71. UCHAR HalpEisaInterrupt2Mask;
  72. UCHAR HalpEisaInterrupt1Level;
  73. UCHAR HalpEisaInterrupt2Level;
  74. BOOLEAN
  75. HalpCreateEisaStructures (
  76. VOID
  77. )
  78. /*++
  79. Routine Description:
  80. This routine initializes the structures necessary for EISA operations
  81. and connects the intermediate interrupt dispatcher. It also initializes the
  82. EISA interrupt controller.
  83. Arguments:
  84. None.
  85. Return Value:
  86. If the second level interrupt dispatcher is connected, then a value of
  87. TRUE is returned. Otherwise, a value of FALSE is returned.
  88. --*/
  89. {
  90. UCHAR DataByte;
  91. KIRQL oldIrql;
  92. //
  93. // Initialize the EISA NMI interrupt.
  94. //
  95. KeInitializeInterrupt( &HalpEisaNmiInterrupt,
  96. HalHandleNMI,
  97. NULL,
  98. NULL,
  99. EISA_NMI_VECTOR,
  100. EISA_NMI_LEVEL,
  101. EISA_NMI_LEVEL,
  102. LevelSensitive,
  103. FALSE,
  104. 0,
  105. FALSE
  106. );
  107. //
  108. // Don't fail if the interrupt cannot be connected.
  109. //
  110. KeConnectInterrupt( &HalpEisaNmiInterrupt );
  111. //
  112. // Clear the Eisa NMI disable bit. This bit is the high order of the
  113. // NMI enable register.
  114. //
  115. DataByte = 0;
  116. WRITE_PORT_UCHAR(
  117. &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
  118. DataByte
  119. );
  120. //
  121. // Enable Software-Generated NMI interrupts by setting bit 1 of port 0x461.
  122. //
  123. DataByte = 0x02;
  124. WRITE_PORT_UCHAR(
  125. &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
  126. DataByte
  127. );
  128. //
  129. // Initialize the EISA interrupt dispatcher for Jazz I/O interrupts.
  130. //
  131. KeInitializeInterrupt( &HalpEisaInterrupt,
  132. HalpEisaDispatch,
  133. (PVOID) EISA_INTA_CYCLE_VIRTUAL_BASE,
  134. (PKSPIN_LOCK)NULL,
  135. PIC_VECTOR,
  136. EISA_DEVICE_LEVEL,
  137. EISA_DEVICE_LEVEL,
  138. LevelSensitive,
  139. TRUE,
  140. 0,
  141. FALSE
  142. );
  143. if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
  144. return(FALSE);
  145. }
  146. //
  147. // Raise the IRQL while the EISA interrupt controller is initalized.
  148. //
  149. KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql);
  150. //
  151. // Initialize the EISA interrupt controller. There are two cascaded
  152. // interrupt controllers, each of which must initialized with 4 initialize
  153. // control words.
  154. //
  155. DataByte = 0;
  156. ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
  157. ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
  158. WRITE_PORT_UCHAR(
  159. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  160. DataByte
  161. );
  162. WRITE_PORT_UCHAR(
  163. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  164. DataByte
  165. );
  166. //
  167. // The second intitialization control word sets the iterrupt vector to
  168. // 0-15.
  169. //
  170. DataByte = 0;
  171. WRITE_PORT_UCHAR(
  172. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  173. DataByte
  174. );
  175. DataByte = 0x08;
  176. WRITE_PORT_UCHAR(
  177. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  178. DataByte
  179. );
  180. //
  181. // The thrid initialization control word set the controls for slave mode.
  182. // The master ICW3 uses bit position and the slave ICW3 uses a numberic.
  183. //
  184. DataByte = 1 << SLAVE_IRQL_LEVEL;
  185. WRITE_PORT_UCHAR(
  186. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  187. DataByte
  188. );
  189. DataByte = SLAVE_IRQL_LEVEL;
  190. WRITE_PORT_UCHAR(
  191. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  192. DataByte
  193. );
  194. //
  195. // The fourth initialization control word is used to specify normal
  196. // end-of-interrupt mode and not special-fully-nested mode.
  197. //
  198. DataByte = 0;
  199. ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
  200. WRITE_PORT_UCHAR(
  201. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  202. DataByte
  203. );
  204. WRITE_PORT_UCHAR(
  205. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  206. DataByte
  207. );
  208. //
  209. // Disable all of the interrupts except the slave.
  210. //
  211. HalpEisaInterrupt1Mask = ~(1 << SLAVE_IRQL_LEVEL);
  212. WRITE_PORT_UCHAR(
  213. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  214. HalpEisaInterrupt1Mask
  215. );
  216. HalpEisaInterrupt2Mask = 0xFF;
  217. WRITE_PORT_UCHAR(
  218. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  219. HalpEisaInterrupt2Mask
  220. );
  221. //
  222. // Initialize the edge/level register masks to 0 which is the default
  223. // edge sensitive value.
  224. //
  225. HalpEisaInterrupt1Level = 0;
  226. HalpEisaInterrupt2Level = 0;
  227. //
  228. // Restore IRQL level.
  229. //
  230. KeLowerIrql(oldIrql);
  231. //
  232. // Initialize the DMA mode registers to a default value.
  233. // Disable all of the DMA channels except channel 4 which is the
  234. // cascade of channels 0-3.
  235. //
  236. WRITE_PORT_UCHAR(
  237. &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
  238. 0x0F
  239. );
  240. WRITE_PORT_UCHAR(
  241. &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
  242. 0x0E
  243. );
  244. return(TRUE);
  245. }
  246. BOOLEAN
  247. HalpEisaDispatch(
  248. IN PKINTERRUPT Interrupt,
  249. IN PVOID ServiceContext
  250. )
  251. /*++
  252. Routine Description:
  253. This routine is entered as the result of an interrupt being generated
  254. via the vector that is connected to an interrupt object that describes
  255. the EISA device interrupts. Its function is to call the second
  256. level interrupt dispatch routine and acknowledge the interrupt at the EISA
  257. controller.
  258. This service routine should be connected as follows:
  259. KeInitializeInterrupt(&Interrupt, HalpEisaDispatch,
  260. EISA_VIRTUAL_BASE,
  261. (PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_LEVEL,
  262. LevelSensitive, TRUE, 0, FALSE);
  263. KeConnectInterrupt(&Interrupt);
  264. Arguments:
  265. Interrupt - Supplies a pointer to the interrupt object.
  266. ServiceContext - Supplies a pointer to the EISA interrupt acknowledge
  267. register.
  268. Return Value:
  269. Returns the value returned from the second level routine.
  270. --*/
  271. {
  272. UCHAR interruptVector;
  273. PKPRCB Prcb;
  274. BOOLEAN returnValue;
  275. USHORT PCRInOffset;
  276. UCHAR Int1Isr;
  277. UCHAR Int2Isr;
  278. PULONG DispatchCode;
  279. PKINTERRUPT InterruptObject;
  280. //
  281. // Read the interrupt vector.
  282. //
  283. interruptVector = READ_PORT_UCHAR(ServiceContext);
  284. //
  285. // schedule the read
  286. //
  287. HalpMb();
  288. KeStallExecutionProcessor(1);
  289. interruptVector = READ_PORT_UCHAR(ServiceContext);
  290. if ((interruptVector & 0x07) == 0x07) {
  291. //
  292. // Check for a passive release by looking at the inservice register.
  293. // If there is a real IRQL7 interrupt, just go along normally. If there
  294. // is not, then it is a passive release. So just dismiss it.
  295. //
  296. WRITE_PORT_UCHAR(
  297. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  298. 0x0B
  299. );
  300. Int1Isr = READ_PORT_UCHAR(
  301. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
  302. //
  303. // do second controller
  304. //
  305. WRITE_PORT_UCHAR(
  306. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  307. 0x0B
  308. );
  309. Int2Isr = READ_PORT_UCHAR(
  310. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
  311. if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
  312. //
  313. // Clear the master controller to clear situation
  314. //
  315. if (!(Int2Isr & 0x80)) {
  316. WRITE_PORT_UCHAR(
  317. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  318. NONSPECIFIC_END_OF_INTERRUPT
  319. );
  320. }
  321. return(TRUE);
  322. }
  323. }
  324. //
  325. // Dispatch to the secondary interrupt service routine.
  326. //
  327. PCRInOffset = interruptVector + EISA_VECTORS;
  328. DispatchCode = PCR->InterruptRoutine[PCRInOffset];
  329. InterruptObject = CONTAINING_RECORD(DispatchCode,
  330. KINTERRUPT,
  331. DispatchCode);
  332. returnValue = ((PSECONDARY_DISPATCH) InterruptObject->DispatchAddress)(
  333. InterruptObject,
  334. NULL);
  335. //
  336. // Dismiss the interrupt in the EISA interrupt controllers.
  337. //
  338. //
  339. // If this is a cascaded interrupt then the interrupt must be dismissed in
  340. // both controlles.
  341. //
  342. if (interruptVector & 0x08) {
  343. WRITE_PORT_UCHAR(
  344. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
  345. NONSPECIFIC_END_OF_INTERRUPT
  346. );
  347. }
  348. WRITE_PORT_UCHAR(
  349. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
  350. NONSPECIFIC_END_OF_INTERRUPT
  351. );
  352. return(returnValue);
  353. }
  354. VOID
  355. HalpDisableEisaInterrupt(
  356. IN ULONG Vector
  357. )
  358. /*++
  359. Routine Description:
  360. This function Disables the EISA bus specified EISA bus interrupt.
  361. Arguments:
  362. Vector - Supplies the vector of the ESIA interrupt that is Disabled.
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. //
  368. // Calculate the EISA interrupt vector.
  369. //
  370. Vector -= EISA_VECTORS;
  371. //
  372. // Determine if this vector is for interrupt controller 1 or 2.
  373. //
  374. if (Vector & 0x08) {
  375. //
  376. // The interrupt is in controller 2.
  377. //
  378. Vector &= 0x7;
  379. HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
  380. WRITE_PORT_UCHAR(
  381. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  382. HalpEisaInterrupt2Mask
  383. );
  384. } else {
  385. //
  386. // The interrupt is in controller 1.
  387. //
  388. Vector &= 0x7;
  389. //
  390. // never disable IRQL2, it is the slave interrupt
  391. //
  392. if (Vector != SLAVE_IRQL_LEVEL) {
  393. HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
  394. WRITE_PORT_UCHAR(
  395. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  396. HalpEisaInterrupt1Mask
  397. );
  398. }
  399. }
  400. }
  401. VOID
  402. HalpEnableEisaInterrupt(
  403. IN ULONG Vector,
  404. IN KINTERRUPT_MODE InterruptMode
  405. )
  406. /*++
  407. Routine Description:
  408. This function enables the EISA bus specified EISA bus interrupt and sets
  409. the level/edge register to the requested value.
  410. Arguments:
  411. Vector - Supplies the vector of the ESIA interrupt that is enabled.
  412. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  413. Latched.
  414. Return Value:
  415. None.
  416. --*/
  417. {
  418. //
  419. // Calculate the EISA interrupt vector.
  420. //
  421. Vector -= EISA_VECTORS;
  422. //
  423. // Determine if this vector is for interrupt controller 1 or 2.
  424. //
  425. if (Vector & 0x08) {
  426. //
  427. // The interrupt is in controller 2.
  428. //
  429. Vector &= 0x7;
  430. HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
  431. WRITE_PORT_UCHAR(
  432. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
  433. HalpEisaInterrupt2Mask
  434. );
  435. //
  436. // Set the level/edge control register.
  437. //
  438. if (InterruptMode == LevelSensitive) {
  439. HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
  440. } else {
  441. HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
  442. }
  443. WRITE_PORT_UCHAR(
  444. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
  445. HalpEisaInterrupt2Level
  446. );
  447. } else {
  448. //
  449. // The interrupt is in controller 1.
  450. //
  451. Vector &= 0x7;
  452. HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
  453. WRITE_PORT_UCHAR(
  454. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
  455. HalpEisaInterrupt1Mask
  456. );
  457. //
  458. // Set the level/edge control register.
  459. //
  460. if (InterruptMode == LevelSensitive) {
  461. HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
  462. } else {
  463. HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
  464. }
  465. WRITE_PORT_UCHAR(
  466. &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
  467. HalpEisaInterrupt1Level
  468. );
  469. }
  470. }
  471. BOOLEAN
  472. HalHandleNMI(
  473. IN PKINTERRUPT Interrupt,
  474. IN PVOID ServiceContext
  475. )
  476. /*++
  477. Routine Description:
  478. This function is called when an EISA NMI occurs. It print the appropriate
  479. status information and bugchecks.
  480. Arguments:
  481. Interrupt - Supplies a pointer to the interrupt object
  482. ServiceContext - Bug number to call bugcheck with.
  483. Return Value:
  484. Returns TRUE.
  485. --*/
  486. {
  487. UCHAR StatusByte;
  488. UCHAR EisaPort;
  489. ULONG port;
  490. ULONG AddressSpace = 1; // 1 = I/O address space
  491. BOOLEAN Status;
  492. PHYSICAL_ADDRESS BusAddress;
  493. PHYSICAL_ADDRESS TranslatedAddress;
  494. StatusByte =
  495. READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
  496. if (StatusByte & 0x80) {
  497. HalDisplayString ("NMI: Parity Check / Parity Error\n");
  498. }
  499. if (StatusByte & 0x40) {
  500. HalDisplayString ("NMI: Channel Check / IOCHK\n");
  501. }
  502. //
  503. // This is an Eisa machine, check for extnded nmi information...
  504. //
  505. StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl);
  506. if (StatusByte & 0x80) {
  507. HalDisplayString ("NMI: Fail-safe timer\n");
  508. }
  509. if (StatusByte & 0x40) {
  510. HalDisplayString ("NMI: Bus Timeout\n");
  511. }
  512. if (StatusByte & 0x20) {
  513. HalDisplayString ("NMI: Software NMI generated\n");
  514. }
  515. //
  516. // Look for any Eisa expansion board. See if it asserted NMI.
  517. //
  518. BusAddress.HighPart = 0;
  519. for (EisaPort = 0; EisaPort <= 0xf; EisaPort++)
  520. {
  521. BusAddress.LowPart = (EisaPort << 12) + 0xC80;
  522. Status = HalTranslateBusAddress(Eisa, // InterfaceType
  523. 0, // BusNumber (0 for Jensen)
  524. BusAddress,
  525. &AddressSpace, // 1=I/O address space
  526. &TranslatedAddress); // QVA
  527. if (Status == FALSE)
  528. {
  529. UCHAR pbuf[80];
  530. sprintf(pbuf,
  531. "Unable to translate bus address %x for EISA slot %d\n",
  532. BusAddress.LowPart, EisaPort);
  533. HalDisplayString(pbuf);
  534. KeBugCheck(NMI_HARDWARE_FAILURE);
  535. }
  536. port = TranslatedAddress.LowPart;
  537. WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
  538. StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
  539. if ((StatusByte & 0x80) == 0) {
  540. //
  541. // Found valid Eisa board, Check to see if it's
  542. // if IOCHKERR is asserted.
  543. //
  544. StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
  545. if (StatusByte & 0x2) {
  546. EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
  547. HalDisplayString (EisaNMIMsg);
  548. }
  549. }
  550. }
  551. #if 0
  552. // Reset NMI interrupts (for debugging purposes only).
  553. WRITE_PORT_UCHAR(
  554. &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00);
  555. WRITE_PORT_UCHAR(
  556. &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02);
  557. #endif
  558. KeBugCheck(NMI_HARDWARE_FAILURE);
  559. return(TRUE);
  560. }