/*++ Copyright (C) 1990-1995 Microsoft Corporation Copyright (C) 1994,1995 MOTOROLA, INC. All Rights Reserved. This file contains copyrighted material. Use of this file is restricted by the provisions of a Motorola Software License Agreement. Module Name: pxmemctl.c Abstract: The module initializes any planar registers. This module also implements machince check parity error handling. --*/ #include "halp.h" #include "pxmemctl.h" #include "pxdakota.h" #include "arccodes.h" VOID HalDisplayString(PUCHAR String); ULONG HalpGetHID0(VOID); VOID HalpSetHID0(ULONG Value); BOOLEAN HalpStrCmp( char *, char *); VOID HalpEnableL2Cache(VOID); ULONG HalpSizeL2Cache(VOID); extern ULONG HalpSizeL2(VOID); BOOLEAN HalpInitPlanar(VOID); BOOLEAN HalpMapPlanarSpace(VOID); VOID HalpFlushAndEnableL2(VOID); VOID HalpFlushAndDisableL2(VOID); VOID HalpEnableBridgeSettings(VOID); VOID HalpEnable_HID0_Settings(VOID); VOID HalpCheckHardwareRevisionLevels(VOID); VOID HalpDumpHardwareState(VOID); #define PCI_CONFIG_PHYSICAL_BASE 0x80800000 // physical base of PCI config space #define PCI_CONFIG_SIZE 0x00800000 #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,HalpStrCmp) #pragma alloc_text(INIT,HalpInitPlanar) #pragma alloc_text(INIT,HalpMapPlanarSpace) #pragma alloc_text(INIT,HalpEnableL2Cache) #pragma alloc_text(INIT,HalpSizeL2Cache) #pragma alloc_text(INIT,HalpEnableBridgeSettings) #pragma alloc_text(INIT,HalpEnable_HID0_Settings) #pragma alloc_text(INIT,HalpCheckHardwareRevisionLevels) #endif #define NEGATECHAR '~' #define BridgeIndexRegister ((PULONG) (((PUCHAR) HalpIoControlBase) + 0xcf8)) #define BridgeDataRegister (((ULONG) HalpIoControlBase) + 0xcfc) #define HalpReadBridgeUlong(Port) \ (*BridgeIndexRegister = (Port), __builtin_eieio(), *((PULONG) BridgeDataRegister)) #define HalpWriteBridgeUlong(Port, Value) \ (*BridgeIndexRegister = (Port), *((PULONG) BridgeDataRegister) = (Value), __builtin_sync()) #define HalpReadBridgeUshort(Port) \ (*BridgeIndexRegister = (Port), __builtin_eieio(), *((PUSHORT)(BridgeDataRegister+(Port&0x2)))) #define HalpWriteBridgeUshort(Port, Value) \ (*BridgeIndexRegister = (Port), *((PUSHORT)(BridgeDataRegister+(Port&0x2))) = (Value), __builtin_sync()) #define HalpReadBridgeUchar(Port) \ (*BridgeIndexRegister = (Port), __builtin_eieio(), *((PUCHAR)(BridgeDataRegister+(Port&0x3)))) #define HalpWriteBridgeUchar(Port, Value) \ (*BridgeIndexRegister = (Port), *((PUCHAR)(BridgeDataRegister+(Port&0x3))) = (Value), __builtin_sync()) #define HalpDisplayHex32(Num, Buf) HalpDisplayHex( 32, Num, Buf) #define HalpDisplayHex16(Num, Buf) HalpDisplayHex( 16, Num, Buf) #define HalpDisplayHex8(Num, Buf) HalpDisplayHex( 8, Num, Buf) VOID HalpDisplayHex( ULONG NoBits, ULONG Number, IN PUCHAR Buffer ) { int Bits; for (Bits=NoBits-4; Bits >= 0; Bits -=4) { *Buffer++ = (UCHAR) ((((Number >> Bits) & 0xF) > 9) ? ((Number >> Bits) & 0xF) - 10 + 'A' : ((Number >> Bits) & 0xF) + '0'); } *Buffer++ = '.'; *Buffer++ = '\n'; *Buffer++ = '\0'; } UCHAR HalpUpperCase(UCHAR c) { if (c >= 'a' && c <= 'z') c -= 'a'-'A'; return c; } // // Routine Description: // // This routine is a helper routine for parameter parsing. // It compares UpperCase of String1 to UpperCase of String2. // // Return Value // // TRUE if strings match; otherwise FALSE // BOOLEAN HalpStrCmp( char *String0, char *String1 ) { char *tmp0, *tmp1; tmp0 = String0; tmp1 = String1; while( (*tmp0 = toupper( *tmp0 )) && (*tmp1 = toupper( *tmp1 )) ) { tmp0++; tmp1++; } return( strcmp(String0, String1) == 0 ); } // Oem Output Display function filter noise if OEM or quite VOID OemDisplayString ( PUCHAR String ) { #define BUF_LEN 120 UCHAR CharBuffer[BUF_LEN]; if(HalGetEnvironmentVariable("HALREPORT",sizeof(CharBuffer),&CharBuffer[0]) == ESUCCESS) { if(HalpStrCmp("YES", CharBuffer)) { HalDisplayString(String); } } else { if(HalGetEnvironmentVariable("MOT-OEM-ID",sizeof(CharBuffer),&CharBuffer[0]) != ESUCCESS) { HalDisplayString(String); } } } BOOLEAN HalpInitPlanar ( VOID ) { USHORT CpuRevision, CpuType; UCHAR BridgeRevision, c; UCHAR CharBuffer[20], i; OemDisplayString("\nHAL: Motorola PowerStack 2 Systems."); OemDisplayString("\nHAL: Version 2.37 5/24/96."); CpuType = (USHORT)(HalpGetProcessorVersion() >> 16); CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); OemDisplayString("\nHAL: Processor is a 6"); i = 0; switch (CpuType) { case 1: case 3: case 4: CharBuffer[i++] = '0'; CharBuffer[i++] = (UCHAR)(CpuType) + '0'; break; case 6: CharBuffer[i++] = '0'; CharBuffer[i++] = '3'; CharBuffer[i++] = 'e'; break; case 7: CharBuffer[i++] = '0'; CharBuffer[i++] = '3'; CharBuffer[i++] = 'e'; CharBuffer[i++] = 'v'; break; case 9: CharBuffer[i++] = '0'; CharBuffer[i++] = '4'; CharBuffer[i++] = 'e'; CharBuffer[i++] = 'v'; break; case 20: CharBuffer[i++] = '2'; CharBuffer[i++] = '0'; break; default: CharBuffer[i++] = '?'; CharBuffer[i++] = '?'; break; } CharBuffer[i] = '\0'; OemDisplayString(CharBuffer); OemDisplayString(" revision "); i = 0; c = (UCHAR)((CpuRevision >> 8) & 0xf); CharBuffer[i++] = c + '0'; CharBuffer[i++] = '.'; if (c = (UCHAR)((CpuRevision >> 4) & 0xf)) CharBuffer[i++] = c + '0'; c = (UCHAR)(CpuRevision & 0xf); CharBuffer[i++] = c + '0'; CharBuffer[i++] = '.'; CharBuffer[i] = '\0'; OemDisplayString(CharBuffer); OemDisplayString("\nHAL: Bridge 27-82660 revision "); BridgeRevision = HalpReadBridgeUchar(0x80000008); i = 0; CharBuffer[i++] = (UCHAR) (BridgeRevision >> 4) + '0'; CharBuffer[i++] = '.'; CharBuffer[i++] = (UCHAR) (BridgeRevision & 0x0F) + '0'; CharBuffer[i++] = '.'; CharBuffer[i++] = '\n'; CharBuffer[i] = '\0'; OemDisplayString(CharBuffer); return TRUE; } char * MyStrtok ( char * string, const char * control ) { unsigned char *str; const unsigned char *ctrl = control; unsigned char map[32]; int count; static char *nextoken; /* Clear control map */ for (count = 0; count < 32; count++) map[count] = 0; /* Set bits in delimiter table */ do { map[*ctrl >> 3] |= (1 << (*ctrl & 7)); } while (*ctrl++); /* Initialize str. If string is NULL, set str to the saved * pointer (i.e., continue breaking tokens out of the string * from the last strtok call) */ if (string) str = string; else str = nextoken; /* Find beginning of token (skip over leading delimiters). Note that * there is no token iff this loop sets str to point to the terminal * null (*str == '\0') */ while ( (map[*str >> 3] & (1 << (*str & 7))) && *str ) str++; string = str; /* Find the end of the token. If it is not the end of the string, * put a null there. */ for ( ; *str ; str++ ) if ( map[*str >> 3] & (1 << (*str & 7)) ) { *str++ = '\0'; break; } /* Update nextoken (or the corresponding field in the per-thread data * structure */ nextoken = str; /* Determine if a token has been found. */ if ( string == str ) return NULL; else return string; } VOID HalpEnableBridgeSettings( VOID ) { UCHAR CharBuffer[BUF_LEN], *Value; BOOLEAN Negate; ULONG StatusRegister; volatile ULONG ErrorAddress; #define SetBridgeUchar( Clear, Offset, Val ) \ SetBridgeReg(Clear, Offset, Val, HalpReadBridgeUchar, HalpWriteBridgeUchar); #define SetBridgeUshort( Clear, Offset, Val ) \ SetBridgeReg(Clear, Offset, Val, HalpReadBridgeUshort, HalpWriteBridgeUshort); #define SetBridgeUlong( Clear, Offset, Val ) \ SetBridgeReg(Clear, Offset, Val, HalpReadBridgeUlong, HalpWriteBridgeUlong); #define SetBridgeReg( Clear, Offset, Val, GetReg, SetReg) \ { \ if (Clear) { \ SetReg(Offset, GetReg(Offset) & ~Val); \ } else { \ SetReg(Offset, GetReg(Offset) | Val); \ } \ } // // MOTKJR - Errata 19 from the Errata Summary Revision 1.3 says: // The error handling logic incorrectly detects EIEIO as a CPU transfer type error. // Always mask CPU transfer type errors (Error Enable 1 bit 0). // StatusRegister = HalpReadBridgeUchar(0x800000C0); // Clear CPU Transfer type error enable bit. HalpWriteBridgeUchar(0x800000C0, ~0x01 & (UCHAR)(StatusRegister)); // // The environment variable "BRIDGESETTINGS" is defined as: // Matching a string serves to enable that feature while a tilde (~) // immediately before the parameter string indicates that it is to be disabled. // if ((HalGetEnvironmentVariable("BRIDGESETTINGS", BUF_LEN, &CharBuffer[0]) == ESUCCESS) || (HalGetEnvironmentVariable("EAGLESETTINGS", BUF_LEN, &CharBuffer[0]) == ESUCCESS)) { for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, " :;,") ) { Negate = FALSE; if (*Value == NEGATECHAR) { Value++; Negate = TRUE; } if (HalpStrCmp("PCI_PARITY", Value)) { SetBridgeUshort( Negate, 0x80000004, 0x0040 ); } else if (HalpStrCmp("SERR", Value)) { SetBridgeUshort( Negate, 0x80000004, 0x0140 ); } else if (HalpStrCmp("MCP_EN", Value) || HalpStrCmp("MCP", Value)) { SetBridgeUchar( Negate, 0x800000BA, 0x01 ); } else if (HalpStrCmp("TEA_EN", Value) || HalpStrCmp("TEA", Value)) { SetBridgeUchar( Negate, 0x800000BA, 0x02 ); } else if (HalpStrCmp("PCI_ISA_IO_MAPPING", Value)) { SetBridgeUchar( Negate, 0x800000BA, 0x04 ); } else if (HalpStrCmp("POWER_MANAGEMENT", Value)) { SetBridgeUchar( Negate, 0x800000BB, 0x02 ); } else if (HalpStrCmp("CPU_TRANSFER_TYPE", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x01 ); } else if (HalpStrCmp("PARITY", Value) || HalpStrCmp("MEMORY", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x04 ); } else if (HalpStrCmp("SINGLE_BIT_ECC", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x04 ); } else if (HalpStrCmp("MULTI_BIT_ECC", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x08 ); } else if (HalpStrCmp("SELECT", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x20 ); } else if (HalpStrCmp("SERR_WHEN_PERR", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x40 ); } else if (HalpStrCmp("TARGET_ABORT", Value)) { SetBridgeUchar( Negate, 0x800000C0, 0x80 ); } else if (HalpStrCmp("CPU_DATA_BUS_PARITY", Value)) { SetBridgeUchar( Negate, 0x800000C4, 0x04 ); } else if (HalpStrCmp("L2_PARITY", Value) || HalpStrCmp("L2", Value)) { SetBridgeUchar( Negate, 0x800000C4, 0x08 ); } else if (HalpStrCmp("MASTER_ABORT", Value)) { SetBridgeUchar( Negate, 0x800000C4, 0x10 ); } else if (HalpStrCmp("ECC", Value) || HalpStrCmp("MEMORY_ERROR_CHECKING", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x01 ); SetBridgeUchar( Negate, 0x800000C0, 0x08 ); } else if (HalpStrCmp("MEMORY_DRAM", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x04 ); } else if (HalpStrCmp("L2_SRAM", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x08 ); } else if (HalpStrCmp("MCP_MODE", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x10 ); } else if (HalpStrCmp("EXTERNAL_REGISTER", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x20 ); } else if (HalpStrCmp("BROADCAST_SNOOP", Value)) { SetBridgeUchar( Negate, 0x800000D4, 0x80 ); } else { HalDisplayString("HAL: Error in BRIDGESETTINGS environment variable: "); HalDisplayString(CharBuffer); HalDisplayString("\n"); } } // End for } // End If // // Clear the error address register and L2 Cache Error register. // ErrorAddress = READ_PORT_ULONG(HalpErrorAddressRegister); StatusRegister = READ_PORT_UCHAR(&((PDAKOTA_CONTROL) HalpIoControlBase)->L2CacheErrorClear); HalpWriteBridgeUchar(0x800000C1, 0xFF); // Clear Error Detection Register 1. HalpWriteBridgeUchar(0x800000C5, 0xFF); // Clear Error Detection Register 2. StatusRegister = HalpReadBridgeUshort(0x80000006); // Get any Un-documented Status bits. HalpWriteBridgeUshort(0x80000006, 0xF900 | (USHORT)(StatusRegister)); // Clear Device Status Register. // // Initialize the PowerPC HID0 register here, // before we clear the detection bits in the Kauai/Lanai. // Otherwise we can miss the MCP pin signal transition. // HalpEnable_HID0_Settings(); // Setup HID0 register. } ULONG HalpSizeL2Cache( VOID ) { return (HalpSizeL2()); } VOID HalpEnableL2Cache( VOID ) { BOOLEAN Negate; int i; UCHAR CharBuffer[BUF_LEN], *Value; UCHAR L2_Parameter[BUF_LEN]; UCHAR ControlByte; // // Parse the environment variable "L2" // if (HalGetEnvironmentVariable("L2", BUF_LEN, &CharBuffer[0]) == ESUCCESS) { // Copy L2 environment variable i = 0; while (L2_Parameter[i] = CharBuffer[i]) { i++; } for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, " :;,") ) { if (*Value == NEGATECHAR) { Value++; Negate = TRUE; } else Negate = FALSE; // Check for L2 = "OFF" if (HalpStrCmp( "OFF", Value )) { OemDisplayString("HAL: L2 cache is disabled via environment variable L2\n"); HalpFlushAndDisableL2(); PCR->SecondLevelDcacheSize = PCR->SecondLevelIcacheSize = 0; return; } // Check for WriteThrough else if ( HalpStrCmp( "WT", Value ) || HalpStrCmp( "ON", Value )) { if (Negate) { Value--; goto ParseError; } // // Enable L2 cache on Kauai / Lanai. // HalpFlushAndEnableL2(); } else { ParseError: HalDisplayString("HAL: Error in L2 environment variable: "); HalDisplayString(L2_Parameter); HalDisplayString("\n illegal parameter begins here "); for (i = 0; i < Value - CharBuffer; i++) HalDisplayString("\304"); HalDisplayString("^\n"); break; } } // End for } // End If return; } VOID HalpEnable_HID0_Settings( VOID ) { USHORT CpuRevision, CpuType; UCHAR CharBuffer[BUF_LEN], *Value; ULONG HidEnable, HidDisable, CurrentHID0; BOOLEAN Negate; #define HID_MCP (0x80000000) #define HID_CACHE (0x40000000) #define HID_ADDRESS (0x20000000) #define HID_DATA (0x10000000) #define HID_PAR (0x01000000) #define HID_DPM (0x00100000) #define HID_FBIOB (0x00000010) #define HID_BHT (0x00000004) #define HID_NOOPTI (0x00000001) #define SetCPUMask( Disable, Val ) \ { \ if (Disable) \ HidDisable |= Val; \ else \ HidEnable |= Val; \ } CpuType = (USHORT)(HalpGetProcessorVersion() >> 16); CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); HidEnable = 0; HidDisable = 0; CurrentHID0 = HalpGetHID0(); switch (CpuType) { case 7: // 603ev // // Work-around for early parts. // CurrentHID0 |= HID_NOOPTI; case 3: // 603 case 6: // 603e // // Enable Dynamic Power Management // CurrentHID0 |= HID_DPM; break; case 4: // 604 case 9: // 604e // // Enable L1 Cache Parity Checking // CurrentHID0 |= HID_CACHE; break; } // // Set the default CPU Parity Checking. // This default can be platform dependent. // CurrentHID0 |= HID_MCP; // // The environment variable "HID0SETTINGS" is defined either as: // "CACHE", "ADDRESS", "DATA", "MCP", "DPM" with either blank or semi-colon // characters used as separators. Matching a string serves to enable // that feature while a tilde (~) immediately before the parameter // string indicates that it is to be disabled. // if (HalGetEnvironmentVariable("HID0SETTINGS", BUF_LEN, &CharBuffer[0]) == ESUCCESS) { for( Value = MyStrtok(CharBuffer, " :;,"); Value; Value = MyStrtok(NULL, " :;,") ) { Negate = FALSE; if (*Value == NEGATECHAR) { Value++; Negate = TRUE; } if (HalpStrCmp("MCP", Value)) { SetCPUMask(Negate, HID_MCP); } else if (HalpStrCmp("ADDRESS", Value)) { SetCPUMask(Negate, HID_ADDRESS); } else if (HalpStrCmp("DATA", Value)) { SetCPUMask(Negate, HID_DATA); } else if (HalpStrCmp("PAR", Value)) { SetCPUMask(Negate, HID_PAR); } else if (HalpStrCmp("BHT", Value)) { SetCPUMask(Negate, HID_BHT); } else if (HalpStrCmp("CACHE", Value)) { SetCPUMask(Negate, HID_CACHE); } else if (HalpStrCmp("DPM", Value)) { SetCPUMask(Negate, HID_DPM); } else if (HalpStrCmp("FBIOB", Value)) { SetCPUMask(Negate, HID_FBIOB); } else if (HalpStrCmp("NOOPTI", Value)) { SetCPUMask(Negate, HID_NOOPTI); } else { HalDisplayString("HAL: Error in HID0SETTINGS environment variable: "); HalDisplayString(CharBuffer); HalDisplayString("\n"); } } // End While } // End If // // Check for inconsistencies in HID0SETTINGS // if (HidEnable & HidDisable) { HalDisplayString("HAL: Inconsistent settings in HID0SETTINGS environment variable.\n"); HalDisplayString(" Disable setting will override enable setting.\n"); // // Enforce DISABLE override ENABLE // HidEnable &= ~HidDisable; } // // Disable and Enable the bits in the HID0 register. // CurrentHID0 &= ~HidDisable; // Disable bits first. HalpSetHID0(CurrentHID0); CurrentHID0 |= HidEnable; // Enable Bits last. HalpSetHID0(CurrentHID0); } BOOLEAN HalpMapPlanarSpace ( VOID ) /*++ Routine Description: This routine maps the interrupt acknowledge and error address spaces for a PowerPC system. Arguments: None. Return Value: If the initialization is successfully completed, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { PHYSICAL_ADDRESS physicalAddress; // // Map interrupt control space. // physicalAddress.HighPart = 0; physicalAddress.LowPart = INTERRUPT_PHYSICAL_BASE; HalpInterruptBase = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE); // // Map the error address register // physicalAddress.HighPart = 0; physicalAddress.LowPart = ERROR_ADDRESS_REGISTER; HalpErrorAddressRegister = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE); if (HalpInterruptBase == NULL || HalpErrorAddressRegister == NULL) return FALSE; else return TRUE; } BOOLEAN HalpMapBusConfigSpace ( VOID ) /*++ Routine Description: This routine maps the HAL PCI config spaces for a PowerPC system. Arguments: None. Return Value: If the initialization is successfully completed, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { PHYSICAL_ADDRESS physicalAddress; // // Map the PCI config space. // physicalAddress.LowPart = PCI_CONFIG_PHYSICAL_BASE; HalpPciConfigBase = MmMapIoSpace(physicalAddress, PCI_CONFIG_SIZE, FALSE); if (HalpPciConfigBase == NULL) return FALSE; else return TRUE; } BOOLEAN HalpPhase0MapBusConfigSpace ( VOID ) /*++ Routine Description: This routine maps the HAL PCI config spaces for a PowerPC system during phase 0 initialization. Arguments: None. Return Value: If the initialization is successfully completed, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { // // Map the PCI config space. // HalpPciConfigBase = (PUCHAR)KePhase0MapIo(PCI_CONFIG_PHYSICAL_BASE, 0x400000); if (HalpPciConfigBase == NULL) return FALSE; else return TRUE; } VOID HalpPhase0UnMapBusConfigSpace ( VOID ) /*++ Routine Description: This routine maps the HAL PCI config spaces for a PowerPC system during phase 0 initialization. Arguments: None. Return Value: If the initialization is successfully completed, than a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ { // // Unmap the PCI config space and set HalpPciConfigBase to NULL. // KePhase0DeleteIoMap(PCI_CONFIG_PHYSICAL_BASE, 0x400000); HalpPciConfigBase = NULL; } VOID HalpHandleMemoryError( VOID ) { UCHAR StatusByte; ULONG ErrorAddress; UCHAR TextAddress[20]; USHORT DeviceStatus; // // Read the error address register first // ErrorAddress = READ_PORT_ULONG(HalpErrorAddressRegister); // // Convert error address to HEX characters // HalpDisplayHex32(ErrorAddress, TextAddress ); DeviceStatus = HalpReadBridgeUshort(0x80000006); if (DeviceStatus & 0x8100) HalDisplayString("\n27-82660: Status Register: PARITY Error Detected.\n"); if (DeviceStatus & 0x4000) HalDisplayString("\n27-82660: Status Register: SERR asserted.\n"); // MOTKJR 08/22/95 - Don't check for the following bit. // It is always set when NT scans the slots on the PCI bus. // if (DeviceStatus & 0x2000) // HalDisplayString("\n27-82660: Status Register: Transaction terminated with master-abort.\n"); if (DeviceStatus & 0x1000) HalDisplayString("\n27-82660: Status Register: Transaction terminated by target-abort while master.\n"); if (DeviceStatus & 0x0800) HalDisplayString("\n27-82660: Status Register: Transaction terminated by target-abort while slave.\n"); // // Check TEA conditions // StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL) HalpIoControlBase)->MemoryParityErrorStatus); if (!(StatusByte & 0x01)) { HalDisplayString ("27-82660: Memory Parity Error at Address "); HalDisplayString (TextAddress); } StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL) HalpIoControlBase)->L2CacheErrorStatus); if (!(StatusByte & 0x01)) { HalDisplayString ("27-82660: L2 Cache Parity Error\n"); } StatusByte = READ_PORT_UCHAR(&((PDAKOTA_CONTROL) HalpIoControlBase)->TransferErrorStatus); if (!(StatusByte & 0x01)) { HalDisplayString ("27-82660: Transfer Error at Address "); HalDisplayString (TextAddress); } // // Check the Error Status 1 Register // StatusByte = HalpReadBridgeUchar(0x800000C1); if (StatusByte & 0x03) HalDisplayString("27-82660: CPU Transfer Error.\n"); if (StatusByte & 0x04) HalDisplayString("27-82660: Memory Parity Error.\n"); if (StatusByte & 0x08) HalDisplayString("27-82660: Memory Multi-bit ECC Error.\n"); if (StatusByte & 0x20) HalDisplayString("27-82660: Memory Select Error.\n"); if (StatusByte & 0x40) HalDisplayString("27-82660: PCI Data Bus Parity Error or PCI_SERR asserted.\n"); // // Check the Error Status 2 Register // StatusByte = HalpReadBridgeUchar(0x800000C5); if (StatusByte & 0x04) HalDisplayString("27-82660: CPU Data Bus Parity Error.\n"); if (StatusByte & 0x08) HalDisplayString("27-82660: L2 Parity Error.\n"); // // Check the PCI Bus Error Status Register // StatusByte = HalpReadBridgeUchar(0x800000C7); if (StatusByte & 0x10) HalDisplayString("27-82660: PCI cycle with 82660 Bridge as target.\n"); #if DBG // // We have had a catastrophic hardware malfunction. // Dump the state of the Bridge and HID 0 registers. // HalDisplayString("\n"); HalpDumpHardwareState(); #endif } VOID HalpCheckHardwareRevisionLevels( VOID ) { USHORT CpuRevision, CpuType; UCHAR BridgeRevision; UCHAR CharBuffer[20], i; ARC_STATUS Status; CpuType = (USHORT)(HalpGetProcessorVersion() >> 16); CpuRevision = (USHORT)(HalpGetProcessorVersion() & 0xFFFF); BridgeRevision = HalpReadBridgeUchar(0x80000008); // // Minimum hardware requirements: // 660 Bridge: v1.1 or greater // 603 or 604: v3.2 or greater // 603e: v1.4 or greater // 603ev: any CPU revision // 601, 604e, 620: any CPU revision // if (BridgeRevision >= 0x01) { switch (CpuType) { case 3: // 603 case 4: // 604 if (CpuRevision >= 0x0302) return; break; case 6: // 603e if (CpuRevision >= 0x0104) return; break; case 1: // 601 case 7: // 603ev case 9: // 604e case 20: // 620 default: return; } } // // If the environment variable BOOTOLDHARDWARE exists // (value is a don't care), then try to boot anyway. // Status = HalGetEnvironmentVariable("BOOTOLDHARDWARE", 5, CharBuffer); if (Status == ESUCCESS || Status == ENOMEM) return; HalDisplayString("HAL: Unsupported CPU and/or Bridge revision level."); // // Bug check - after stalling to allow // any information printed on the screen // to be read and seen by the user. // for (i=0; i<15; i++) { HalDisplayString("."); KeStallExecutionProcessor(1000000); } KeBugCheck(HAL_INITIALIZATION_FAILED); return; } VOID HalpDumpHardwareState(VOID) { ULONG BridgeRegister, HID0; UCHAR CharBuffer[12]; #if DBG if ( HalGetEnvironmentVariable("DBG_HAL", BUF_LEN, &CharBuffer[0]) == ESUCCESS ) { BridgeRegister = HalpReadBridgeUshort(0x80000004); HalDisplayString("HAL: Bridge register 04 = 0x"); HalpDisplayHex16(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUshort(0x80000006); HalDisplayString("HAL: Bridge register 06 = 0x"); HalpDisplayHex16(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000A0); HalDisplayString("HAL: Bridge register A0 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000A1); HalDisplayString("HAL: Bridge register A1 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000A2); HalDisplayString("HAL: Bridge register A2 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000B1); HalDisplayString("HAL: Bridge register B1 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000BA); HalDisplayString("HAL: Bridge register BA = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000BB); HalDisplayString("HAL: Bridge register BB = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C0); HalDisplayString("HAL: Bridge register C0 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C1); HalDisplayString("HAL: Bridge register C1 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C3); HalDisplayString("HAL: Bridge register C3 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C4); HalDisplayString("HAL: Bridge register C4 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C5); HalDisplayString("HAL: Bridge register C5 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000C7); HalDisplayString("HAL: Bridge register C7 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUlong(0x800000C8); HalDisplayString("HAL: Bridge register C8 = 0x"); HalpDisplayHex32(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); BridgeRegister = HalpReadBridgeUchar(0x800000D4); HalDisplayString("HAL: Bridge register D4 = 0x"); HalpDisplayHex8(BridgeRegister, CharBuffer ); HalDisplayString(CharBuffer); HID0 = HalpGetHID0(); HalDisplayString("HAL: PowerPC Register HID0 = 0x"); HalpDisplayHex32(HID0, CharBuffer ); HalDisplayString(CharBuffer); HalDisplayString("HAL: PCR Virtual Address - sprg1 = 0x"); HalpDisplayHex32((ULONG)PCRsprg1, CharBuffer ); HalDisplayString(CharBuffer); } #endif }