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
|