1543 lines
39 KiB
C
1543 lines
39 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
apecserr.c
|
||
|
||
Abstract:
|
||
|
||
This module implements error handling (machine checks and error
|
||
interrupts) for machines based on the APECS chip-set.
|
||
|
||
Author:
|
||
|
||
Joe Notarangelo 14-Feb-1994
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
Chao Chen 31-Aug-1995 Added in ECC correctable error handling.
|
||
|
||
Balakumar.N 26-Sep-1995 added Uncorrectable Error Logging code and
|
||
merged Chao's changes to handle correctable error.
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "apecs.h"
|
||
#include "stdio.h"
|
||
|
||
//
|
||
// Declare the extern variable UncorrectableError declared in
|
||
// inithal.c.
|
||
//
|
||
extern PERROR_FRAME PUncorrectableError;
|
||
|
||
//
|
||
// Define the context structure for use by interrupt service routines.
|
||
//
|
||
|
||
typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
|
||
PKINTERRUPT InterruptObject,
|
||
PVOID ServiceContext
|
||
);
|
||
|
||
|
||
VOID
|
||
HalpSetMachineCheckEnables(
|
||
IN BOOLEAN DisableMachineChecks,
|
||
IN BOOLEAN DisableProcessorCorrectables,
|
||
IN BOOLEAN DisableSystemCorrectables
|
||
);
|
||
|
||
VOID
|
||
HalpApecsReportFatalError(
|
||
VOID
|
||
);
|
||
|
||
ULONG
|
||
HalpSimm(
|
||
ULONGLONG Address
|
||
);
|
||
|
||
VOID
|
||
HalpApecsCorrectableError(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
HalpApecsConfig(
|
||
PAPECS_CONFIGURATION Config
|
||
);
|
||
|
||
// jnfix - temp count
|
||
ULONG CorrectedMemoryReads = 0;
|
||
#define MAX_ERROR_STRING 128
|
||
|
||
extern ULONG HalDisablePCIParityChecking;
|
||
|
||
|
||
VOID
|
||
HalpInitializeMachineChecks(
|
||
IN BOOLEAN ReportCorrectableErrors
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes machine check handling for an APECS-based
|
||
system by clearing all pending errors in the COMANCHE and EPIC and
|
||
enabling correctable errors according to the callers specification.
|
||
|
||
Arguments:
|
||
|
||
ReportCorrectableErrors - Supplies a boolean value which specifies
|
||
if correctable error reporting should be
|
||
enabled.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG Dummy;
|
||
EPIC_ECSR Ecsr;
|
||
COMANCHE_EDSR Edsr;
|
||
|
||
//
|
||
// Clear the lost error bit in the Comanche EDSR.
|
||
//
|
||
|
||
Edsr.all = 0;
|
||
Edsr.Losterr = 1;
|
||
WRITE_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister,
|
||
Edsr.all );
|
||
|
||
//
|
||
// Unlock the other error bits of the EDSR by reading the error address
|
||
// registers.
|
||
//
|
||
|
||
Dummy = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister
|
||
);
|
||
|
||
Dummy = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister
|
||
);
|
||
|
||
//
|
||
// Clear all of the error bits in the Epic ECSR. Set correctable error
|
||
// reporting as requested.
|
||
//
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
|
||
|
||
//
|
||
// For the common registers, simply set them - common in that the P1
|
||
// definition matches the P2 definition (same structure offset).
|
||
//
|
||
|
||
Ecsr.Merr = 1;
|
||
Ecsr.Iptl = 1;
|
||
Ecsr.Umrd = 1;
|
||
Ecsr.Cmrd = 1;
|
||
Ecsr.Ndev = 1;
|
||
Ecsr.Tabt = 1;
|
||
Ecsr.Iope = 1;
|
||
Ecsr.Ddpe = 1;
|
||
Ecsr.Lost = 1;
|
||
Ecsr.Iort = 1;
|
||
|
||
if( ReportCorrectableErrors == TRUE ){
|
||
Ecsr.Dcei = 0;
|
||
} else {
|
||
Ecsr.Dcei = 1;
|
||
}
|
||
|
||
if (HalDisablePCIParityChecking == 0xffffffff) {
|
||
Ecsr.Dpec = 1;
|
||
} else {
|
||
Ecsr.Dpec = HalDisablePCIParityChecking;
|
||
}
|
||
#if HALDBG
|
||
if (HalDisablePCIParityChecking == 0) {
|
||
DbgPrint("apecserr: PCI Parity Checking ON\n");
|
||
} else if (HalDisablePCIParityChecking == 1) {
|
||
DbgPrint("apecserr: PCI Parity Checking OFF\n");
|
||
} else {
|
||
DbgPrint("apecserr: PCI Parity Checking OFF - not set by ARC yet\n");
|
||
}
|
||
#endif
|
||
|
||
WRITE_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
|
||
Ecsr.all );
|
||
|
||
//
|
||
// Set the machine check enables with the EV4.
|
||
//
|
||
|
||
if( ReportCorrectableErrors == TRUE ){
|
||
HalpSetMachineCheckEnables( FALSE, FALSE, FALSE );
|
||
} else {
|
||
HalpSetMachineCheckEnables( FALSE, TRUE, TRUE );
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
VOID
|
||
HalpReadApecsErrorRegisters(
|
||
VOID
|
||
)
|
||
{
|
||
COMANCHE_EDSR Edsr;
|
||
EPIC_ECSR Ecsr;
|
||
ULONG ErrorAddress;
|
||
ULONG ErrorHighAddress;
|
||
ULONG ErrorLowAddress;
|
||
ULONG Pear;
|
||
ULONG Sear;
|
||
ULONG SystemErrorAddress;
|
||
PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
|
||
|
||
if(PUncorrectableError){
|
||
apecserr = (PAPECS_UNCORRECTABLE_FRAME)
|
||
PUncorrectableError->UncorrectableFrame.RawSystemInformation;
|
||
}
|
||
|
||
if(apecserr)
|
||
HalpApecsConfig( &apecserr->Configuration);
|
||
|
||
//
|
||
// Read both of the error registers. It is possible that more
|
||
// than one error was reported simulataneously.
|
||
//
|
||
|
||
Edsr.all = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister );
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
|
||
|
||
|
||
//
|
||
// Read all of the relevant error address registers.
|
||
//
|
||
|
||
ErrorLowAddress = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister );
|
||
|
||
ErrorHighAddress = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister);
|
||
|
||
ErrorAddress = ((ULONG)(ErrorHighAddress) << 21) +
|
||
((ULONG)(ErrorLowAddress) << 5);
|
||
|
||
Sear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
|
||
|
||
SystemErrorAddress = (ULONG)(Sear) << 2;
|
||
|
||
Pear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister );
|
||
|
||
//
|
||
// Fill in the Apecs uncorrectbale frame
|
||
//
|
||
if(apecserr)
|
||
apecserr->ComancheEdsr = Edsr.all;
|
||
|
||
if( PUncorrectableError &&
|
||
( (Edsr.Bctaperr == 1) ||
|
||
(Edsr.Bctcperr == 1) ||
|
||
(Edsr.Nxmerr == 1) ) ) {
|
||
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
||
ErrorAddress;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
PhysicalAddressValid = 1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
||
MEMORY_SPACE;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
MemoryErrorSource = SYSTEM_MEMORY;
|
||
}
|
||
|
||
if(apecserr)
|
||
apecserr->EpicEcsr = Ecsr.all;
|
||
|
||
if( PUncorrectableError &&
|
||
( (Ecsr.Merr == 1) ||
|
||
(Ecsr.Umrd == 1) ) ) {
|
||
|
||
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
||
SystemErrorAddress;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
PhysicalAddressValid = 1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
||
MEMORY_SPACE;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
MemoryErrorSource = SYSTEM_MEMORY;
|
||
}
|
||
|
||
if( PUncorrectableError &&
|
||
( (Ecsr.Ndev == 1) ||
|
||
(Ecsr.Tabt == 1) ||
|
||
(Ecsr.Iope == 1) ||
|
||
(Ecsr.Ddpe == 1) ||
|
||
(Ecsr.Iptl == 1) ||
|
||
(Ecsr.Iort == 1) ) ){
|
||
|
||
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
|
||
Pear;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
PhysicalAddressValid = 1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
|
||
IO_SPACE;
|
||
PUncorrectableError->UncorrectableFrame.Flags.
|
||
MemoryErrorSource = 0;
|
||
}
|
||
|
||
if(apecserr){
|
||
apecserr->EpicPciErrAddr = Pear;
|
||
apecserr->EpicSysErrAddr = SystemErrorAddress;
|
||
apecserr->ComancheErrAddr = ErrorAddress;
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
HalpPlatformMachineCheck(
|
||
IN PEXCEPTION_RECORD ExceptionRecord,
|
||
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is given control when an hard error is acknowledged
|
||
by the APECS chipset. The routine is given the chance to
|
||
correct and dismiss the error.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to the exception record generated
|
||
at the point of the exception.
|
||
|
||
ExceptionFrame - Supplies a pointer to the exception frame generated
|
||
at the point of the exception.
|
||
|
||
TrapFrame - Supplies a pointer to the trap frame generated
|
||
at the point of the exception.
|
||
|
||
Return Value:
|
||
|
||
TRUE is returned if the machine check has been handled and dismissed -
|
||
indicating that execution can continue. FALSE is return otherwise.
|
||
|
||
--*/
|
||
{
|
||
COMANCHE_EDSR Edsr;
|
||
EPIC_ECSR Ecsr;
|
||
|
||
PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
|
||
|
||
//
|
||
// Check if there are any memory errors pending in the Comanche.
|
||
//
|
||
// A lost error, tag parity, tag control or non-existent memory
|
||
// error indicates a non-dismissable error.
|
||
//
|
||
|
||
HalpReadApecsErrorRegisters();
|
||
|
||
if(PUncorrectableError)
|
||
apecserr = (PAPECS_UNCORRECTABLE_FRAME)
|
||
PUncorrectableError->UncorrectableFrame.RawSystemInformation;
|
||
|
||
if(apecserr == NULL){
|
||
Edsr.all = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
|
||
ErrorAndDiagnosticStatusRegister );
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
|
||
EpicControlAndStatusRegister );
|
||
|
||
}
|
||
else {
|
||
|
||
Edsr.all = apecserr->ComancheEdsr;
|
||
|
||
Ecsr.all = apecserr->EpicEcsr;
|
||
}
|
||
|
||
if( (Edsr.Losterr == 1) ||
|
||
(Edsr.Bctaperr == 1) ||
|
||
(Edsr.Bctcperr == 1) ||
|
||
(Edsr.Nxmerr == 1) ){
|
||
|
||
goto FatalError;
|
||
|
||
}
|
||
|
||
//
|
||
// Check if there are any non-recoverable I/O errors.
|
||
//
|
||
// Memory errors, invalid page table lookups, uncorrectable
|
||
// memory errors, target aborts, io parity errors, dma parity
|
||
// errors, lost errors, and retry timeouts are all considered
|
||
// non-dismissable errors.
|
||
//
|
||
|
||
if( (Ecsr.Merr == 1) ||
|
||
(Ecsr.Iptl == 1) ||
|
||
(Ecsr.Umrd == 1) ||
|
||
(Ecsr.Tabt == 1) ||
|
||
(Ecsr.Iope == 1) ||
|
||
(Ecsr.Ddpe == 1) ||
|
||
(Ecsr.Iort == 1) ){
|
||
|
||
goto FatalError;
|
||
|
||
}
|
||
|
||
//
|
||
// A Pass1 APECS chip bug will erroneously report a lost operation,
|
||
// so, if a Pass1 chip, then ignore the error.
|
||
//
|
||
|
||
if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
|
||
goto FatalError;
|
||
}
|
||
|
||
//
|
||
// Check for a PCI configuration read error. An error is a
|
||
// candidate if the I/O controller has signalled a NoDevice error.
|
||
//
|
||
|
||
if( Ecsr.Ndev == 1 ){
|
||
|
||
//
|
||
// So far, the error looks like a PCI configuration space read
|
||
// that accessed a device that does not exist. In order to fix
|
||
// this up we expect that the faulting instruction or the instruction
|
||
// previous to the faulting instruction must be a load with v0 as
|
||
// the destination register. If this condition is met then simply
|
||
// update v0 in the register set and return. However, be careful
|
||
// not to re-execute the load.
|
||
//
|
||
// jnfix - add condition to check if Rb contains the superpage
|
||
// address for config space?
|
||
|
||
ALPHA_INSTRUCTION FaultingInstruction;
|
||
BOOLEAN PreviousInstruction = FALSE;
|
||
BOOLEAN WasLost = (Ecsr.Lost == 1 ? TRUE : FALSE);
|
||
|
||
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
|
||
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
|
||
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
|
||
|
||
//
|
||
// Faulting instruction did not match, try the previous
|
||
// instruction.
|
||
//
|
||
|
||
PreviousInstruction = TRUE;
|
||
|
||
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4);
|
||
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
|
||
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
|
||
|
||
//
|
||
// No match, we can't fix this up.
|
||
//
|
||
|
||
goto FatalError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The error has matched all of our conditions. Fix it up by
|
||
// writing the value 0xffffffff into the destination of the load.
|
||
//
|
||
|
||
TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
|
||
|
||
//
|
||
// If the faulting instruction was the load the restart execution
|
||
// at the instruction after the load.
|
||
//
|
||
|
||
if( PreviousInstruction == FALSE ){
|
||
TrapFrame->Fir += 4;
|
||
}
|
||
|
||
//
|
||
// Clear the error condition in the ECSR.
|
||
//
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister);
|
||
|
||
Ecsr.Ndev = 1;
|
||
Ecsr.Dcei = 1;
|
||
|
||
if (WasLost) {
|
||
Ecsr.Lost = 1;
|
||
}
|
||
|
||
WRITE_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
|
||
Ecsr.all );
|
||
|
||
return TRUE;
|
||
|
||
} //endif Ecsr.Ndev == 1
|
||
|
||
|
||
//
|
||
// Handle any ECC correctable errors.
|
||
//
|
||
|
||
if( Ecsr.Cmrd ) {
|
||
|
||
//
|
||
// Handle the error and then clear the error bit.
|
||
//
|
||
|
||
HalpApecsCorrectableError();
|
||
Ecsr.Cmrd = 0;
|
||
Ecsr.Lost = 0;
|
||
|
||
//
|
||
// If there are no other outstanding errors, then return.
|
||
//
|
||
|
||
if ( Ecsr.all )
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// A Pass1 APECS chip bug will erroneously report a lost operation,
|
||
// so, if a Pass1 chip, then ignore the error.
|
||
//
|
||
|
||
if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
|
||
goto FatalError;
|
||
}
|
||
|
||
//
|
||
// The system is not well and cannot continue reliable execution.
|
||
// Print some useful messages and return FALSE to indicate that the error
|
||
// was not handled.
|
||
//
|
||
|
||
FatalError:
|
||
|
||
if(PUncorrectableError) {
|
||
PUncorrectableError->UncorrectableFrame.Flags.SystemInformationValid =
|
||
1;
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"Uncorrectable Error From Apecs Chipset Detected");
|
||
}
|
||
|
||
HalpApecsReportFatalError();
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpApecsErrorInterrupt(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is entered as a result of an error interrupt on the
|
||
APECS chipset. This function determines if the error is fatal
|
||
or recoverable and if recoverable performs the recovery and
|
||
error logging.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
COMANCHE_EDSR Edsr;
|
||
EPIC_ECSR Ecsr;
|
||
PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
|
||
|
||
HalpReadApecsErrorRegisters();
|
||
|
||
if(PUncorrectableError)
|
||
apecserr = (PAPECS_UNCORRECTABLE_FRAME)
|
||
PUncorrectableError->UncorrectableFrame.RawSystemInformation;
|
||
|
||
if(apecserr == NULL){
|
||
Edsr.all = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
|
||
ErrorAndDiagnosticStatusRegister );
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
|
||
EpicControlAndStatusRegister );
|
||
|
||
}
|
||
else {
|
||
|
||
Edsr.all = apecserr->ComancheEdsr;
|
||
|
||
Ecsr.all = apecserr->EpicEcsr;
|
||
}
|
||
|
||
//
|
||
// Any error from the COMANCHE represents a fatal condition.
|
||
//
|
||
|
||
if( (Edsr.Losterr == 1) ||
|
||
(Edsr.Bctaperr == 1) ||
|
||
(Edsr.Bctcperr == 1) ||
|
||
(Edsr.Nxmerr == 1) ){
|
||
|
||
goto FatalErrorInterrupt;
|
||
|
||
}
|
||
|
||
//
|
||
// Almost any error from the EPIC is also fatal. The only exception
|
||
// is the correctable memory read error. Any other error is fatal.
|
||
//
|
||
|
||
if( (Ecsr.Merr == 1) ||
|
||
(Ecsr.Iptl == 1) ||
|
||
(Ecsr.Umrd == 1) ||
|
||
(Ecsr.Tabt == 1) ||
|
||
(Ecsr.Ndev == 1) ||
|
||
(Ecsr.Iope == 1) ||
|
||
(Ecsr.Ddpe == 1) ||
|
||
(Ecsr.Iort == 1) ){
|
||
|
||
goto FatalErrorInterrupt;
|
||
|
||
}
|
||
|
||
//
|
||
// A Pass1 APECS chip bug will erroneously report a lost operation,
|
||
// so, if a Pass1 chip, then ignore the error.
|
||
//
|
||
|
||
if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
|
||
goto FatalErrorInterrupt;
|
||
}
|
||
|
||
//
|
||
// The error may be correctable. If the correctable error bit is
|
||
// set in the ECSR then log the error and clear the condition.
|
||
//
|
||
|
||
if( Ecsr.Cmrd == 1 ){
|
||
|
||
ULONG Sear;
|
||
ULONGLONG SystemErrorAddress;
|
||
|
||
CorrectedMemoryReads += 1;
|
||
|
||
Sear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
|
||
|
||
SystemErrorAddress = (ULONGLONG)(Sear) << 2;
|
||
|
||
//jnfix - temporary debug logging only
|
||
#if (DBG) || (HALDBG)
|
||
|
||
if( (CorrectedMemoryReads % 32) == 0 ){
|
||
DbgPrint( "APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n",
|
||
CorrectedMemoryReads,
|
||
SystemErrorAddress );
|
||
}
|
||
|
||
#endif //DBG || HALDBG
|
||
|
||
//
|
||
// Clear the error condition.
|
||
//
|
||
|
||
WRITE_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
|
||
Ecsr.all
|
||
);
|
||
|
||
return;
|
||
|
||
} //endif Ecsr.Cmrd == 1
|
||
|
||
//
|
||
// The interrupt indicates a fatal system error.
|
||
// Display information about the error and shutdown the machine.
|
||
//
|
||
|
||
FatalErrorInterrupt:
|
||
|
||
HalpApecsReportFatalError();
|
||
|
||
//jnfix - add some of the address registers?
|
||
//
|
||
// Add the address of the error frame as 4th parameter.
|
||
//
|
||
KeBugCheckEx( DATA_BUS_ERROR,
|
||
Edsr.all,
|
||
Ecsr.all,
|
||
0,
|
||
(ULONG)PUncorrectableError );
|
||
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpApecsReportFatalError(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reports and interprets a fatal hardware error on
|
||
the APECS chipset. The COMANCHE Error and Diagnostic Status Register
|
||
and the EPIC Error and Status Register are read to determine how
|
||
to interpret the error.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
COMANCHE_EDSR Edsr;
|
||
EPIC_ECSR Ecsr;
|
||
ULONGLONG ErrorAddress;
|
||
ULONG ErrorHighAddress;
|
||
ULONG ErrorLowAddress;
|
||
ULONG Pear;
|
||
ULONG Sear;
|
||
ULONGLONG SystemErrorAddress;
|
||
UCHAR OutBuffer[MAX_ERROR_STRING];
|
||
PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
|
||
PEXTENDED_ERROR PExtErr = NULL;
|
||
|
||
//
|
||
// Begin the error output by acquiring ownership of the display
|
||
// and printing the dreaded banner.
|
||
//
|
||
|
||
HalAcquireDisplayOwnership(NULL);
|
||
|
||
HalDisplayString( "\nFatal system hardware error.\n\n" );
|
||
|
||
//
|
||
// Extract register values to report from Error Frame.
|
||
//
|
||
if(PUncorrectableError){
|
||
apecserr = (PAPECS_UNCORRECTABLE_FRAME)
|
||
PUncorrectableError->UncorrectableFrame.RawSystemInformation;
|
||
PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
|
||
}
|
||
|
||
if(apecserr == NULL){
|
||
Edsr.all = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
|
||
ErrorAndDiagnosticStatusRegister );
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
|
||
EpicControlAndStatusRegister );
|
||
|
||
ErrorLowAddress = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister );
|
||
|
||
ErrorHighAddress = READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister);
|
||
|
||
ErrorAddress = ((ULONGLONG)(ErrorHighAddress) << 21) +
|
||
((ULONGLONG)(ErrorLowAddress) << 5);
|
||
|
||
Sear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
|
||
|
||
SystemErrorAddress = (ULONGLONG)(Sear) << 2;
|
||
|
||
Pear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister );
|
||
|
||
}
|
||
else {
|
||
|
||
Edsr.all = apecserr->ComancheEdsr;
|
||
|
||
Ecsr.all = apecserr->EpicEcsr;
|
||
|
||
Pear = apecserr->EpicPciErrAddr;
|
||
SystemErrorAddress = apecserr->EpicSysErrAddr;
|
||
ErrorAddress = apecserr->ComancheErrAddr;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Interpret any errors from the COMANCHE EDSR.
|
||
//
|
||
|
||
sprintf( OutBuffer, "Comanche EDSR = 0x%x\n", Edsr.all );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
if( Edsr.Bctaperr == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"B-Cache Tag Address Parity Error");
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
|
||
SYSTEM_CACHE;
|
||
//
|
||
// At present the HalpSimm routine doesn't do anything
|
||
// it expected to be fixed in the near future.
|
||
//
|
||
PExtErr->CacheError.Flags.CacheSimmValid = 1;
|
||
PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress);
|
||
HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo);
|
||
if( Edsr.Dmacause == 1 ){
|
||
PExtErr->CacheError.TransferType = BUS_DMA_OP;
|
||
}
|
||
if( Edsr.Viccause == 1 ){
|
||
PExtErr->CacheError.TransferType = VICTIM_WRITE;
|
||
}
|
||
|
||
}
|
||
|
||
sprintf( OutBuffer,
|
||
"Bcache Tag Address Parity Error, Address: %Lx, SIMM = %d\n",
|
||
ErrorAddress, HalpSimm(ErrorAddress) );
|
||
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Edsr.Bctcperr == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"B-Cache Tag Control Parity Error");
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
|
||
SYSTEM_CACHE;
|
||
//
|
||
// At present the HalpSimm routine doesn't do anything
|
||
// it is expected to be fixed in the near future.
|
||
//
|
||
PExtErr->CacheError.Flags.CacheSimmValid = 1;
|
||
PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress);
|
||
HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo);
|
||
if( Edsr.Dmacause == 1 ){
|
||
PExtErr->CacheError.TransferType = BUS_DMA_OP;
|
||
}
|
||
if( Edsr.Viccause == 1 ){
|
||
PExtErr->CacheError.TransferType = VICTIM_WRITE;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
sprintf( OutBuffer,
|
||
"Bcache Tag Control Parity Error, Address: %Lx, SIMM = %d\n",
|
||
ErrorAddress, HalpSimm(ErrorAddress) );
|
||
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Edsr.Nxmerr == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"Non-existent memory error");
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
|
||
SYSTEM_MEMORY;
|
||
//
|
||
// At present the HalpSimm routine doesn't do anything
|
||
// it expected to be fixed in the near future.
|
||
//
|
||
PExtErr->MemoryError.Flags.MemorySimmValid = 1;
|
||
PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress);
|
||
HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo);
|
||
if( Edsr.Dmacause == 1 ){
|
||
PExtErr->MemoryError.TransferType = BUS_DMA_OP;
|
||
}
|
||
if( Edsr.Viccause == 1 ){
|
||
PExtErr->MemoryError.TransferType = VICTIM_WRITE;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
sprintf( OutBuffer,
|
||
"Non-existent memory error, Address: %Lx\n",
|
||
ErrorAddress );
|
||
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( (Edsr.Bctaperr == 1) || (Edsr.Bctcperr == 1) ||
|
||
(Edsr.Nxmerr == 1) ){
|
||
|
||
if( Edsr.Dmacause == 1 ){
|
||
HalDisplayString( "Error caused on DMA.\n" );
|
||
}
|
||
|
||
if( Edsr.Viccause == 1 ){
|
||
HalDisplayString( "Victim write caused error.\n" );
|
||
}
|
||
|
||
}
|
||
|
||
if( Edsr.Losterr == 1 ){
|
||
HalDisplayString( "Multiple Cache/Memory errors.\n" );
|
||
}
|
||
|
||
//
|
||
// Interpret any errors from the EPIC Ecsr.
|
||
//
|
||
|
||
sprintf( OutBuffer, "EPIC ECSR = 0x%lx\n", Ecsr.all );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
if( Ecsr.Iort == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"PCI Retry timeout error");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
|
||
sprintf( OutBuffer,
|
||
"PCI Retry timeout error, PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Ddpe == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"DMA Data Parity Error");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"DMA Data Parity Error at PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Iope == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"I/O Data Parity Error");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"I/O Data Parity Error at PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Tabt == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"Target Abort Error");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"Target Abort Error at PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Ndev == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"No Device Error");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"No Device Error at PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Iptl == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"Invalid Page Table Lookup");
|
||
PExtErr->IoError.Interface = PCIBus;
|
||
|
||
//
|
||
// Since APECS supports only one PCI Bus we will simply set
|
||
// the busnumber to 0.
|
||
//
|
||
PExtErr->IoError.BusNumber = 0;
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"Invalid Page Table Lookup at PCI Address: 0x%x\n",
|
||
Pear );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Umrd == 1 ){
|
||
|
||
if(PExtErr){
|
||
PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
|
||
1;
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
|
||
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
|
||
"memory read error");
|
||
|
||
PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
|
||
SYSTEM_MEMORY;
|
||
//
|
||
// At present the HalpSimm routine doesn't do anything
|
||
// it expected to be fixed in the near future.
|
||
//
|
||
PExtErr->MemoryError.Flags.MemorySimmValid = 1;
|
||
PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress);
|
||
HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo);
|
||
|
||
|
||
}
|
||
sprintf( OutBuffer,
|
||
"Uncorrectable memory read error, System Address: 0x%Lx\n",
|
||
SystemErrorAddress );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
|
||
if( Ecsr.Merr == 1 ){
|
||
|
||
sprintf( OutBuffer,
|
||
"Memory error, System Address: 0x%Lx\n",
|
||
SystemErrorAddress );
|
||
HalDisplayString( OutBuffer );
|
||
|
||
}
|
||
|
||
if( Ecsr.Lost == 1 ){
|
||
HalDisplayString( "Multiple I/O errors detected.\n" );
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
ULONG
|
||
HalpSimm(
|
||
ULONGLONG Address
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return the number of the SIMM corresponding to the supplied physical
|
||
address.
|
||
|
||
Arguments:
|
||
|
||
Address - Supplies the physical address of a byte in memory.
|
||
|
||
Return Value:
|
||
|
||
The number of the SIMM that contains the byte of physical memory is
|
||
returned. If the Address does not fit within a SIMM or the SIMM number
|
||
cannot be determined 0xffffffff is returned.
|
||
|
||
--*/
|
||
{
|
||
|
||
//jnfix - see if this can be determined exclusively from memory registers
|
||
//jnfix - or is this platform-dependent
|
||
|
||
return( 0xffffffff );
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpApecsCorrectableError(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handle ECC correctable errors from the APECS.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
static ERROR_FRAME Frame;
|
||
static APECS_CORRECTABLE_FRAME ApecsFrame;
|
||
|
||
ERROR_FRAME TempFrame;
|
||
PCORRECTABLE_ERROR CorrPtr;
|
||
PBOOLEAN ErrorlogBusy;
|
||
PULONG DispatchCode;
|
||
PKINTERRUPT InterruptObject;
|
||
PKSPIN_LOCK ErrorlogSpinLock;
|
||
EPIC_ECSR Ecsr;
|
||
ULONG Sear;
|
||
ULONGLONG SystemErrorAddress;
|
||
|
||
//
|
||
// Read the Epic control and status register.
|
||
//
|
||
|
||
Ecsr.all = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
|
||
|
||
//
|
||
// Get the system address. Note, bits 2-4 of the address not available.
|
||
//
|
||
|
||
Sear = READ_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
|
||
|
||
SystemErrorAddress = (ULONGLONG)Sear << 2;
|
||
|
||
#if (DBG) || (HALDBG)
|
||
|
||
if( (CorrectedMemoryReads % 32) == 0 ){
|
||
DbgPrint("APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n",
|
||
CorrectedMemoryReads,
|
||
SystemErrorAddress );
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Get the interrupt object.
|
||
//
|
||
|
||
DispatchCode = (PULONG)(PCR->InterruptRoutine[CORRECTABLE_VECTOR]);
|
||
InterruptObject = CONTAINING_RECORD(DispatchCode,
|
||
KINTERRUPT,
|
||
DispatchCode);
|
||
|
||
//
|
||
// Set various pointers so we can use them later.
|
||
//
|
||
|
||
CorrPtr = &TempFrame.CorrectableFrame;
|
||
ErrorlogBusy = (PBOOLEAN)((PUCHAR)InterruptObject->ServiceContext +
|
||
sizeof(PERROR_FRAME));
|
||
ErrorlogSpinLock = (PKSPIN_LOCK)((PUCHAR)ErrorlogBusy + sizeof(PBOOLEAN));
|
||
|
||
//
|
||
// Update the number of correctable errors.
|
||
//
|
||
|
||
CorrectedMemoryReads += 1;
|
||
|
||
//
|
||
// Clear the data structures that we will use.
|
||
//
|
||
|
||
RtlZeroMemory(&TempFrame, sizeof(ERROR_FRAME));
|
||
|
||
//
|
||
// Fill in the error frame information.
|
||
//
|
||
|
||
TempFrame.Signature = ERROR_FRAME_SIGNATURE;
|
||
TempFrame.FrameType = CorrectableFrame;
|
||
TempFrame.VersionNumber = ERROR_FRAME_VERSION;
|
||
TempFrame.SequenceNumber = CorrectedMemoryReads;
|
||
TempFrame.PerformanceCounterValue =
|
||
KeQueryPerformanceCounter(NULL).QuadPart;
|
||
|
||
//
|
||
// Check for lost error.
|
||
//
|
||
|
||
if( Ecsr.Lost ) {
|
||
|
||
//
|
||
// Since the error registers are locked from a previous error,
|
||
// we don't know where the error came from. Mark everything
|
||
// as UNIDENTIFIED.
|
||
//
|
||
|
||
CorrPtr->Flags.LostCorrectable = 1;
|
||
CorrPtr->Flags.LostAddressSpace = UNIDENTIFIED;
|
||
CorrPtr->Flags.LostMemoryErrorSource = UNIDENTIFIED;
|
||
}
|
||
|
||
//
|
||
// Either a DMA read or DMA TLB read ECC error. We can't tell
|
||
// since the EPIC chip doesn't provid enough information. Just
|
||
// log everything as a DMA ECC error.
|
||
//
|
||
|
||
CorrPtr->Flags.AddressSpace = MEMORY_SPACE;
|
||
CorrPtr->Flags.ExtendedErrorValid = 1;
|
||
CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY;
|
||
CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_READ;
|
||
|
||
//
|
||
// Get the physical address where the error occurred.
|
||
//
|
||
|
||
CorrPtr->Flags.PhysicalAddressValid = 1;
|
||
CorrPtr->PhysicalAddress = SystemErrorAddress;
|
||
|
||
//
|
||
// Scrub the error if it's any type of memory error.
|
||
//
|
||
|
||
if (CorrPtr->Flags.AddressSpace == MEMORY_SPACE &&
|
||
CorrPtr->Flags.PhysicalAddressValid )
|
||
CorrPtr->Flags.ScrubError = 1;
|
||
|
||
//
|
||
// Acquire the spinlock.
|
||
//
|
||
|
||
KiAcquireSpinLock(ErrorlogSpinLock);
|
||
|
||
//
|
||
// Check to see if an errorlog operation is in progress already.
|
||
//
|
||
|
||
if (!*ErrorlogBusy) {
|
||
|
||
//
|
||
// The error is expected to be a corrected ECC error on a DMA or
|
||
// Scatter/Gather TLB read. Read the error registers relevant
|
||
// to this error.
|
||
//
|
||
|
||
ApecsFrame.EpicEcsr = Ecsr.all;
|
||
|
||
ApecsFrame.EpicSysErrAddr = Sear;
|
||
|
||
//
|
||
// Read the CIA configuration registers for logging information.
|
||
//
|
||
|
||
ApecsFrame.Configuration.ApecsRev = Ecsr.Pass2;
|
||
HalpApecsConfig( &ApecsFrame.Configuration );
|
||
|
||
//
|
||
// Set the raw system information.
|
||
//
|
||
|
||
CorrPtr->RawSystemInformationLength = sizeof(APECS_CORRECTABLE_FRAME);
|
||
CorrPtr->RawSystemInformation = &ApecsFrame;
|
||
|
||
//
|
||
// Set the raw processor information. Disregard at the moment.
|
||
//
|
||
|
||
CorrPtr->RawProcessorInformationLength = 0;
|
||
|
||
//
|
||
// Set reporting processor information. Disregard at the moment.
|
||
//
|
||
|
||
CorrPtr->Flags.ProcessorInformationValid = 0;
|
||
|
||
//
|
||
// Set system information. Disregard at the moment.
|
||
//
|
||
|
||
CorrPtr->Flags.SystemInformationValid = 0;
|
||
|
||
//
|
||
// Copy the information that we need to log.
|
||
//
|
||
|
||
RtlCopyMemory(&Frame,
|
||
&TempFrame,
|
||
sizeof(ERROR_FRAME));
|
||
|
||
//
|
||
// Put frame into ISR service context.
|
||
//
|
||
|
||
*(PERROR_FRAME *)InterruptObject->ServiceContext = &Frame;
|
||
|
||
} else {
|
||
|
||
//
|
||
// An errorlog operation is in progress already. We will
|
||
// set various lost bits and then get out without doing
|
||
// an actual errorloging call.
|
||
//
|
||
|
||
Frame.CorrectableFrame.Flags.LostCorrectable = TRUE;
|
||
Frame.CorrectableFrame.Flags.LostAddressSpace =
|
||
TempFrame.CorrectableFrame.Flags.AddressSpace;
|
||
Frame.CorrectableFrame.Flags.LostMemoryErrorSource =
|
||
TempFrame.CorrectableFrame.Flags.MemoryErrorSource;
|
||
}
|
||
|
||
//
|
||
// Release the spinlock.
|
||
//
|
||
|
||
KiReleaseSpinLock(ErrorlogSpinLock);
|
||
|
||
//
|
||
// Dispatch to the secondary correctable interrupt service routine.
|
||
// The assumption here is that if this interrupt ever happens, then
|
||
// some driver enabled it, and the driver should have the ISR connected.
|
||
//
|
||
|
||
((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
|
||
InterruptObject,
|
||
InterruptObject->ServiceContext);
|
||
|
||
//
|
||
// Clear lost and correctable error bit.
|
||
//
|
||
|
||
if (Ecsr.Lost) {
|
||
|
||
Ecsr.all = 0;
|
||
Ecsr.Cmrd = 1;
|
||
Ecsr.Lost = 1;
|
||
|
||
} else {
|
||
|
||
Ecsr.all = 0;
|
||
Ecsr.Cmrd = 1;
|
||
}
|
||
|
||
WRITE_EPIC_REGISTER(
|
||
&((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
|
||
Ecsr.all);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpApecsConfig(
|
||
PAPECS_CONFIGURATION Config
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads in the configuration registers from the Comanche chip.
|
||
|
||
Arguments:
|
||
|
||
Pointer to the configuration frame.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Read in all the registers.
|
||
//
|
||
|
||
Config->CGcr =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GeneralControlRegister
|
||
);
|
||
|
||
Config->CTer =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->TagEnableRegister
|
||
);
|
||
|
||
Config->CGtr =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GlobalTimingRegister
|
||
);
|
||
|
||
Config->CRtr =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->RefreshTimingRegister
|
||
);
|
||
|
||
Config->CBank0 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank0ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank1 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank1ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank2 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank2ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank3 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank3ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank4 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank4ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank5 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank5ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank6 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank6ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank7 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank7ConfigurationRegister
|
||
);
|
||
|
||
Config->CBank8 =
|
||
READ_COMANCHE_REGISTER(
|
||
&((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank8ConfigurationRegister
|
||
);
|
||
}
|