472 lines
8.7 KiB
C
472 lines
8.7 KiB
C
#if defined(JENSEN)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
.../ntos/hal/alpha/jxinitnt.c
|
||
|
||
Abstract:
|
||
|
||
|
||
This module implements the interrupt initialization for an Alpha/Jensen
|
||
system. Contains the VLSI 82C106, the 82357 and an EISA bus.
|
||
|
||
Stolen from Dave Cutler's jxinitnt.c in ../mips
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 26-Apr-1991
|
||
Jeff McLeman (DEC) 18-May-1992
|
||
Miche Baker-Harvey (miche) 18-May-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
Jeff McLeman (DEC) 30-Jul-1992
|
||
Remove Clock interrupt from this module, because it is done
|
||
in JXCLOCK.C
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "jnsnrtc.h"
|
||
#include "jnsndef.h"
|
||
#include "jxserp.h"
|
||
#include "eisa.h"
|
||
|
||
|
||
|
||
//
|
||
// Define global data for builtin device interrupt enables.
|
||
//
|
||
|
||
USHORT HalpBuiltinInterruptEnable;
|
||
|
||
|
||
// irql mask and tables
|
||
//
|
||
// irql 0 - passive
|
||
// irql 1 - sfw apc level
|
||
// irql 2 - sfw dispatch level
|
||
// irql 3 - device low (All devices except)
|
||
// irql 4 - device high (the serial lines)
|
||
// irql 5 - clock
|
||
// irql 6 - real time
|
||
// irql 7 - error, mchk, nmi, halt
|
||
//
|
||
//
|
||
// IDT mappings:
|
||
// For the built-ins, GetInterruptVector will need more info,
|
||
// or it will have to be built-in to the routines, since
|
||
// these don't match IRQL levels in any meaningful way.
|
||
//
|
||
// 0 passive 8
|
||
// 1 apc 9
|
||
// 2 dispatch 10 PIC
|
||
// 3 11 keyboard/mouse
|
||
// 4 serial 12 errors
|
||
// 5 clock 13 parallel
|
||
// 6 14 halt
|
||
// 7 nmi 15
|
||
//
|
||
// This is assuming the following prioritization:
|
||
// nmi
|
||
// halt
|
||
// errors
|
||
// clock
|
||
// serial
|
||
// parallel
|
||
// keyboard/mouse
|
||
// pic
|
||
|
||
//
|
||
// This is the HalpIrqlMask for Jensen
|
||
// Jensen interrupt pins:
|
||
//
|
||
// eirq 0 interval timer from 82c106
|
||
// eirq 1 PIC - 82357 interrupts
|
||
// eirq 2 NMI from the ISP
|
||
// eirq 3 Keyboard and Mouse (82c106)
|
||
// eirq 4 Front-panel HALT switch
|
||
// eirq 5 serial ports A and B.
|
||
// (note that the parallel printer from the 82c106 comes in on the PIC)
|
||
|
||
#include "jxirql.h"
|
||
|
||
//
|
||
// For information purposes: here is what the IDT division looks like:
|
||
//
|
||
// 000-015 Built-ins (we only use 8 entries; NT wants 10)
|
||
// 016-031 ISA
|
||
// 048-063 EISA
|
||
// 080-095 PCI
|
||
// 112-127 Turbo Channel
|
||
// 128-255 unused, as are all other holes
|
||
//
|
||
|
||
VOID
|
||
HalpClearInterrupts(
|
||
);
|
||
|
||
VOID
|
||
HalpHaltInterrupt(
|
||
);
|
||
|
||
|
||
BOOLEAN
|
||
HalpInitializeInterrupts (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes interrupts for an Alpha system.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A value of TRUE is returned if the initialization is successfully
|
||
completed. Otherwise a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UCHAR DataByte;
|
||
ULONG DataLong;
|
||
ULONG Index;
|
||
extern VOID KeUpdateSystemTime(VOID);
|
||
|
||
//
|
||
// Initialize HAL processor parameters based on estimated CPU speed.
|
||
// This must be done before HalpStallExecution is called. Compute integral
|
||
// megahertz first to avoid rounding errors due to imprecise cycle clock
|
||
// period values.
|
||
//
|
||
|
||
HalpInitializeProcessorParameters();
|
||
|
||
//
|
||
// Initialize the IRQL translation table in the PCR. These tables are
|
||
// used by the interrupt dispatcher to determine the new irql, and to
|
||
// determine the vector into the IDT. This is a bit different from
|
||
// "normal" NT, which uses the IRQL to index into the vector table directly.
|
||
// Since we have more information about who has interrupted (from the CPU
|
||
// interrupt pins), we use that information to get directly to the vector
|
||
// for the builting device which has interrupted.
|
||
//
|
||
|
||
|
||
for (Index = 0; Index < (sizeof(HalpIrqlMask)/4); Index++){
|
||
PCR->IrqlMask[Index].IrqlTableIndex = HalpIrqlMask[Index].IrqlTableIndex;
|
||
PCR->IrqlMask[Index].IDTIndex = HalpIrqlMask[Index].IDTIndex;
|
||
}
|
||
|
||
for (Index = 0; Index < (sizeof(HalpIET)/4); Index++){
|
||
PCR->IrqlTable[Index] = HalpIET[Index];
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Connect the Stall interrupt vector to the clock. When the
|
||
// profile count is calculated, we then connect the normal
|
||
// clock.
|
||
|
||
|
||
PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpStallInterrupt;
|
||
|
||
//
|
||
// Register the Halt interrupt
|
||
//
|
||
|
||
PCR->InterruptRoutine[HALT_VECTOR] = (PKINTERRUPT_ROUTINE)HalpHaltInterrupt;
|
||
|
||
HalpInitializeProfiler();
|
||
|
||
//
|
||
// Clear all pending interrupts
|
||
//
|
||
|
||
HalpClearInterrupts();
|
||
|
||
//
|
||
// Start the peridodic interrupt from the RTC
|
||
//
|
||
HalpProgramIntervalTimer(MAXIMUM_RATE_SELECT);
|
||
|
||
//
|
||
// Later there must be initialization for the local interrupts
|
||
// and PIC, but not now ....
|
||
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpClearInterrupts(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function clears all pending interrupts on the Jensen.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PSP_READ_REGISTERS SP_READ;
|
||
PSP_WRITE_REGISTERS SP_WRITE;
|
||
UCHAR tmp;
|
||
int i;
|
||
UCHAR btmp;
|
||
UCHAR DataByte;
|
||
|
||
//
|
||
// clear out VTI interrupts, except the RTC
|
||
//
|
||
|
||
#ifdef JMBUG
|
||
//
|
||
// Reset the EISA bus. This is a draconian way of clearing out any
|
||
// residual interrupts. It has to be done here in Phase 0, because
|
||
// unlike the Jazz machine, our I/O and graphics are on EISA. If we
|
||
// were to pull EISA reset in Phase 1, we would lose device context.
|
||
// Sort of like changing your sparkplugs while driving 65 MPH on
|
||
// interstate 5.
|
||
|
||
DataByte = 0;
|
||
|
||
((PNMI_EXTENDED_CONTROL) &DataByte)->BusReset = 1;
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR)(&((PEISA_CONTROL)DMA_VIRTUAL_BASE)->ExtendedNmiResetControl),
|
||
DataByte
|
||
);
|
||
|
||
//
|
||
// Use a stall loop since KeStallExecutionProcessor isn't available in
|
||
// Phase 0.
|
||
//
|
||
|
||
HalpStallExecution(4);
|
||
|
||
DataByte = 0;
|
||
|
||
WRITE_PORT_UCHAR(
|
||
(PUCHAR)(&((PEISA_CONTROL)DMA_VIRTUAL_BASE)->ExtendedNmiResetControl),
|
||
DataByte
|
||
);
|
||
#endif
|
||
|
||
//
|
||
// COM1
|
||
//
|
||
|
||
//
|
||
// clear the interrupt enable
|
||
//
|
||
|
||
outVti(0x3f9, 0x0);
|
||
HalpStallExecution(3);
|
||
|
||
//
|
||
// clear out port 1 interrupts
|
||
//
|
||
|
||
outVti(0x3fc, 0x0f);
|
||
HalpStallExecution(3);
|
||
|
||
tmp = inVti(0x3fb);
|
||
tmp &= ~0xc0;
|
||
outVti(0x3fb, tmp);
|
||
HalpStallExecution(3);
|
||
|
||
for (i = 0; i< 15; i++) {
|
||
tmp = inVti(0x3f8);
|
||
HalpStallExecution(3);
|
||
if (!inVti(0x3fd) & 1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i< 1000; i++) {
|
||
if(!(0x3fe & 0x0f)) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i< 5; i++) {
|
||
if (inVti(0x3fa) & 1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// clear the interrupt enable
|
||
//
|
||
|
||
outVti(0x3f9, 0x0);
|
||
HalpStallExecution(3);
|
||
//DbgPrint("COM1: Interrupt Enable = %x\n", inVti(0x3f9));
|
||
|
||
//
|
||
// COM2
|
||
//
|
||
|
||
//
|
||
// clear the interrupt enable
|
||
//
|
||
|
||
outVti(0x2f9, 0x0);
|
||
HalpStallExecution(3);
|
||
|
||
//
|
||
// clear out port 2 interrupts
|
||
//
|
||
|
||
outVti(0x2fc, 0x0f);
|
||
HalpStallExecution(3);
|
||
|
||
tmp = inVti(0x2fb);
|
||
tmp &= ~0xc0;
|
||
outVti(0x2fb, tmp);
|
||
HalpStallExecution(3);
|
||
|
||
for (i = 0; i< 15; i++) {
|
||
tmp = inVti(0x2f8);
|
||
HalpStallExecution(3);
|
||
if (!inVti(0x2fd) & 1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i< 1000; i++) {
|
||
if(!(0x2fe & 0x0f)) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i< 5; i++) {
|
||
if (inVti(0x2fa) & 1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// clear the interrupt enable
|
||
//
|
||
|
||
outVti(0x2f9, 0x0);
|
||
HalpStallExecution(3);
|
||
//DbgPrint("COM2: Interrupt Enable = %x\n", inVti(0x2f9));
|
||
|
||
//
|
||
// Kbd and Mouse
|
||
//
|
||
|
||
outVti(0x64, 0x60);
|
||
HalpStallExecution(3);
|
||
outVti(0x60, 0x0);
|
||
HalpStallExecution(3);
|
||
tmp = inVti(0x60);
|
||
while (inVti(0x64) & 1) {
|
||
HalpStallExecution(3);
|
||
tmp = inVti(0x60);
|
||
}
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpStallExecution(
|
||
ULONG Microseconds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used internally to the HAL on Alpha AXP systems to
|
||
stall execution before KeStallExecutionProcessor is available.
|
||
|
||
Arguments:
|
||
|
||
Microseconds - Supplies the number of microseconds to stall.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LONG StallCyclesRemaining; // signed value
|
||
ULONG PreviousRpcc, CurrentRpcc;
|
||
|
||
|
||
//
|
||
// Get the value of the RPCC as soon as we enter
|
||
//
|
||
|
||
PreviousRpcc = HalpRpcc();
|
||
|
||
//
|
||
// Compute the number of cycles to stall
|
||
//
|
||
|
||
StallCyclesRemaining = Microseconds * HalpClockMegaHertz;
|
||
|
||
//
|
||
// Wait while there are stall cycles remaining.
|
||
// The accuracy of this routine is limited by the
|
||
// length of this while loop.
|
||
//
|
||
|
||
while (StallCyclesRemaining > 0) {
|
||
|
||
CurrentRpcc = HalpRpcc();
|
||
|
||
//
|
||
// The subtraction always works because the Rpcc
|
||
// is a wrapping long-word. If it wraps, we still
|
||
// get the positive number we want.
|
||
//
|
||
|
||
StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc);
|
||
|
||
//
|
||
// remember this RPCC value
|
||
//
|
||
|
||
PreviousRpcc = CurrentRpcc;
|
||
}
|
||
|
||
}
|
||
|
||
#endif
|