NT4/private/ntos/nthals/halfire/ppc/pxinithl.c
2020-09-30 17:12:29 +02:00

1115 lines
27 KiB
C

/*
* Copyright (c) 1995 FirePower Systems, Inc.
* DO NOT DISTRIBUTE without permission
*
* $RCSfile: pxinithl.c $
* $Revision: 1.92 $
* $Date: 1996/05/14 02:34:31 $
* $Locker: $
*/
/*++
Copyright (c) 1991-1993 Microsoft Corporation
Copyright (c) 1994 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:
pxinithl.c
Abstract:
This module implements the initialization of the system dependent
functions that define the Hardware Architecture Layer (HAL) for a
Power PC system.
Author:
David N. Cutler (davec) 25-Apr-1991
Environment:
Kernel mode only.
Revision History:
Jim Wooldridge (jimw@austin.ibm.com) Initial Power PC port
Removed call to HalpMapFixedTbEntries, the PPC port
maps all memory via calls to MmMapIoSpace().
Removed call to HalpInializeInterrupts - 8259 initialized in phase 1
Removed Cache error handler - 601 has no cache error interrupt
Removed call to HalpCreateDmaSturctures - it supports internal DMA
internal DMA contoller.
--*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "halp.h"
#include "pxmemctl.h"
#include "fpproto.h"
#include "phsystem.h"
#include "fpio.h"
#include "fpdcc.h"
#include "fpds1385.h"
#include "fpcpu.h"
#include "arccodes.h"
//#include "arc.h"
#include "fpdebug.h"
#include "fparch.h"
#include "fpi2c.h"
#include "pxpcisup.h"
ULONG TmpVramBase;
ULONG TmpDbatNum;
ULONG TmpDbatVal;
CHAR SysName[48];
PCHAR SystemName="Unknown System";
ULONG CpuClockMultiplier=0;
ULONG MemoryParityErrorsThisBoot = 0;
ULONG MemoryParityErrorsForever = 0;
extern ADDRESS_USAGE HalpDefaultIoSpace;
extern ULONG HalpGetInstructionTimes( VOID );
extern VOID HalpInitializeVector2Irql(VOID);
extern UCHAR PciDevicePrimaryInts[];
extern ULONG PciAllowedInts;
VOID
HalpSynchronizeExecution(
VOID
);
BOOLEAN
HalpPhase0MapIo (
VOID
);
BOOLEAN
HalpPhase0MapPCIConfig (
VOID
);
VOID
HalpInitParityErrorLog (
VOID
);
extern VOID HalpTranslateSystemSpecificData ( VOID );
extern ULONG HalpPerformanceFrequency;
extern BOOLEAN HalpSetRevs( RelInfo * );
VOID HalpRestoreDBATs(VOID);
VOID HalpSaveDBATs(VOID);
#if defined(HALDEBUG_ON)
VOID HalpDisplayBatForVRAM(void);
VOID HalpGetDebugValue(VOID);
extern BOOLEAN HalpPrintRevs( RelInfo * ); // from phvrsion.c
extern VOID HalpVersionInternal( VOID ); // from phvrsion.c
#endif
extern VOID HalpVersionExternal( RelInfo *, PLOADER_PARAMETER_BLOCK ); // from phvrsion.c
ULONG TimeBaseCount=0;
//
// This prototype taken from ntrtl.h.
// Why not just include ntrtl.h? Well because I would need to include a dozen
// other files too.
//
NTSYSAPI // ntddk ntifs
NTSTATUS // ntddk ntifs
NTAPI // ntddk ntifs
RtlCharToInteger ( // ntddk ntifs
PCSZ String, // ntddk ntifs
ULONG Base, // ntddk ntifs
PULONG Value // ntddk ntifs
); // ntddk ntifs
RelInfo ThisOne;
PROCESSOR_DESCRIPTION ProcessorDescription [nPROCESSOR_TYPE] = {
// Flags HashSize ProcessorName;
{PROC_NOSUPP, 0, "Unknown", "X"},
{PROC_SUPP, (64*1024), "601", "1"},
{PROC_NOSUPP, 0, "602", "2"},
{PROC_SUPP, 0, "603", "3"},
{PROC_SUPP |
PROC_HASHTABLE |
PROC_MPCAPABLE, (64*1024), "604", "4"},
{PROC_NOSUPP, 0, "605", "5"},
{PROC_SUPP, 0, "606", "3"},
{PROC_NOSUPP, 0, "607", "7"},
{PROC_NOSUPP, 0, "608", "8"},
{PROC_SUPP |
PROC_HASHTABLE |
PROC_MPCAPABLE, (64*1024), "609", "4"},
};
PROCESSOR_TYPE ProcessorType = PPC_UNKNOWN;
SYSTEM_DESCRIPTION SystemDescription [] = {
{SYS_NOSUPP, "Unknown System Type"},
{SYS_SUPP, "ES"},
{SYS_SUPP|
SYS_MPCAPABLE, "MX"},
{SYS_SUPP|
SYS_MPCAPABLE, "TX"},
{SYS_SUPP|
SYS_MPCAPABLE, "LX"},
};
SYSTEM_TYPE SystemType = SYS_UNKNOWN;
PVOID HalpSystemControlBase = NULL;
PVOID HalpSystemRegisterBase = NULL;
ULONG SafePlace;
//
// Define memory allocation structure.
//
typedef struct _AVR_MEMORY_DESCRIPTOR {
LIST_ENTRY *NextEntry;
LIST_ENTRY *PrevEntry;
MEMORY_DESCRIPTOR MemoryEntry;
} AVR_MEMORY_DESCRIPTOR, *PAVR_MEMORY_DESCRIPTOR;
CHAR *MemTypeList[] = {
"MemoryExceptionBlock",
"MemorySystemBlock",
"MemoryFree",
"MemoryBad",
"MemoryLoadedProgram",
"MemoryFirmwareTemporary",
"MemoryFirmwarePermanent",
"LoaderOsloaderHeap",
"LoaderOsloaderStack",
"LoaderSystemCode",
"LoaderHalCode",
"LoaderBootDriver",
"LoaderConsoleInDriver",
"LoaderConsoleOutDriver",
"LoaderStartupDpcStack",
"LoaderStartupKernelStack",
"LoaderStartupPanicStack",
"LoaderStartupPcrPage",
"LoaderStartupPdrPage",
"LoaderRegistryData",
"LoaderMemoryData",
"LoaderNlsData",
"LoaderSpecialMemory",
"LoaderMaximum"
};
//
// There are two variables that control debug printouts, HALDEBUG_ON,
// and HALDEBUGVALUE. HALDEBUGVALUE is used to set a minimum level
// of printing and debug behavior, and HALDEBUG_ON turns on the
// environment variable. HALDEBUG_ON may be defined without HALPDEBUGVALUE,
// but defining HALPDEBUGVALUE should require HALDEBUG_ON also be defined.
//
#if defined(HALDEBUG_ON)
//
// set the HalpDebugValue that determines what level of debug printout
// occurs. If one is defined on the cmd line, then 'or' it in with
// whatever is defined in the environment ( nvram ) area.
//
# if defined(HALPDEBUGVALUE)
int HalpDebugValue = HALPDEBUGVALUE;
# else
int HalpDebugValue = 0;
# endif // HALPDEBUGVALUE
#endif // HALPDEBUG_ON
//
// Put all code for HAL initialization in the INIT section. It will be
// deallocated by memory management when phase 1 initialization is
// completed.
//
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(INIT, HalInitSystem)
#pragma alloc_text(INIT, HalInitializeProcessor)
#pragma alloc_text(INIT, HalpInitParityErrorLog)
#endif
PVOID HalpIoControlBase = (PVOID) 0;
PVOID HalpIoMemoryBase = (PVOID) 0;
VOID
HalpInitBusHandlers (
VOID
);
VOID
HalpRegisterInternalBusHandlers (
VOID
);
//
// Define global spin locks used to synchronize various HAL operations.
//
KSPIN_LOCK HalpBeepLock;
KSPIN_LOCK HalpDisplayAdapterLock;
KSPIN_LOCK HalpSystemInterruptLock;
KSPIN_LOCK HalpDS1385Lock;
KSPIN_LOCK HalpRTCLock;
/*++
Routine Description: BOOLEAN HalInitSystem ()
This function initializes the Hardware Architecture Layer (HAL) for a
Power PC system.
Arguments:
Phase - Supplies the initialization phase (zero or one).
LoaderBlock - Supplies a pointer to a loader parameter block.
Return Value:
A value of TRUE is returned is the initialization was successfully
complete. Otherwise a value of FALSE is returend.
--*/
BOOLEAN
HalInitSystem (
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
PKPRCB Prcb;
ULONG BuildType = 0;
SYSTEM_TYPE I2CSystemType;
UCHAR slot;
ULONG *TreeDepth = 0;
UCHAR CpuId;
KIRQL IrqlIn;
//
// Initialize the HAL components based on the phase of initialization
// and the processor number.
//
Prcb = PCR->Prcb;
IrqlIn = PCR->CurrentIrql;
SET_LEDS(0xf7);
//
// The following handles the initialization requirements for
// all processors greater than 1.
//
if (Prcb->Number > 0) {
HDBG(DBG_INTERNAL,
HalpDebugPrint("HalInitSystem: Init of Cpu(%d)\n", GetCpuId()););
//
// Mask interrrupts, clear all of them and then
// enable interrupts.
//
HalpDisableInterrupts();
HalpInitInts(Prcb->Number);
HalpRestoreDBATs();
HalpEnableInterrupts();
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: Cpu (%d) Interrupt Mask (0x%08x)\n",
GetCpuId(), RInterruptMask(GetCpuId())););
HDBG(DBG_INTERNAL,
HalpDebugPrint("HalInitSystem: exit Cpu(%d)\n", GetCpuId()));
//
// Check the current irql level and make sure we exit at the same
// irql we entered with:
//
if( PCR->CurrentIrql >= IrqlIn ) {
KeLowerIrql(IrqlIn);
} else {
KIRQL dummyIrql;
KeRaiseIrql(IrqlIn, &dummyIrql);
}
return TRUE;
}
//
// Phase 0 initialization. (Main Processor Only).
//
ASSERT(Prcb->Number == 0);
if (Phase == 0) {
PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
ULONG MatchKey = 0;
HalpInitParityErrorLog();
#if defined(HALDEBUG_ON)
//
// Get user defined debug variable and 'or' it into the
// compiled version of the debug variable.
//
HalpGetDebugValue();
#endif
// moved this from after ConfigurationEntry because HalpGet
if (NULL == HalpIoControlBase) {
if (!HalpPhase0MapIo() || !HalpPhase0MapPCIConfig()) {
return FALSE;
}
}
// Initialize the Pci Primary Slot table to be invalid; this table
// is filled in on a per system basis.
for (slot = 0; slot < MAXIMUM_PCI_SLOTS; slot++) {
PciDevicePrimaryInts[slot] = INVALID_INT;
}
ConfigurationEntry =
KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
SystemClass,
ArcSystem,
&MatchKey);
if (ConfigurationEntry) {
//
// If configuration entry is not null, then look at the
// identifier returned for this arc system name. If its the MP
// system, it means we really do have more than one cpu and
// will want to set a flag so VRAM is handled
// differently, and some extra checking is done.
//
SystemName = ConfigurationEntry->ComponentEntry.Identifier;
// Check if I2C is present
if (HalpI2CGetSystem(&I2CSystemType) == TRUE) {
SystemDescription[SystemType].Flags |= SYS_MPFOREAL;
// If I2C is present, determine if we are Slice or Serve
SystemType = I2CSystemType;
if ((SystemType != SYS_POWERSLICE) &&
(SystemType != SYS_POWERSERVE)) {
SystemType = SYS_UNKNOWN;
}
// An I2C is present, find the interrupt table. If there
// is no interrupt table, set SystemType back to SYS_UNKNOWN
// so that we may die now, since this is an unrecoverable
// error.
if (HalpI2CGetInterrupt() == FALSE) {
SystemType = SYS_UNKNOWN;
}
}
// If I2c is not present, must be either Pro or Top
else {
if (SystemType == SYS_POWERTOP) {
SystemDescription[SystemType].Flags |= SYS_MPFOREAL;
}
PciDevicePrimaryInts[1] = 0x19;
PciDevicePrimaryInts[2] = 0x16;
PciDevicePrimaryInts[3] = 0x17;
PciDevicePrimaryInts[4] = 0x1a;
PciAllowedInts = 0x06c00000;
}
} else {
HalpDebugPrint("ConfigurationEntry is null \n");
}
// Now compute the allowed interrupt mask
for (slot = 0; slot < MAXIMUM_PCI_SLOTS; slot++) {
if (PciDevicePrimaryInts[slot] != INVALID_INT) {
PciAllowedInts |= (1 << PciDevicePrimaryInts[slot]);
}
}
PciAllowedInts |= 0x40000000; // Add the MemErr bit
// If we are not a valid system type; die a horrible death
if (SystemType == SYS_UNKNOWN) {
HalpDebugPrint("HalInitSystem: Unknown SystemType\n");
DbgBreakPoint();
}
// Once we have the interrupt structure, we can initialize the IRQL
// values for the PIO slots.
HalpInitializeVector2Irql();
HDBG(DBG_INTERNAL,
HalpDebugPrint("HalInitSystem: phase 0 init (processor 0)\n"););
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: HalpIoControlBase set: 0x%08x\n",
HalpIoControlBase););
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: HalpSystemRegisterBase(0x%x)\n",
HalpSystemRegisterBase););
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: rInterruptRequest(0x%x)\n",
_ADDR(0x0)););
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: PciAllowedInts(0x%x)\n",
PciAllowedInts););
HalpInterruptBase =
(PULONG)HalpSystemRegisterBase + INTERRUPT_OFFSET;
//
// clear out all the crap from the system interrupt registers:
//
RInterruptMask(GetCpuId()) = 0x0;
WaitForRInterruptMask(GetCpuId());
rInterruptRequest = 0xffffffff;
FireSyncRegister();
//
// Verify that the processor block major version number conform
// to the system that is being loaded.
//
if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
KeBugCheck(MISMATCHED_HAL);
}
//
// Init variables, spin locks, and the display adapter.
//
//
// Set the interval clock increment value.
//
HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
HalpNewTimeIncrement = MAXIMUM_INCREMENT;
KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT);
//
// Initialize all spin locks.
//
KeInitializeSpinLock(&HalpBeepLock);
KeInitializeSpinLock(&HalpDisplayAdapterLock);
KeInitializeSpinLock(&HalpSystemInterruptLock);
KeInitializeSpinLock(&HalpDS1385Lock);
KeInitializeSpinLock(&HalpRTCLock);
HalpRegisterAddressUsage (&HalpDefaultIoSpace);
//
// Initialize the display adapter.
//
if (!HalpInitializeDisplay(LoaderBlock)) {
HalpDebugPrint("HalInitSystem: did not init display\n");
return FALSE;
}
//
// set the background red for phase 0
//
HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x00ff0000, 0x00000001 ););
HDBG(DBG_GENERAL,
HalpDebugPrint("Debug Value is 0x%x\n", HalpDebugValue););
HDBG(DBG_DUMPTREE,
PHalpDumpConfigData(LoaderBlock->ConfigurationRoot,
TreeDepth););
HDBG(DBG_DUMPTREE,
PHalpDumpLoaderBlock(LoaderBlock););
//
// Check if we should call a break point
//
HDBG(DBG_BREAK,
HalpDebugPrint("HalInitSystem: Calling Break Point\n"));
HDBG(DBG_BREAK, DbgBreakPoint());
//
// RTC: check that the RTC is working...
//
HDBG(DBG_GENERAL, HalpDebugPrint("Checking RTC ....\n"););
HalpInitFirePowerRTC();
//
// Calibrate execution stall
//
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: Calibrating stall\n"););
HalpCalibrateTimingValues();
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: HalpPerformanceFrequency = %d\n",
HalpPerformanceFrequency););
//
// InitializeInterrupts
//
HDBG(DBG_GENERAL, HalpDebugPrint("HalInitSystem: Initting ints\n"););
if (!HalpInitializeInterrupts()) {
HalpDebugPrint("HalInitSystem: Did not init interrupts ");
return FALSE;
}
HDBG(DBG_GENERAL, HalpDisplayBatForVRAM(););
HalpSaveDBATs();
HDBG(DBG_GENERAL,
HalDisplayString("HalInitSystem: done with phase 0 \n"););
HDBG(DBG_GENERAL,
HalpDebugPrint("System Name: %s \n", SystemName ););
} else {
//
// Phase 1 initialization.
//
//
// set the display to green while in phase 1:
//
HDBG(DBG_COLORS, HalpSetPixelColorMap(0x00009900, 0x00000001););
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: phase 1 init (processor 0)\n"););
HalpInitializeDisplay1(LoaderBlock );
HalpRegisterInternalBusHandlers ();
if (!HalpAllocateMapBuffer()) {
HalpDebugPrint("HalInitSystem: Did not allocate map buffer");
return FALSE;
}
//
// Map I/O space and create ISA data structures.
//
if (!HalpMapIoSpace()) {
HalpDebugPrint("HalInitSystem: Did not map io space");
return FALSE;
}
//
// Setup Io bus handlers ( really only setting up pci bus 0:
// the primary one). This needs to be done before the call
// to HalpCreateSioStructures so it can find the pci-e/isa
// bridge chip.
//
HalpInitIoBuses();
if (!HalpCreateSioStructures()) {
HalpDebugPrint("HalInitSystem: No sio structures created");
return FALSE;
}
//
// At this point, the interrupt handlers are installed so any
// interrupts pending are cleared...
//
if (!HalpInitIntelAIP()) {
HalpDebugPrint("HalInitSystem: AIP did not initialize\n");
return FALSE;
}
//
// Note: GetCpuId can not be called earlier
// because the registers are not mapped.
//
CpuId = (UCHAR) GetCpuId();
if (SystemType == SYS_POWERPRO) {
CpuId = 0;
}
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: Cpu id is: %d\n", CpuId););
//
// Display HAL specific information
//
HalpSetRevs( &ThisOne );
HDBG(DBG_GENERAL, HalpPrintRevs( &ThisOne ););
HDBG(DBG_GENERAL, HalpVersionInternal(););
HDBG(DBG_GENERAL,
HalpDebugPrint("CpuClockMultiplier = 0x%x ( %d ) \n",
CpuClockMultiplier, CpuClockMultiplier ));
HalpVersionExternal(&ThisOne, LoaderBlock);
//
// Before we exit, make sure any device interrupts are masked
// off, and all interrupts are cleared. DON'T FORGET: by this
// point, several interrupts have gone through a connect call,
// they may already exist in the mask. None of the devices are
// currently in this set but the cpu message interrupt. DON"T
// MESS WITH THE CPU MESSAGE INTERRUPT BIT!!
//
switch(SystemType) {
case SYS_POWERSLICE:
RInterruptMask(GetCpuId()) &= ~(ENABLE_EISA_MASK);
break;
case SYS_POWERSERVE:
// TX_PROTO: allowable PCI interrupts
RInterruptMask(GetCpuId()) &=
~(ENABLE_EISA_MASK|0x06700000);
break;
case SYS_POWERTOP:
case SYS_POWERPRO:
RInterruptMask(GetCpuId()) &= ~(ENABLE_EISA_MASK|
SCSI_INT|
ENET_INT);
break;
default:
break;
};
WaitForRInterruptMask(GetCpuId());
rInterruptRequest = SET_INTS_CLEAR;
FireSyncRegister();
//HalpEnableInterrupts();
// Turn on interrupts, set the irql, and setup the system int masks:
//
KeLowerIrql(LOW_LEVEL);
HDBG(DBG_GENERAL,
HalpDebugPrint("HalInitSystem: Cpu (%d) Interrupt Mask (0x%x)\n",
GetCpuId(), RInterruptMask(GetCpuId())));
//
// Make sure the display is now a blue background with
// White letters:
//
HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x00ffffff, 0x000000ff ));
HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x000000ff, 0x00000001 ));
HalpInitializeRegistry(LoaderBlock); // mogawa
HalpTranslateSystemSpecificData ();
HDBG(DBG_GENERAL, HalpDebugPrint("HalInitSystem: done phase 1\n"););
}
//
// Check the current irql level and make sure we exit at the same
// irql we entered with:
//
if( PCR->CurrentIrql >= IrqlIn ) {
KeLowerIrql(IrqlIn);
} else {
KIRQL dummyIrql;
KeRaiseIrql(IrqlIn, &dummyIrql);
}
return TRUE;
}
/*++
Routine Description: VOID HalInitializeProcessor ()
This function is called early in the initialization of the kernel
to perform platform dependent initialization for each processor
before the HAL Is fully functional.
N.B. When this routine is called, the PCR is present but is not
fully initialized.
Arguments:
Number - Supplies the number of the processor to initialize.
Return Value:
None.
--*/
VOID
HalInitializeProcessor (
IN ULONG Number
)
{
PULONG pPCIBase;
BOOLEAN newMap;
ULONG IcacheSize, DcacheSize;
ULONG CacheBlockAlignment;
//
// Initialize the processor type (601, 603, 604, ...)
//
ProcessorType = (HalpGetProcessorVersion() >> 16);
//
// FireWorks ( FirePOWER and Firmworks ) veneer does not correctly set the
// processor cache size and alignment requirements in the loader parameter
// block so we forcibly replace the values that were copied from there
// into the PCR.
//
switch( ProcessorType ) {
case 1: // 601 processor
IcacheSize = 32 * 1024;
DcacheSize = 32 * 1024;
CacheBlockAlignment = 32 - 1;
break;
case 3: // 603 processor
IcacheSize = 8 * 1024;
DcacheSize = 8 * 1024;
CacheBlockAlignment = 32 - 1;
break;
case 6: // 603+ processor
case 4: // 604 processor
IcacheSize = 16 * 1024;
DcacheSize = 16 * 1024;
CacheBlockAlignment = 32 - 1;
break;
case 9: // 604+ processor
IcacheSize = 32 * 1024;
DcacheSize = 32 * 1024;
CacheBlockAlignment = 32 - 1;
break;
default:
KeBugCheck(HAL_INITIALIZATION_FAILED);
return;
}
PCRsprg1->FirstLevelIcacheSize = IcacheSize;
PCRsprg1->FirstLevelDcacheSize = DcacheSize;
PCRsprg1->DcacheAlignment = CacheBlockAlignment;
PCRsprg1->IcacheAlignment = CacheBlockAlignment;
//
// Check what cpu we're on. Return now if this cpu is
// not the primary ( first ) cpu.
//
if (Number != 0) {
return; // Nothing to do here, just return
}
//
// Initialize the system type register (PowerPro vs PowerTop).
// Use the System Register Base address if mapped to access
// the control page of the system. If not, map a virtual
// address temporarily and unmap it when finished.
//
if (NULL == HalpIoControlBase) {
if (!HalpPhase0MapIo() || !HalpPhase0MapPCIConfig()) {
DbgPrint("HalInitializeProcessor: Failed to map dbats\n");
return;
}
}
if (HalpSystemRegisterBase) {
pPCIBase = (PULONG)((PUCHAR)HalpSystemRegisterBase +
(SYSTEM_PCI_CONFIG_BASE - SYSTEM_REGISTER_SPACE));
newMap = FALSE;
} else {
pPCIBase =
(PULONG)KePhase0MapIo((PVOID)SYSTEM_PCI_CONFIG_BASE, 0x1000);
newMap = TRUE;
}
if (pPCIBase) {
PULONG pDeviceId;
// for little endian reasons, add the 1 in.
pDeviceId = (PULONG)(pPCIBase + 0x42 + 0x01);
switch (*pDeviceId) {
case ESCC_IDENT:
SystemType = SYS_POWERPRO;
break;
case TSC_IDENT:
SystemType = SYS_POWERTOP;
break;
default:
SystemType = SYS_UNKNOWN;
break;
}
if (newMap) {
KePhase0DeleteIoMap((PVOID)SYSTEM_PCI_CONFIG_BASE, 0x1000);
}
} else {
SystemType = SYS_UNKNOWN;
}
//
// If this is the first processor, initialize the cache
// sweeping routines depending on type of processor.
//
if (HalpCacheSweepSetup()) {
KeBugCheck(MISMATCHED_HAL);
}
//
// Calculate the cpu clock rate:
//
// Temporary fix until we understand the code
if (SystemType == SYS_POWERPRO) {
CpuClockMultiplier = 30; // fix it for the moment....
} else {
if ((SystemType == SYS_POWERSLICE) ||
(SystemType == SYS_POWERTOP) ||
(SystemType == SYS_POWERSERVE)) {
//
// The times recorded from HalpGetInstructionTimes range about
// 80 to 256.
// times: Multiplier:
// 85/6 3x BusClock
// 128 2x
// 170/1 1.5x
// 256 1x
//
// Since there can be a non integer multiple of bus clocks, will
// do all integer math at a multiple of 10 and remove the extra
// order of magnitude downstream when the value is used
//
TimeBaseCount = HalpGetInstructionTimes();
TimeBaseCount = HalpGetInstructionTimes();
CpuClockMultiplier = ((480 * 10) / (10 * (TimeBaseCount/10)));
if (CpuClockMultiplier > 50 ) {
CpuClockMultiplier = 50; // limit frequency multiples to 5.
}
}
}
return;
}
#define MAX_DBATS 4
ULONG DBATUpper[MAX_DBATS];
ULONG DBATLower[MAX_DBATS];
VOID
HalpRestoreDBATs()
{
int i;
HDBG(DBG_INTERNAL, HalpDebugPrint("HalpRestoreDBATs: entered\n"););
for (i = 0; i < MAX_DBATS; i++) {
HDBG(DBG_DBAT,
HalpDebugPrint("HalpRestoreDBATs: U(%d):Old(0x%08x) New(0x%08x)\n",
i, HalpGetUpperDBAT(i), DBATUpper[i]););
HDBG(DBG_DBAT,
HalpDebugPrint("HalpRestoreDBATs: L(%d):Old(0x%08x) New(0x%08x)\n",
i, HalpGetLowerDBAT(i), DBATLower[i]););
HalpSetUpperDBAT(i, DBATUpper[i]);
HalpSetLowerDBAT(i, DBATLower[i]);
}
HDBG(DBG_INTERNAL, HalpDebugPrint("HalpRestoreDBATs: exit\n"););
}
VOID
HalpSaveDBATs()
{
int i;
HDBG(DBG_INTERNAL, HalpDebugPrint("HalpSaveDBATs: entered\n"););
for (i = 0; i < MAX_DBATS; i++) {
DBATUpper[i] = HalpGetUpperDBAT(i);
DBATLower[i] = HalpGetLowerDBAT(i);
HDBG(DBG_DBAT,
HalpDebugPrint("HalpSaveDBATs: (%d): U(0x%08x) L(0x%08x)\n",
i, DBATUpper[i], DBATLower[i]););
}
}
/*++
Routine Description: BOOLEAN HalpPhase0MapIo ()
This function forces a very special DBAT mapping for Phase0.
The kernel routine KePhase0DeleteIoMap has a nasty bug, so
just map three (the max) DBATS:
1) system registers
2) memory (to be reused for VRAM if no INT10 support)
3) I/O control (change the size of its mapping)
The idea is to let the kernel map the three DBATs.
It sets the boundary to 8Mb and maps 8Mb starting at
virtual address 0xb0000000. Thus you get the following
virtual to physical mappings:
DBAT2 = 0xb0800000-0xb0ffffff -> 0xff000000-0xffffffff
DBAT3 = 0xb1000000-0xb17fffff -> 0x80000000-0x80ffffff
The I/O control size will be changed (by HalpPhase0MapPCIConfig())
to 16Mb so it maps 0x80000000 to 0x80ffffff which covers the PCI
config space.
The mapping of the frame buffer or memory space (for INT10)
is left to pxdisp.c which will use DBAT1.
Arguments:
Return Value:
TRUE if success, FALSE if failure
--*/
BOOLEAN
HalpPhase0MapIo (
VOID
)
{
//
// Get access to I/O space.
//
if (NULL == HalpIoControlBase) {
HalpIoControlBase =
(PVOID)KePhase0MapIo((PVOID)IO_CONTROL_PHYSICAL_BASE, 0x800000);
if (!HalpIoControlBase) {
DbgPrint("HalpPhase0MapIo: HalpIoControlBase map failed\n");
return FALSE;
}
}
//
// Get access to System Register space.
//
if (NULL == HalpSystemRegisterBase) {
HalpSystemRegisterBase =
(PVOID)KePhase0MapIo((PVOID)SYSTEM_REGISTER_SPACE, 0x800000);
if(HalpSystemRegisterBase) {
HalpInterruptBase =
(PULONG)HalpSystemRegisterBase + INTERRUPT_OFFSET;
HalpSystemControlBase =
(PULONG)HalpSystemRegisterBase + SYSTEM_CONTROL_OFFSET;
} else {
DbgPrint("HalpPhase0MapIo: HalpSystemRegisterBase map failed\n");
return FALSE;
}
}
return TRUE;
}
/*++
Routine Description: BOOLEAN HalpPhase0MapPCIConfig ()
This function extends the map length of I/O Control
to include PCI Config space.
Arguments:
Return Value:
TRUE if success, FALSE if failure
--*/
BOOLEAN
HalpPhase0MapPCIConfig (
VOID
)
{
ULONG hi, low;
LONG i;
//
//
// Look for the I/O control space DBAT mapping.
//
for (i = 1; i < MAX_DBATS; i++) {
PVOID va = NULL;
low = HalpGetLowerDBAT(i);
if (IO_CONTROL_PHYSICAL_BASE == (low & 0xfffe0000)) {
hi = HalpGetUpperDBAT(i);
if ((PVOID)(hi & 0xfffe0000) == HalpIoControlBase) {
if (3 == i) {
//
// Change the size to 16Mb.
//
hi &= ~0x000001fc;
hi |= 0x000001fc;
HalpSetUpperDBAT(i, hi);
hi = HalpGetUpperDBAT(i);
if ((hi & 0x00001ffc) == 0x000001fc) {
HalpPciConfigBase = (PUCHAR)HalpIoControlBase +
((ULONG)PCI_CONFIG_PHYSICAL_BASE -
(ULONG)IO_CONTROL_PHYSICAL_BASE);
} else {
DbgPrint("HalpPhase0MapPCIConfig: failed, invalid size\n");
return FALSE;
}
} else {
DbgPrint("HalpPhase0MapPCIConfig: failed, invalid DBAT\n");
}
} else {
DbgPrint("HalpPhase0MapPCIConfig: failed, invalid virtual address\n");
return FALSE;
}
return TRUE;
}
}
DbgPrint("HalpPhase0MapPCIConfig: failed, invalid physical address\n");
return FALSE;
}
#if defined(HALDEBUG_ON)
VOID
HalpGetDebugValue()
{
CHAR buf[30];
int nvramValue;
//
// Get Debug Value from NVRAM and or with compiler version
//
if (HalGetEnvironmentVariable("HALDEBUG", sizeof(buf), buf) == ESUCCESS) {
nvramValue = atoi(buf);
HalpDebugValue |= nvramValue;
}
}
#endif
//
// Initialize the global variables for parity error count.
//
// The initial value for this boot is zero.
// The initial value forever is read from NVRAM.
//
// The NVRAM values are stored in the env variable
// "MEMORY_PARITY_ERRORS" as:
// # errors this boot, # errors forever
//
//
VOID
HalpInitParityErrorLog (
VOID
)
{
ULONG rc;
CHAR buf[80];
rc = HalGetEnvironmentVariable(MemoryParityErrorsVarName,
sizeof(buf), buf);
if (ESUCCESS == rc) {
PCHAR tok;
const PCHAR delimiters = ",; ";
if (buf && strlen(buf) && (tok = FpStrtok(buf, delimiters))) {
rc = RtlCharToInteger(tok, 0, &MemoryParityErrorsThisBoot);
if (STATUS_SUCCESS != rc) {
MemoryParityErrorsThisBoot = 0;
}
while ( tok = FpStrtok(NULL, delimiters) ) {
if (strlen(tok)) {
rc = RtlCharToInteger(tok, 10, &MemoryParityErrorsForever);
if (STATUS_SUCCESS != rc) {
MemoryParityErrorsForever = 0;
}
}
}
}
}
}