diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halflex/mips | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nthals/halflex/mips')
20 files changed, 5306 insertions, 0 deletions
diff --git a/private/ntos/nthals/halflex/mips/addrsup.c b/private/ntos/nthals/halflex/mips/addrsup.c new file mode 100644 index 000000000..795e529a5 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/addrsup.c @@ -0,0 +1,204 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ixphwsup.c + +Abstract: + + This module contains the HalpXxx routines for the NT I/O system that + are hardware dependent. Were these routines not hardware dependent, + they would normally reside in the internal.c module. + +Author: + + Michael D. Kinney 30-Apr-1995 + +Environment: + + Kernel mode, local to I/O system + +Revision History: + + +--*/ + +#include "halp.h" + +#define KERNEL_PCI_VGA_VIDEO_ROM (LONGLONG)(0x8000000000000000) + +PLATFORM_RANGE_LIST Gambit20Trebbia13RangeList[] = { + { Isa , 0, BusIo, 0, TREB1_GAMBIT_ISA_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Isa , 0, BusMemory, 0, TREB1_GAMBIT_ISA_MEMORY_BASE_PHYSICAL , 0x00000000, 0x00ffffff }, + + { Isa , 1, BusIo, 0, TREB1_GAMBIT_ISA1_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Isa , 1, BusMemory, 0, TREB1_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Isa , 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { Eisa , 0, BusIo, 0, TREB1_GAMBIT_ISA_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Eisa , 0, BusMemory, 0, TREB1_GAMBIT_ISA_MEMORY_BASE_PHYSICAL , 0x00000000, 0xffffffff }, + + { Eisa , 1, BusIo, 0, TREB1_GAMBIT_ISA1_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Eisa , 1, BusMemory, 0, TREB1_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Eisa , 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { PCIBus, 0, BusIo, 0, TREB1_GAMBIT_PCI_IO_BASE_PHYSICAL , 0x00000000, 0xffffffff }, + { PCIBus, 0, BusMemory, 0, TREB1_GAMBIT_PCI_MEMORY_BASE_PHYSICAL+0x40000000 , 0x40000000, 0xffffffff }, + + { PCIBus, 1, BusIo, 0, TREB1_GAMBIT_PCI_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { PCIBus, 1, BusMemory, 0, TREB1_GAMBIT_PCI_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { PCIBus, 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + { PCIBus, 1, BusMemory, 0, TREB1_GAMBIT_PCI_MEMORY_BASE_PHYSICAL+0x40000000 , 0x40000000, 0xffffffff }, + + { MaximumInterfaceType, 0, 0, 0, 0 , 0 , 0 } +}; + +PLATFORM_RANGE_LIST Gambit20Trebbia20RangeList[] = { + { Isa , 0, BusIo, 0, TREB2_GAMBIT_ISA_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Isa , 0, BusMemory, 0, TREB2_GAMBIT_ISA_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Isa , 0, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { Isa , 1, BusIo, 0, TREB2_GAMBIT_ISA1_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Isa , 1, BusMemory, 0, TREB2_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Isa , 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { Eisa , 0, BusIo, 0, TREB2_GAMBIT_ISA_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Eisa , 0, BusMemory, 0, TREB2_GAMBIT_ISA_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Eisa , 0, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { Eisa , 1, BusIo, 0, TREB2_GAMBIT_ISA1_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { Eisa , 1, BusMemory, 0, TREB2_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { Eisa , 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + + { PCIBus, 0, BusIo, 0, TREB2_GAMBIT_PCI_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { PCIBus, 0, BusMemory, 0, TREB2_GAMBIT_PCI_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { PCIBus, 0, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + { PCIBus, 0, BusMemory, 0, TREB2_GAMBIT_PCI_MEMORY_BASE_PHYSICAL+0x40000000 , 0x40000000, 0xffffffff }, + + { PCIBus, 1, BusIo, 0, TREB2_GAMBIT_PCI1_IO_BASE_PHYSICAL , 0x00000000, 0x0000ffff }, + { PCIBus, 1, BusMemory, 0, TREB2_GAMBIT_PCI1_MEMORY_BASE_PHYSICAL+0xa0000 , 0x000a0000, 0x000bffff }, + { PCIBus, 1, BusMemory, 0, KERNEL_PCI_VGA_VIDEO_ROM , 0x000c0000, 0x000c7fff }, + { PCIBus, 1, BusMemory, 0, TREB2_GAMBIT_PCI1_MEMORY_BASE_PHYSICAL+0x40000000 , 0x40000000, 0xffffffff }, + + { MaximumInterfaceType, 0, 0, 0, 0 , 0 , 0 } +}; + + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) + +{ + ULONG i; + INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType; + ULONG BusNumber = BusHandler->BusNumber; + LONGLONG Offset; + PVOID va = 0; // note, this is used for a placeholder + +//BusAddress.HighPart = 0; +//DbgPrint("HalTranslateBusAddress(IT=%d,BN=%d,BA=%08x %08x,AS=%d)\n\r",InterfaceType,BusNumber,BusAddress.HighPart,BusAddress.LowPart,*AddressSpace); + + // + // PCI Bus 0 is different than PCI Bus 1, but all other PCI busses are the same a PCI Bus 1 + // + + if (InterfaceType == PCIBus) { + + switch (HalpMotherboardType) { + case TREBBIA13 : + if (BusNumber > 1) { + BusNumber = 1; + } + break; + + case TREBBIA20 : + if (BusNumber == 0) { + + // + // There are no resources in PCI Bus #0. It only contains the memory system and bridges. + // + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + + if (BusNumber >= HalpSecondPciBridgeBusNumber) { + BusNumber = 1; + } else { + BusNumber = 0; + } + break; + + default : + +//DbgPrint(" Invalid Motherboard Type\n\r"); + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + } + + // + // If the VGA decodes are not enabled on the DEC PCI-PCI bridge associated with this + // memory range, then fail the translation. + // + + if (!(HalpVgaDecodeBusNumber & (1<<BusNumber)) && + BusAddress.QuadPart < (LONGLONG)0x0000000000100000 && + (((ADDRESS_SPACE_TYPE)(*AddressSpace) == BusMemory) || + ((ADDRESS_SPACE_TYPE)(*AddressSpace) == UserBusMemory) || + ((ADDRESS_SPACE_TYPE)(*AddressSpace) == KernelPciDenseMemory) || + ((ADDRESS_SPACE_TYPE)(*AddressSpace) == UserPciDenseMemory) )) { + + *AddressSpace = 0; + TranslatedAddress->LowPart = 0; + return(FALSE); + } + + // + // Search the table for a valid mapping. + // + + for(i=0;HalpRangeList[i].InterfaceType!=MaximumInterfaceType;i++) { + + if (HalpRangeList[i].InterfaceType == InterfaceType && + HalpRangeList[i].BusNumber == BusNumber && + HalpRangeList[i].AddressType == (ADDRESS_SPACE_TYPE)(*AddressSpace) && + BusAddress.QuadPart >= HalpRangeList[i].Base && + BusAddress.QuadPart <= HalpRangeList[i].Limit ) { + + TranslatedAddress->QuadPart = HalpRangeList[i].SystemBase; + *AddressSpace = HalpRangeList[i].SystemAddressSpace; + + if (TranslatedAddress->QuadPart & KERNEL_PCI_VGA_VIDEO_ROM) { + TranslatedAddress->QuadPart &= ~KERNEL_PCI_VGA_VIDEO_ROM; + if (HalpPlatformParameterBlock->FirmwareRevision >= 50) { + TranslatedAddress->QuadPart += (LONGLONG)HalpPlatformSpecificExtension->PciVideoExpansionRomAddress; + } else { + TranslatedAddress->QuadPart += (TREB1_GAMBIT_ISA_MEMORY_BASE_PHYSICAL + (LONGLONG)0xc0000); + } + } + + Offset = BusAddress.QuadPart - HalpRangeList[i].Base; + TranslatedAddress->QuadPart += Offset; + return(TRUE); + } + } + + // + // A valid mapping was not found. + // + + *AddressSpace = 0; + TranslatedAddress->QuadPart = 0; + return(FALSE); +} diff --git a/private/ntos/nthals/halflex/mips/arcssup.c b/private/ntos/nthals/halflex/mips/arcssup.c new file mode 100644 index 000000000..44d37edd3 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/arcssup.c @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) 1995 DeskStation Technology + +Module Name: + + arcssup.c + +Abstract: + + This module allocates resources before a call to the ARCS Firmware, and + frees those reources after the call returns. + +Author: + + Michael D. Kinney 30-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + +typedef +VOID +(*PSET_VIRTUAL_BASE) ( + IN ULONG Number, + IN PVOID Base + ); + + +VOID +HalpArcsSetVirtualBase ( + IN ULONG Number, + IN PVOID Base + ) + +/*++ + +Routine Description: + + This routine makes a private call into the ARCS Firmware to provide the + firmware with parameters is need to perform I/O operations while NT is + active. + +Arguments: + + Number : Address space type + + Base : Kernel Virtual Address for the given address space type. + +Return Value: + + None. + +--*/ + +{ + PSYSTEM_PARAMETER_BLOCK SystemParameterBlock = SYSTEM_BLOCK; + PSET_VIRTUAL_BASE PrivateSetVirtualBase; + + + // + // Call private vector function SetVirtualBase so that the firmware functions + // can perform I/O operations while NT is active. If SetVirtualBase does + // not exist, then print an error message out the debug port and halt the system. + // + + if ((SystemParameterBlock->VendorVectorLength / 4) >= 28) { + + PrivateSetVirtualBase = *(PSET_VIRTUAL_BASE *)((ULONG)(SystemParameterBlock->VendorVector) + 28*4); + PrivateSetVirtualBase(Number,Base); + + } else { + + KdPrint(("HAL : SetVirtualBase does not exist. Halting\n")); + for(;;); + + } + +} + + +VOID +HalpAllocateArcsResources ( + VOID + ) + +/*++ + +Routine Description: + + This routine allocated resources required before an ARCS Firmware call is made. + On a MIPS system, if any I/O operations are going to be performed by the + firmware routine, a TLB entry needs to be reserved for these I/O operations. + This routine reserves a single TLB entry and a 4 KB page out of the kernel + virtual address space. These parameters are passed to the firmware through + a private vector call. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + + +{ + HalpArcsSetVirtualBase(6,(PVOID)(HalpAllocateTbEntry())); + HalpArcsSetVirtualBase(7,HalpFirmwareVirtualBase); +} + +VOID +HalpFreeArcsResources ( + VOID + ) + +/*++ + +Routine Description: + + This routine frees the TLB entry that was reserved for the ARCS + Firmware call. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + HalpFreeTbEntry(); +} diff --git a/private/ntos/nthals/halflex/mips/dtidef.h b/private/ntos/nthals/halflex/mips/dtidef.h new file mode 100644 index 000000000..5dcbd65c8 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/dtidef.h @@ -0,0 +1,150 @@ +/*++ BUILD Version: 0005 // Increment this if a change has global effects + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + dtidef.h + +Abstract: + + This module is the header file that describes hardware addresses + for the Jazz system. + +Author: + + David N. Cutler (davec) 26-Nov-1990 + +Revision History: + +--*/ + +#ifndef _DTIDEF_ +#define _DTIDEF_ + +#include "uniflex.h" +#include "gambit.h" +#include "platform.h" + +// +// Define the data structure returned by a private vector firmware function +// that contains a set of system parameters. +// + +typedef struct PLATFORM_SPECIFIC_EXTENSION { + UCHAR PciInterruptToIsaIrq[12]; + ULONG PciVideoExpansionRomAddress; + PVOID AdvancedSetupInfo; +} PLATFORM_SPECIFIC_EXTENSION; + +typedef struct TREB13SETUPINFO { + ULONG Reserved1:16; + ULONG Drive0Type:4; + ULONG Drive1Type:4; + ULONG PciInterruptToIsaIrq0:4; + ULONG PciInterruptToIsaIrq8:4; + ULONG PciInterruptToIsaIrq1:4; + ULONG PciInterruptToIsaIrq9:4; + ULONG PciInterruptToIsaIrq2:4; + ULONG PciInterruptToIsaIrq10:4; + ULONG PciInterruptToIsaIrq3:4; + ULONG PciInterruptToIsaIrq11:4; + ULONG Lpt1Irq:8; + ULONG Lpt2Irq:8; + ULONG Lpt3Irq:8; + ULONG SerialMousePort:8; + ULONG EnableAmd1:1; + ULONG EnableAmd2:1; + ULONG EnableX86Emulator:1; + ULONG Reserved2:5; + ULONG LoadEmbeddedScsiDrivers:1; + ULONG Reserved3:7; + ULONG LoadSoftScsiDrivers:1; + ULONG LoadFlashScsiDrivers:1; + ULONG Reserved4:6; + ULONG EnableDelays:1; + ULONG Reserved5:7; + ULONG ResetDelay:8; + ULONG DetectDelay:8; + ULONG EnableIdeDriver:1; + ULONG Reserved6:7; +} TREB13SETUPINFO; + +typedef struct TREB20SETUPINFO { + ULONG Isa0Drive0Type:4; + ULONG Isa0Drive1Type:4; + ULONG Isa1Drive0Type:4; + ULONG Isa1Drive1Type:4; + ULONG SerialMousePort:8; + ULONG Isa0Lpt1Irq:8; + ULONG Isa0Lpt2Irq:8; + ULONG Isa0Lpt3Irq:8; + ULONG Isa1Lpt1Irq:8; + ULONG Isa1Lpt2Irq:8; + ULONG Isa1Lpt3Irq:8; + ULONG EnableNcr:1; + ULONG EnableX86Emulator:1; + ULONG LoadEmbeddedScsiDrivers:1; + ULONG LoadSoftScsiDrivers:1; + ULONG LoadFlashScsiDrivers:1; + ULONG EnableDelays:1; + ULONG EnableIdeDriver:1; + ULONG Reserved1:1; + ULONG ResetDelay:8; + ULONG DetectDelay:8; + ULONG PciInterruptToIsaIrq0:4; + ULONG PciInterruptToIsaIrq1:4; + ULONG PciInterruptToIsaIrq2:4; + ULONG PciInterruptToIsaIrq3:4; + ULONG PciInterruptToIsaIrq4:4; + ULONG PciInterruptToIsaIrq5:4; + ULONG PciInterruptToIsaIrq6:4; + ULONG PciInterruptToIsaIrq7:4; + ULONG PciInterruptToIsaIrq8:4; + ULONG PciInterruptToIsaIrq9:4; + ULONG NcrTermLow:1; + ULONG NcrTermHigh:1; + ULONG Reserved2:6; +} TREB20SETUPINFO; + +// +// Define the data structure used to describe all bus translations. +// + +typedef struct PLATFORM_RANGE_LIST { + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + ADDRESS_SPACE_TYPE AddressType; + ULONG SystemAddressSpace; + LONGLONG SystemBase; + LONGLONG Base; + LONGLONG Limit; +} PLATFORM_RANGE_LIST, *PPLATFORM_RANGE_LIST; + +// +// Define clock constants and clock levels. +// + +#define UNIFLEX_CLOCK_LEVEL UNIFLEX_EISA_VECTORS + 0 // Interval clock level is on ISA IRQ 0 +#define UNIFLEX_ISA_DEVICE_LEVEL 4 // ISA bus interrupt level +#define UNIFLEX_EISA_DEVICE_LEVEL 4 // EISA bus interrupt level +#define UNIFLEX_PCI_DEVICE_LEVEL 3 // PCI bus interrupt level +#define UNIFLEX_CLOCK2_LEVEL UNIFLEX_CLOCK_LEVEL + +// +// Define ISA, EISA and PCI device interrupt vectors. +// + +#define UNIFLEX_ISA_VECTORS 48 +#define UNIFLEX_MAXIMUM_ISA_VECTOR (15 + UNIFLEX_ISA_VECTORS) +#define UNIFLEX_EISA_VECTORS 48 +#define UNIFLEX_MAXIMUM_EISA_VECTOR (15 + UNIFLEX_EISA_VECTORS) +#define UNIFLEX_ISA1_VECTORS 64 +#define UNIFLEX_MAXIMUM_ISA1_VECTOR (15 + UNIFLEX_ISA1_VECTORS) +#define UNIFLEX_EISA1_VECTORS 64 +#define UNIFLEX_MAXIMUM_EISA1_VECTOR (15 + UNIFLEX_EISA1_VECTORS) +#define UNIFLEX_PCI_VECTORS 100 +#define UNIFLEX_MAXIMUM_PCI_VECTOR (15 + UNIFLEX_PCI_VECTORS) + + +#endif // _DTIDEF_ diff --git a/private/ntos/nthals/halflex/mips/flushio.c b/private/ntos/nthals/halflex/mips/flushio.c new file mode 100644 index 000000000..985601ccc --- /dev/null +++ b/private/ntos/nthals/halflex/mips/flushio.c @@ -0,0 +1,282 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1995 DeskStation Technology + +Module Name: + + flushio.c + +Abstract: + + This module implements the system dependent kernel function to flush + the data cache for I/O transfers on a MIPS R4000 Jazz system. + +Author: + + David N. Cutler (davec) 24-Apr-1991 + Michael D. Kinney 30-Apr-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + + +VOID +HalpSweepSecondaryCache( + VOID + ) + +/*++ + +Routine Description: + + This function invalidate all lines from all sets of the secondary write-through cache. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + // + // Force read to invalidate entire secondary cache + // + + READ_REGISTER_ULONG(HalpSecondaryCacheResetBase); +} + +VOID +HalFlushIoBuffers ( + IN PMDL Mdl, + IN BOOLEAN ReadOperation, + IN BOOLEAN DmaOperation + ) + +/*++ + +Routine Description: + + This function flushes the I/O buffer specified by the memory descriptor + list from the data cache on the current processor. + +Arguments: + + Mdl - Supplies a pointer to a memory descriptor list that describes the + I/O buffer location. + + ReadOperation - Supplies a boolean value that determines whether the I/O + operation is a read into memory. + + DmaOperation - Supplies a boolean value that determines whether the I/O + operation is a DMA operation. + +Return Value: + + None. + +--*/ + +{ + + ULONG CacheSegment; + ULONG Length; + ULONG Offset; + PULONG PageFrame; + ULONG Source; + + // + // The Jazz R4000 uses a write back data cache and, therefore, must be + // flushed on reads and writes. + // + // If the length of the I/O operation is greater than the size of the + // data cache, then sweep the entire data cache. Otherwise, export or + // purge individual pages from the data cache as appropriate. + // + + Offset = Mdl->ByteOffset & PCR->DcacheAlignment; + Length = (Mdl->ByteCount + + PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment; + + if (Length > PCR->FirstLevelDcacheSize) { + + // + // If the I/O operation is a DMA operation, or the I/O operation is + // not a DMA operation and the I/O operation is a page read operation, + // then sweep (index/writeback/invalidate) the entire data cache. + // + + if ((DmaOperation != FALSE) || + ((DmaOperation == FALSE) && + (ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) { + HalSweepDcache(); + } + + // + // If the I/O operation is a page read, then sweep (index/invalidate) + // the entire instruction cache. + // + + if ((ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) { + HalSweepIcache(); + } + + // + // Maintain Secondary Caches only on DMA Read Operations + // + + if (HalpPlatformParameterBlock->External.UnifiedCache.Size>0 && + ReadOperation!=FALSE && + DmaOperation!=FALSE) { + + // + // See if the transfer length is larger than the size of the secondary cache + // + + if (Length > HalpPlatformParameterBlock->External.UnifiedCache.Size) { + // + // Do a fast invalidate of all tags in all sets of the secondary cache + // + + HalpSweepSecondaryCache(); + } else { + + // + // Walk MDL and do hit/invalidate cycles on the secondary cache + // + + Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment; + PageFrame = (PULONG)(Mdl + 1); + Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset; + + do { + if (Length >= (PAGE_SIZE - Offset)) { + CacheSegment = PAGE_SIZE - Offset; + } else { + CacheSegment = Length; + } + + HalpInvalidateSecondaryCachePage((PVOID)Source, *PageFrame, CacheSegment); + + PageFrame += 1; + Length -= CacheSegment; + Offset = 0; + Source += CacheSegment; + } while(Length != 0); + } + } + + } else { + + // + // Export or purge the specified pages from the data cache and + // instruction caches as appropriate. + // + // Compute the number of pages to flush and the starting MDL page + // frame address. + // + + Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment; + PageFrame = (PULONG)(Mdl + 1); + Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset; + + // + // Export or purge the specified page segments from the data and + // instruction caches as appropriate. + // + + do { + + if (Length >= (PAGE_SIZE - Offset)) { + CacheSegment = PAGE_SIZE - Offset; + } else { + CacheSegment = Length; + } + + if (ReadOperation == FALSE) { + + // + // The I/O operation is a write and the data only needs to + // to be copied back into memory if the operation is also + // a DMA operation. + // + + if (DmaOperation != FALSE) { + HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + + } else { + + // + // If the I/O operation is a DMA operation, then purge the + // data cache. Otherwise, is the I/O operation is a page read + // operation, then export the data cache. + // + + if (DmaOperation != FALSE) { + HalPurgeDcachePage((PVOID)Source, *PageFrame, CacheSegment); + if (HalpPlatformParameterBlock->External.UnifiedCache.Size>0) { + HalpInvalidateSecondaryCachePage((PVOID)Source, *PageFrame, CacheSegment); + } + } else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) { + HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + + // + // If the I/O operation is a page read, then the instruction + // cache must be purged. + // + + if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) { + HalPurgeIcachePage((PVOID)Source, *PageFrame, CacheSegment); + } + } + + PageFrame += 1; + Length -= CacheSegment; + Offset = 0; + Source += CacheSegment; + + } while(Length != 0); + } + return; +} + +ULONG +HalGetDmaAlignmentRequirement ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the alignment requirements for DMA transfers on + host system. + +Arguments: + + None. + +Return Value: + + The DMA alignment requirement is returned as the fucntion value. + +--*/ + +{ + return PCR->DcacheFillSize; +} diff --git a/private/ntos/nthals/halflex/mips/gambit.h b/private/ntos/nthals/halflex/mips/gambit.h new file mode 100644 index 000000000..7356d16cd --- /dev/null +++ b/private/ntos/nthals/halflex/mips/gambit.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 1995 DeskStation Technology + +Module Name: + + gambit.h + +Abstract: + + This file contains definitions specific to the Gambit (MIPS R4600) + processor module. + +Author: + + Michael D. Kinney 31-Aug-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +// +// Define physical base addresses for system mapping. +// + +#define TREB1_GAMBIT_ISA_IO_BASE_PHYSICAL (LONGLONG)0x200000000 // ISA I/O Base Address +#define TREB1_GAMBIT_ISA_MEMORY_BASE_PHYSICAL (LONGLONG)0x000000000 // ISA Memory Base Address +#define TREB1_GAMBIT_ISA1_IO_BASE_PHYSICAL (LONGLONG)0xa00000000 // ISA I/O Base Address +#define TREB1_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL (LONGLONG)0x800000000 // ISA Memory Base Address +#define TREB1_GAMBIT_PCI_IO_BASE_PHYSICAL (LONGLONG)0xa00000000 // PCI I/O Base Address +#define TREB1_GAMBIT_PCI_MEMORY_BASE_PHYSICAL (LONGLONG)0x800000000 // PCI Memory Base Address + +#define TREB2_GAMBIT_ISA_IO_BASE_PHYSICAL (LONGLONG)0xa00000000 // ISA I/O Base Address +#define TREB2_GAMBIT_ISA_MEMORY_BASE_PHYSICAL (LONGLONG)0x800000000 // ISA Memory Base Address +#define TREB2_GAMBIT_ISA1_IO_BASE_PHYSICAL (LONGLONG)0x200000000 // ISA I/O Base Address +#define TREB2_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL (LONGLONG)0x000000000 // ISA Memory Base Address +#define TREB2_GAMBIT_PCI_IO_BASE_PHYSICAL (LONGLONG)0xa00000000 // PCI I/O Base Address +#define TREB2_GAMBIT_PCI_MEMORY_BASE_PHYSICAL (LONGLONG)0x800000000 // PCI Memory Base Address +#define TREB2_GAMBIT_PCI1_IO_BASE_PHYSICAL (LONGLONG)0x200000000 // PCI I/O Base Address +#define TREB2_GAMBIT_PCI1_MEMORY_BASE_PHYSICAL (LONGLONG)0x000000000 // PCI Memory Base Address + +#define GAMBIT_PCI_CONFIG0_BASE_PHYSICAL (LONGLONG)0xb00000000 // PCI Config Type 0 Base Address +#define GAMBIT_PCI_CONFIG1_BASE_PHYSICAL (LONGLONG)0xc00000000 // PCI Config Type 1 Base Address +#define GAMBIT_PCI_INTERRUPT_BASE_PHYSICAL (LONGLONG)0x500000000 // PCI Interrupt Register Base Address +#define GAMBIT_SECONDARY_CACHE_RESET_BASE_PHYSICAL (LONGLONG)0x700000000 // Secondary Cache Reset Register Base Address +#define GAMBIT_SECONDARY_CACHE_INVALIDATE_PHYSICAL_BASE (LONGLONG)0x600000000 // Secondary Cache Invalidate Base Address +#define GAMBIT_PFN_SECONDARY_CACHE_INVALIDATE_PHYSICAL_BASE 0x00600000 // PFN version of Secondary Cache Invalidate Base Address +#define GAMBIT_DMA_CACHE_BASE_PHYSICAL (LONGLONG)0x001c0000 // DMA Cache Base Address +#define GAMBIT_DMA_CACHE_SIZE 0x00040000 // Size of DMA Cache in bytes - 256 KB diff --git a/private/ntos/nthals/halflex/mips/info.c b/private/ntos/nthals/halflex/mips/info.c new file mode 100644 index 000000000..f9abd9d6d --- /dev/null +++ b/private/ntos/nthals/halflex/mips/info.c @@ -0,0 +1,116 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation +Copyright (c) 1994 Digital Equipment Corporation + +Module Name: + + info.c + +Abstract: + +Author: + + Ken Reneris (kenr) 08-Aug-1994 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "halp.h" + +#ifdef _PNP_POWER_ +HAL_CALLBACKS HalCallback; +#endif // _PNP_POWER_ + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HaliQuerySystemInformation) +#pragma alloc_text(PAGE,HaliSetSystemInformation) +#endif + + +NTSTATUS +HaliQuerySystemInformation( + IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + OUT PVOID Buffer, + OUT PULONG ReturnedLength + ) +/*++ + +Routine Description: + + The function returns system-wide information controlled by the HAL for a + variety of classes. + +Arguments: + + InformationClass - Information class of the request. + + BufferSize - Size of buffer supplied by the caller. + + Buffer - Supplies the space to store the data. + + ReturnedLength - Supplies a count in bytes of the amount of data returned. + +Return Value: + + STATUS_SUCCESS or error. + +--*/ +{ + NTSTATUS Status; + + switch (InformationClass) { + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return(Status); +} + +NTSTATUS +HaliSetSystemInformation ( + IN HAL_SET_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN PVOID Buffer + ) +/*++ + +Routine Description: + + The function allows setting of various fields return by + HalQuerySystemInformation. + +Arguments: + + InformationClass - Information class of the request. + + BufferSize - Size of buffer supplied by the caller. + + Buffer - Supplies the data to be set. + +Return Value: + + STATUS_SUCCESS or error. + +--*/ +{ + NTSTATUS Status; + + switch (InformationClass) { + + default: + Status = STATUS_INVALID_LEVEL; + break; + } + + return Status; +} diff --git a/private/ntos/nthals/halflex/mips/initsys.c b/private/ntos/nthals/halflex/mips/initsys.c new file mode 100644 index 000000000..e23d422c6 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/initsys.c @@ -0,0 +1,405 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + initsys.c + +Abstract: + + This module implements the platform specific potions of the + HAL initialization. + +Author: + + Michael D. Kinney 3-May-1995 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +// +// The WINNT350 define is used to remove memory from the MDL passed in +// from the loader block. This is required because Windows NT 3.50 had +// some problems with holes in the MDL. This problem was fixed for +// Windows NT 3.51. +// + +//#define WINNT350 + +ULONG HalpIoArchitectureType = UNKNOWN_PROCESSOR_MODULE; + +ULONG IoSpaceAlreadyMapped = FALSE; +UCHAR HalpSecondPciBridgeBusNumber = 2; +ULONG HalpMotherboardType = MOTHERBOARD_UNKNOWN; +UCHAR *HalpInterruptLineToBit; +UCHAR *HalpBitToInterruptLine; +UCHAR *HalpInterruptLineToVirtualIsa; +UCHAR *HalpVirtualIsaToInterruptLine; +ULONGLONG HalpPciConfig0BasePhysical; +ULONGLONG HalpPciConfig1BasePhysical; +ULONGLONG HalpIsaIoBasePhysical; +ULONGLONG HalpIsa1IoBasePhysical; +ULONGLONG HalpIsaMemoryBasePhysical; +ULONGLONG HalpIsa1MemoryBasePhysical; +ULONGLONG HalpPciIoBasePhysical; +ULONGLONG HalpPci1IoBasePhysical; +ULONGLONG HalpPciMemoryBasePhysical; +ULONGLONG HalpPci1MemoryBasePhysical; +PPLATFORM_RANGE_LIST HalpRangeList = NULL; +ULONG HalpIntel82378BusNumber = 0; +ULONG HalpIntel82378DeviceNumber = 0; +ULONG HalpSecondIntel82378DeviceNumber = 0; +ULONG HalpNonExistentPciDeviceMask = ~TREB20_MOTHERBOARD_PCI_DEVICE_MASK; +ULONG HalpNonExistentPci1DeviceMask = 0; +ULONG HalpNonExistentPci2DeviceMask = 0; +ULONG HalpNumberOfIsaBusses; +ULONG HalpVgaDecodeBusNumber; + +// +// Function prototypes. +// + +VOID +HalpGetPlatformParameterBlock( + VOID + ); + +ULONG FindIntel82378(ULONG Dec2105xBusNumber,ULONG Dec2105xDeviceNumber,ULONG BusNumber,ULONG IsaBusNumber) + +{ + ULONG i; + ULONG MaxDevice; + + if (BusNumber == 0) { + MaxDevice = PCI_MAX_LOCAL_DEVICE; + } else { + MaxDevice = 31; + } + for(i=0;i<=MaxDevice;i++) { + if (HalpPciLowLevelConfigRead(BusNumber,i,0,0) == 0x04848086) { + return(i); + } + } + return(0); + } + +VOID +HalpGetIoArchitectureType( + VOID + ) + +/*++ + +Routine Description: + + This function gets the I/O Architecture Type from the Platform Parameter Block + retrieved from the firmware. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG Device16; + ULONG Device17; + + // + // If the I/O Architecture Type is already known, then just return. + // + + if (HalpIoArchitectureType != UNKNOWN_PROCESSOR_MODULE) { + return; + } + + // + // If the Platform Parameter Block has not been retrieved from the firmware, + // then do it now. + // + + if (HalpPlatformParameterBlock == NULL) { + HalpGetPlatformParameterBlock(); + } + + // + // Check for the R4600 Gambit Module Type. + // + + if (strcmp(HalpPlatformParameterBlock->ModuleName,"GAMBIT2.0")==0) { + HalpIoArchitectureType = R4600_PROCESSOR_MODULE; + } + + // + // If the I/O Architecture Type is still unknown then HALT. + // + + if (HalpIoArchitectureType == UNKNOWN_PROCESSOR_MODULE) { + for(;;); + } + + HalpPciConfig0BasePhysical = GAMBIT_PCI_CONFIG0_BASE_PHYSICAL; + HalpPciConfig1BasePhysical = GAMBIT_PCI_CONFIG1_BASE_PHYSICAL; + + // + // Determine the motherboard type. Assume TREBBIA20 so we can do some config cycles. + // + + HalpMotherboardType = TREBBIA20; + + Device16 = HalpPciLowLevelConfigRead(0,0x10,0,0); + Device17 = HalpPciLowLevelConfigRead(0,0x11,0,0); + + // + // Now assume motherboard type is unknown and check out values returned from config cycles. + // + + HalpMotherboardType = MOTHERBOARD_UNKNOWN; + + if (Device16 == 0x00211011 && Device17 == 0x00211011) { + HalpMotherboardType = TREBBIA20; + + // + // Find and initialize up to two Jubilee adapters. + // + + HalpNumberOfIsaBusses = 1; + HalpIntel82378BusNumber = 1; + HalpIntel82378DeviceNumber = FindIntel82378(0,0x11,1,0); + HalpSecondPciBridgeBusNumber = (UCHAR)((HalpPciLowLevelConfigRead(0,0x10,0,0x18) >> 8) & 0xff); + HalpSecondIntel82378DeviceNumber = FindIntel82378(0,0x10,HalpSecondPciBridgeBusNumber,1); + if (HalpSecondIntel82378DeviceNumber != 0) { + HalpNumberOfIsaBusses = 2; + } + HalpVgaDecodeBusNumber = 0x00; + if (HalpPciLowLevelConfigRead(0,0x11,0,0x3c) & 0x00080000) { + HalpVgaDecodeBusNumber |= 0x01; + } + if (HalpPciLowLevelConfigRead(0,0x10,0,0x3c) & 0x00080000) { + HalpVgaDecodeBusNumber |= 0x02; + } + } + + if (Device16 == 0x04848086 && Device17 == 0x00011011) { + HalpMotherboardType = TREBBIA13; + HalpNumberOfIsaBusses = 1; + HalpIntel82378BusNumber = 0; + HalpIntel82378DeviceNumber = 0x10; + HalpVgaDecodeBusNumber = 0x01; + if (HalpPciLowLevelConfigRead(0,0x11,0,0x3c) & 0x00080000) { + HalpVgaDecodeBusNumber |= 0x02; + } + } + + // + // If the Motherboard Type is unknown then HALT. + // + + if (HalpMotherboardType == MOTHERBOARD_UNKNOWN) { + for(;;); + } + + // + // Determine the base physical addresses and PCI interrupt translation tables. + // + + if (HalpMotherboardType == TREBBIA13) { + HalpIsaIoBasePhysical = TREB1_GAMBIT_ISA_IO_BASE_PHYSICAL; + HalpIsa1IoBasePhysical = (ULONGLONG)(0); + HalpIsaMemoryBasePhysical = TREB1_GAMBIT_ISA_MEMORY_BASE_PHYSICAL; + HalpIsa1MemoryBasePhysical = (ULONGLONG)(0); + HalpPciIoBasePhysical = TREB1_GAMBIT_PCI_IO_BASE_PHYSICAL; + HalpPci1IoBasePhysical = (ULONGLONG)(0); + HalpPciMemoryBasePhysical = TREB1_GAMBIT_PCI_MEMORY_BASE_PHYSICAL; + HalpPci1MemoryBasePhysical = (ULONGLONG)(0); + HalpRangeList = Gambit20Trebbia13RangeList; + HalpNonExistentPciDeviceMask = ~TREB13_MOTHERBOARD_PCI_DEVICE_MASK; + HalpNonExistentPci1DeviceMask = 0; + HalpNonExistentPci2DeviceMask = 0; + HalpInterruptLineToBit = Treb13InterruptLineToBit; + HalpBitToInterruptLine = Treb13BitToInterruptLine; + HalpInterruptLineToVirtualIsa = Treb13InterruptLineToVirtualIsa; + HalpVirtualIsaToInterruptLine = Treb13VirtualIsaToInterruptLine; + if (HalpPlatformParameterBlock->FirmwareRevision >= 50) { + if (!((TREB13SETUPINFO *)(HalpPlatformSpecificExtension->AdvancedSetupInfo))->EnableAmd1) { + HalpNonExistentPciDeviceMask |= (1 << 0x0d); + } + if (!((TREB13SETUPINFO *)(HalpPlatformSpecificExtension->AdvancedSetupInfo))->EnableAmd2) { + HalpNonExistentPciDeviceMask |= (1 << 0x0f); + } + } + } + if (HalpMotherboardType == TREBBIA20) { + HalpIsaIoBasePhysical = TREB2_GAMBIT_ISA_IO_BASE_PHYSICAL; + HalpIsa1IoBasePhysical = TREB2_GAMBIT_ISA1_IO_BASE_PHYSICAL; + HalpIsaMemoryBasePhysical = TREB2_GAMBIT_ISA_MEMORY_BASE_PHYSICAL; + HalpIsa1MemoryBasePhysical = TREB2_GAMBIT_ISA1_MEMORY_BASE_PHYSICAL; + HalpPciIoBasePhysical = TREB2_GAMBIT_PCI_IO_BASE_PHYSICAL; + HalpPci1IoBasePhysical = TREB2_GAMBIT_PCI1_IO_BASE_PHYSICAL; + HalpPciMemoryBasePhysical = TREB2_GAMBIT_PCI_MEMORY_BASE_PHYSICAL; + HalpPci1MemoryBasePhysical = TREB2_GAMBIT_PCI1_MEMORY_BASE_PHYSICAL; + HalpRangeList = Gambit20Trebbia20RangeList; + HalpNonExistentPciDeviceMask = ~TREB20_MOTHERBOARD_PCI_DEVICE_MASK; + HalpNonExistentPci1DeviceMask = 0; + HalpNonExistentPci2DeviceMask = 0; + HalpInterruptLineToBit = Treb20InterruptLineToBit; + HalpBitToInterruptLine = Treb20BitToInterruptLine; + HalpInterruptLineToVirtualIsa = Treb20InterruptLineToVirtualIsa; + HalpVirtualIsaToInterruptLine = Treb20VirtualIsaToInterruptLine; + if (HalpPlatformParameterBlock->FirmwareRevision >= 50) { + if (!((TREB20SETUPINFO *)(HalpPlatformSpecificExtension->AdvancedSetupInfo))->EnableNcr) { + HalpNonExistentPci2DeviceMask |= (1 << 0x07); + } + } + } + + // + // If the address translation table is still NULL then HALT. + // + + if (HalpRangeList == NULL) { + for(;;); + } +} + +BOOLEAN +HalpInitSystem ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This function initializes the Hardware Architecture Layer (HAL). + +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. + +--*/ + +{ +#ifdef WINNT350 + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY NextMd; + PLIST_ENTRY DeleteMd; +#endif + + if (Phase == 0) { + + // + // Phase 0 initialization. + // + + HalpGetIoArchitectureType(); + + // + // Set the number of process id's and TB entries. + // + + **((PULONG *)(&KeNumberProcessIds)) = 256; + **((PULONG *)(&KeNumberTbEntries)) = 48; + +#ifdef WINNT350 + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { + Descriptor = CONTAINING_RECORD( NextMd, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry ); + // + // If Descriptor is >256 MB then remove it for NT 3.5. + // This problem was fixed in NT 3.51. + // + + DeleteMd = NextMd; + NextMd = Descriptor->ListEntry.Flink; + if ((Descriptor->BasePage + Descriptor->PageCount) >= ((256*1024*1024)/4096)) { + + // + // Delete Descriptor + // + + RemoveEntryList(DeleteMd); + } + + } +#endif + + // + // Initialize Dma Cache Parameters + // + + HalpMapBufferSize = GAMBIT_DMA_CACHE_SIZE; + HalpMapBufferPhysicalAddress.QuadPart = GAMBIT_DMA_CACHE_BASE_PHYSICAL; + + return TRUE; + + } else { + + UCHAR Message[80]; + + // + // Phase 1 initialization. + // + + HalpMapIoSpace(); + + // + // Initialize the existing bus handlers. + // + + HalpRegisterInternalBusHandlers(); + + // + // Initialize the PCI bus. + // + + HalpInitializePCIBus (); + + // + // Initialize the display adapter. + // + + if (IoSpaceAlreadyMapped == FALSE) { + HalpInitializeX86DisplayAdapter(); + IoSpaceAlreadyMapped = TRUE; + } + + if (HalpMotherboardType == TREBBIA13) { + HalDisplayString("DeskStation Technology UniFlex/Raptor 3 Motherboard Rev. 1\n\r"); + } else { + HalDisplayString("DeskStation Technology Raptor ReFlex Motherboard Rev. 2\n\r"); + } + + HalDisplayString("DeskStation Technology MIPS R4600 Processor Module\n\r"); + + HalpCreateDmaStructures(); + + HalpCalibrateStall(); + + return TRUE; + } +} diff --git a/private/ntos/nthals/halflex/mips/intsup.c b/private/ntos/nthals/halflex/mips/intsup.c new file mode 100644 index 000000000..9ef7a4e98 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/intsup.c @@ -0,0 +1,240 @@ +/*++ + +Copyright (c) 1995 DeskStation Technology + +Module Name: + + intsup.c + +Abstract: + + This module implements the HAL enable/disable system interrupt for + platform specific vectors. + +Author: + + Michael D. Kinney 14-May-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + +VOID +HalpDisablePlatformInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) + +/*++ + +Routine Description: + + This routine disables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is disabled. + + Irql - Supplies the IRQL of the interrupting source. + +Return Value: + + None. + +--*/ + +{ + // + // There are no additional interrupts for MIPS processors + // + + return; +} + + +BOOLEAN +HalpEnablePlatformInterrupt ( + IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is enabled. + + Irql - Supplies the IRQL of the interrupting source. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + TRUE if the system interrupt was enabled + +--*/ + +{ + // + // There are no additional interrupts for MIPS processors + // + + return FALSE; +} + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +/*++ + +Routine Description: + + This function returns the system interrupt vector and IRQL level + corresponding to the specified bus interrupt level and/or vector. The + system interrupt vector and IRQL are suitable for use in a subsequent call + to KeInitializeInterrupt. + + We only use InterfaceType, and BusInterruptLevel. BusInterruptVector + for ISA and EISA are the same as the InterruptLevel, so ignore. + +Arguments: + + BusHandler - Registered BUSHANDLER for the target configuration space + + RootHandler - Registered BUSHANDLER for the orginating HalGetBusData + request. + + BusInterruptLevel - Supplies the bus specific interrupt level. + + BusInterruptVector - Supplies the bus specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the affinity for the requested vector + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +{ + INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType; + ULONG BusNumber = BusHandler->BusNumber; + + ULONG Vector; + + *Affinity = 1; + + if ( (InterfaceType==PCI_BUS && BusInterruptLevel>=0x0 && BusInterruptLevel<=0x0f) || + (HalpMotherboardType==TREBBIA13 && InterfaceType==Isa && BusNumber==1) ) { + + ULONG i; + + for(i=0;i<12;i++) { + if (BusInterruptLevel == HalpPlatformSpecificExtension->PciInterruptToIsaIrq[i]) { + + *Irql = UNIFLEX_PCI_DEVICE_LEVEL; + + BusInterruptLevel = HalpVirtualIsaInterruptToInterruptLine(i) - 0x10; + + return(BusInterruptLevel + UNIFLEX_PCI_VECTORS); + } + } + + // + // Unrecognized interrupt + // + + *Irql = 0; + *Affinity = 0; + return(0); + + } else if (InterfaceType == PCIBus && BusInterruptLevel >= 0x10) { + + // + // Assumes all PCI devices coming in on same pin + // + + *Irql = UNIFLEX_PCI_DEVICE_LEVEL; + + BusInterruptLevel -= 0x10; + + // + // The vector is equal to the specified bus level plus the PCI_VECTOR. + // + + return(BusInterruptLevel + UNIFLEX_PCI_VECTORS); + + } else if (InterfaceType == Isa) { + + // + // Assumes all ISA devices coming in on same pin + // + + *Irql = UNIFLEX_ISA_DEVICE_LEVEL; + + // + // The vector is equal to the specified bus level plus the ISA_VECTOR. + // This is assuming that the ISA levels not assigned Interrupt Levels + // in the Beta programming guide are unused in the LCA system. + // Otherwise, need a different encoding scheme. + // + // Not all interrupt levels are actually supported on Beta; + // Should we make some of them illegal here? + + if (BusNumber == 0) { + return(BusInterruptLevel + UNIFLEX_ISA_VECTORS); + } + if (BusNumber == 1) { + return(BusInterruptLevel + UNIFLEX_ISA1_VECTORS); + } + } else if (InterfaceType == Eisa) { + + // + // Assumes all EISA devices coming in on same pin + // + + *Irql = UNIFLEX_EISA_DEVICE_LEVEL; + + // + // The vector is equal to the specified bus level plus the EISA_VECTOR. + // + + if (BusNumber == 0) { + return(BusInterruptLevel + UNIFLEX_EISA_VECTORS); + } + if (BusNumber == 1) { + return(BusInterruptLevel + UNIFLEX_EISA1_VECTORS); + } + + } else { + + // + // Not an interface supported on EB64P systems + // + + *Irql = 0; + *Affinity = 0; + return(0); + } +} diff --git a/private/ntos/nthals/halflex/mips/j4cache.s b/private/ntos/nthals/halflex/mips/j4cache.s new file mode 100644 index 000000000..d50bd2ba5 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/j4cache.s @@ -0,0 +1,1091 @@ +#if defined(R4000) + +// TITLE("Cache Flush") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Module Name: +// +// j4cache.s +// +// Abstract: +// +// This module implements the code necessary for cache operations on +// a MIPS R4000. +// +// Author: +// +// David N. Cutler (davec) 19-Dec-1991 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" +#include "gambit.h" + + +// +// Define cache operations constants. +// + +#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache) +#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache) +#define FLUSH_BASE 0xfffe0000 // flush base address +#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D)) // + + SBTTL("Change Color Page") +//++ +// +// VOID +// HalChangeColorPage ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function changes the color of a page if the old and new colors +// do not match. +// +// The algorithm used to change colors for a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page to change. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page to change. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is changed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +CpRa: .space 4 // saved return address +CpFrameLength: // length of stack frame +CpA0: .space 4 // (a0) +CpA1: .space 4 // (a1) +CpA2: .space 4 // (a2) +CpA3: .space 4 // (a3) + + NESTED_ENTRY(HalChangeColorPage, CpFrameLength, zero) + + subu sp,sp,CpFrameLength // allocate stack frame + sw ra,CpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + beq a0,a1,10f // if eq, colors match + sw a1,CpA1(sp) // save old color bits + sw a2,CpA2(sp) // save page frame + +// +// Purge the instruction cache using the old page color. +// + + move a0,a1 // set color value + move a1,a2 // set page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeIcachePage // purge instruction cache page + +// +// Flush the data cache using the old page color. +// + + lw a0,CpA1(sp) // get old color bits + lw a1,CpA2(sp) // get page frame number + li a2,PAGE_SIZE // set length of purge + jal HalFlushDcachePage // purge data cache page +10: lw ra,CpRa(sp) // get return address + addu sp,sp,CpFrameLength // deallocate stack frame + j ra // return + + .end HalChangeColorPage + + SBTTL("Flush Data Cache Page") +//++ +// +// VOID +// HalFlushDcachePage ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function flushes (hit/writeback/invalidate) up to a page of data +// from the data cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is flushed. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is flushed. +// +// Length (a2) - Supplies the length of the region in the page that is +// flushed. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalFlushDcachePage) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color and offset bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set flush block size + .set at + .set reorder + +// +// Flush a page from the data cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to flush + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Flush the primary data cache only. +// + +20: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Flush the primary and secondary data caches. +// + + .set noreorder + .set noat +40: cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalFlushDcachePage + + SBTTL("Purge Data Cache Page") +//++ +// +// VOID +// HalPurgeDcachePage ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page of data from the +// data cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalPurgeDcachePage) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set purge block size + .set at + .set reorder + +// +// Purge data from the data cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary data cache only. +// + +20: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Purge the primary and secondary data caches. +// + + .set noreorder + .set noat +40: cache HIT_INVALIDATE_SD,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalPurgeDcachePage + + SBTTL("Purge Instruction Cache Page") +//++ +// +// VOID +// HalPurgeIcachePage ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page fo data from the +// instruction cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalPurgeIcachePage) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size + lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size + bnel zero,v0,15f // if ne, second level cache present + move t4,v0 // set purge block size + .set at + .set reorder + +// +// Purge data from the instruction cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + bne zero,v0,40f // if ne, second level cache present + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary instruction cache only. +// + +20: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + +// +// Purge the primary and secondary instruction caches. +// + + .set noreorder + .set noat +40: cache HIT_INVALIDATE_SI,0(t8) // invalidate cache block + bne t8,t9,40b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalPurgeIcachePage + + SBTTL("Sweep Data Cache") +//++ +// +// VOID +// HalSweepDcache ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the entire data cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepDcache) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + DISABLE_INTERRUPTS(t5) // disable interrupts + + lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the primary data cache. +// + + .set noreorder + .set noat +10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index + cache INDEX_WRITEBACK_INVALIDATE_D,0x2000(a0) // writeback/invalidate on index ORION + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + + lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size + lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size + beq zero,t1,30f // if eq, no second level cache + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the secondary data cache. +// + + .set noreorder + .set noat +20: cache INDEX_WRITEBACK_INVALIDATE_SD,0(a0) // writeback/invalidate on index + bne a0,a1,20b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + +30: + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalSweepDcache + + SBTTL("Sweep Data Cache Range") +//++ +// +// VOID +// HalSweepDcacheRange ( +// IN PVOID BaseAddress, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function sweeps (index/writeback/invalidate) the specified range +// of virtual addresses from the primary data cache. +// +// Arguments: +// +// BaseAddress (a0) - Supplies the base address of the range that is swept +// from the data cache. +// +// Length (a1) - Supplies the length of the range that is swept from the +// data cache. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepDcacheRange) + +#if DBG + + lw t0,KeDcacheFlushCount // get address of dcache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result conditionally + +#endif + + DISABLE_INTERRUPTS(t5) // disable interrupts + + and a0,a0,COLOR_MASK // isolate color and offset bits + or a0,a0,KSEG0_BASE // convert to physical address + lw t0,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size + addu a1,a0,a1 // compute ending cache address + subu a1,a1,t0 // compute ending block address + +// +// Sweep the primary data cache. +// + + .set noreorder + .set noat +10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index + cache INDEX_WRITEBACK_INVALIDATE_D,0x2000(a0) // writeback/invalidate on index ORION + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t0 // compute address of next block + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalSweepDcacheRange + + SBTTL("Sweep Instruction Cache") +//++ +// +// VOID +// HalSweepIcache ( +// VOID +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the entire instruction cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepIcache) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + DISABLE_INTERRUPTS(t5) // disable interrupts + + lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size + beq zero,t1,20f // if eq, no second level cache + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the secondary instruction cache. +// + + .set noreorder + .set noat +10: cache INDEX_INVALIDATE_SI,0(a0) // invalidate cache line + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + +20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size + lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + li a0,KSEG0_BASE // set starting index value + addu a1,a0,t0 // compute ending cache address + subu a1,a1,t1 // compute ending block address + +// +// Sweep the primary instruction cache. +// + + .set noreorder + .set noat +30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + cache INDEX_INVALIDATE_I,0x2000(a0) // invalidate cache line ORION + bne a0,a1,30b // if ne, more to invalidate + addu a0,a0,t1 // compute address of next block + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalSweepIcache + + SBTTL("Sweep Instruction Cache Range") +//++ +// +// VOID +// HalSweepIcacheRange ( +// IN PVOID BaseAddress, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function sweeps (index/invalidate) the specified range of addresses +// from the instruction cache. +// +// Arguments: +// +// BaseAddress (a0) - Supplies the base address of the range that is swept +// from the instruction cache. +// +// Length (a1) - Supplies the length of the range that is swept from the +// instruction cache. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalSweepIcacheRange) + +#if DBG + + lw t0,KeIcacheFlushCount // get address of icache flush count + lw t1,0(t0) // increment the count of flushes + addu t1,t1,1 // + sw t1,0(t0) // store result + +#endif + + DISABLE_INTERRUPTS(t5) // disable interrupts + + and a0,a0,COLOR_MASK // isolate color and offset bits + or a0,a0,KSEG0_BASE // convert to physical address + lw t0,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size + addu a1,a0,a1 // compute ending cache address + subu a1,a1,t0 // compute ending block address + +// +// Sweep the primary instruction cache. +// + + .set noreorder + .set noat +10: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line + cache INDEX_INVALIDATE_I,0x2000(a0) // invalidate cache line ORION + bne a0,a1,10b // if ne, more to invalidate + addu a0,a0,t0 // compute address of next block + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalSweepIcacheRange + + SBTTL("Zero Page") +//++ +// +// VOID +// HalZeroPage ( +// IN PVOID NewColor, +// IN PVOID OldColor, +// IN ULONG PageFrame +// ) +// +// Routine Description: +// +// This function zeros a page of memory. +// +// The algorithm used to zero a page is as follows: +// +// 1. Purge (hit/invalidate) the page from the instruction cache +// using the old color iff the old color is not the same as +// the new color. +// +// 2. Purge (hit/invalidate) the page from the data cache using +// the old color iff the old color is not the same as the new +// color. +// +// 3. Create (create/dirty/exclusive) the page in the data cache +// using the new color. +// +// 4. Write zeros to the page using the new color. +// +// Arguments: +// +// NewColor (a0) - Supplies the page aligned virtual address of the +// new color of the page that is zeroed. +// +// OldColor (a1) - Supplies the page aligned virtual address of the +// old color of the page that is zeroed. +// +// PageFrame (a2) - Supplies the page frame number of the page that +// is zeroed. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 3 * 4 // fill +ZpRa: .space 4 // saved return address +ZpFrameLength: // length of stack frame +ZpA0: .space 4 // (a0) +ZpA1: .space 4 // (a1) +ZpA2: .space 4 // (a2) +ZpA3: .space 4 // (a3) + + NESTED_ENTRY(HalZeroPage, ZpFrameLength, zero) + + subu sp,sp,ZpFrameLength // allocate stack frame + sw ra,ZpRa(sp) // save return address + + PROLOGUE_END + + and a0,a0,COLOR_BITS // isolate new color bits + and a1,a1,COLOR_BITS // isolate old color bits + sw a0,ZpA0(sp) // save new color bits + sw a1,ZpA1(sp) // save old color bits + sw a2,ZpA2(sp) // save page frame + +// +// Purge the instruction cache using the old page color iff the old page +// color is not equal to the new page color. +// + + beq a0,a1,10f // if eq, colors match + move a0,a1 // set old color value + move a1,a2 // set page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeIcachePage // purge instruction cache page + +// +// Purge the data cache using the old page color iff the old page color is +// not equal to the new page color. +// + + lw a0,ZpA1(sp) // get old color value + lw a1,ZpA2(sp) // get page frame number + li a2,PAGE_SIZE // set length of purge + jal HalPurgeDcachePage // purge data cache page + +// +// Create dirty exclusive cache blocks and zero the data. +// + +10: lw a3,ZpA0(sp) // get new color bits + lw a1,ZpA2(sp) // get page frame number + + .set noreorder + .set noat + lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache polciy + li t0,FLUSH_BASE // get base flush address + or t0,t0,a3 // compute new color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a3,a3,0x1000 // isolate TB entry index + beql zero,a3,20f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +20: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size + lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size + .set at + .set reorder + + DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + addu t9,t0,PAGE_SIZE // compute ending address of block + dmtc1 zero,f0 // set write pattern + bne zero,v0,50f // if ne, second level cache present + and t8,t4,0x10 // test if 16-byte cache block + +// +// Zero page in primary data cache only. +// + +30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block + addu t0,t0,t4 // compute next block address + bne zero,t8,40f // if ne, 16-byte cache line + sdc1 f0,-16(t0) // + sdc1 f0,-24(t0) // zero 16 bytes + sdc1 f0,-32(t0) // +40: bne t0,t9,30b // if ne, more blocks to zero + sdc1 f0,-8(t0) // zero 16 bytes + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + +// +// Zero page in primary and secondary data caches. +// + + .set noreorder + .set noat +50: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create secondary cache block + addu v1,v0,t0 // compute ending primary block address +60: addu t0,t0,t4 // compute next block address + bne zero,t8,70f // if ne, 16-byte primary cache line + sdc1 f0,-16(t0) // + sdc1 f0,-24(t0) // zero 16 bytes + sdc1 f0,-32(t0) // +70: bne t0,v1,60b // if ne, more primary blocks to zero + sdc1 f0,-8(t0) // zero 16 bytes + bne t0,t9,50b // if ne, more secondary blocks to zero + nop // fill + .set at + .set reorder + + ENABLE_INTERRUPTS(t5) // enable interrupts + + lw ra,ZpRa(sp) // get return address + addu sp,sp,ZpFrameLength // deallocate stack frame + j ra // return + + .end HalZeroPage + + SBTTL("Invalidate Secondary Cache Page") +//++ +// +// VOID +// HalpInvalidateSecondaryCachePage ( +// IN PVOID Color, +// IN ULONG PageFrame, +// IN ULONG Length +// ) +// +// Routine Description: +// +// This function purges (hit/invalidate) up to a page fo data from the +// instruction cache. +// +// Arguments: +// +// Color (a0) - Supplies the starting virtual address and color of the +// data that is purged. +// +// PageFrame (a1) - Supplies the page frame number of the page that +// is purged. +// +// Length (a2) - Supplies the length of the region in the page that is +// purged. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpInvalidateSecondaryCachePage) + + .set noreorder + .set noat + + li t0,GAMBIT_PFN_SECONDARY_CACHE_INVALIDATE_PHYSICAL_BASE + or a1,a1,t0 + +// lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy + li v0,0x10 // uncached cache policy + + and a0,a0,COLOR_MASK // isolate color bits + li t0,FLUSH_BASE // get base flush address + or t0,t0,a0 // compute color virtual address + sll t1,a1,ENTRYLO_PFN // shift page frame into position + or t1,t1,PROTECTION_BITS // merge protection bits + or t1,t1,v0 // merge cache policy + and a0,a0,0x1000 // isolate TB entry index + beql zero,a0,10f // if eq, first entry + move t2,zero // set second page table entry + move t2,t1 // set second page table entry + move t1,zero // set first page table entry +10: mfc0 t3,wired // get TB entry index + lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size + .set at + .set reorder + +// +// Purge data from the instruction cache. +// + +15: DISABLE_INTERRUPTS(t5) // disable interrupts + + .set noreorder + .set noat + mfc0 t6,entryhi // get current PID and VPN2 + srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address + sll t7,t7,ENTRYHI_VPN2 // + and t6,t6,0xff << ENTRYHI_PID // isolate current PID + or t7,t7,t6 // merge PID with VPN2 of virtual address + mtc0 t7,entryhi // set VPN2 and PID for probe + mtc0 t1,entrylo0 // set first PTE value + mtc0 t2,entrylo1 // set second PTE value + mtc0 t3,index // set TB index value + nop // fill + tlbwi // write TB entry - 3 cycle hazzard + subu t6,t4,1 // compute block size minus one + and t7,t0,t6 // compute offset in block + addu a2,a2,t6 // round up to next block + addu a2,a2,t7 // + nor t6,t6,zero // complement block size minus one + and a2,a2,t6 // truncate length to even number + beq zero,a2,30f // if eq, no blocks to purge + and t8,t0,t6 // compute starting virtual address + addu t9,t8,a2 // compute ending virtual address + subu t9,t9,t4 // compute ending loop address + +// +// Purge the primary instruction cache only. +// + +20: sw zero,0(t8) // invalidate cache block + bne t8,t9,20b // if ne, more blocks to invalidate + addu t8,t8,t4 // compute next block address + .set at + .set reorder + +30: ENABLE_INTERRUPTS(t5) // enable interrupts + + j ra // return + + .end HalpInvalidateSecondaryCachePage + +#endif diff --git a/private/ntos/nthals/halflex/mips/j4flshbf.s b/private/ntos/nthals/halflex/mips/j4flshbf.s new file mode 100644 index 000000000..ff3a32f78 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/j4flshbf.s @@ -0,0 +1,61 @@ +#if defined(R4000) + +// TITLE("Miscellaneous Kernel Functions") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Module Name: +// +// j3flshbf.s +// +// Abstract: +// +// This module implements the system dependent kernel function to flush +// the write buffer or otherwise synchronize writes on a MIPS R4000 Jazz +// system. +// +// Author: +// +// David N. Cutler (davec) 24-Apr-1991 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + SBTTL("Flush Write Buffer") +//++ +// +// NTSTATUS +// KeFlushWriteBuffer ( +// VOID +// ) +// +// Routine Description: +// +// This function flushes the write buffer on the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(KeFlushWriteBuffer) + + sync // synchronize writes + j ra // return + + .end KeFlushWritebuffer + +#endif diff --git a/private/ntos/nthals/halflex/mips/j4prof.c b/private/ntos/nthals/halflex/mips/j4prof.c new file mode 100644 index 000000000..14f92a196 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/j4prof.c @@ -0,0 +1,290 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + j4prof.c + +Abstract: + + This module contains the code to start and stop the profiling interrupt + and to compute the profiling interval for a MIPS R4000 Jazz system. + +Author: + + David N. Cutler (davec) 21-Feb-1991 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + +// +// Define one second and round values. +// + +#define ONE_SECOND (10 * 1000 * 1000) // 1 second in 100ns units +#define ROUND_VALUE ((ONE_SECOND) - 1) // 1 second minus 100ns + +// +// Define static data. +// + +LARGE_INTEGER HalpPerformanceCounter; +ULONG HalpProfileInterval = DEFAULT_PROFILE_INTERVAL; + +LARGE_INTEGER +KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER Frequency OPTIONAL + ) + +/*++ + +Routine Description: + + This routine returns the current performance counter value and the + performance counter frequency. + +Arguments: + + Frequency - Supplies an optional pointer to a variable which receives + the performance counter frequency in Hertz. + +Return Value: + + The current performance counter value is returned as the function + value. + +--*/ + +{ + + ULONG CurrentCount; + KIRQL OldIrql; + LARGE_INTEGER PerformanceCounter; + + // + // Raise IRQL to PROFILE_LEVEL, read the current value of the count + // register, read the performance counter, and lower IRQL to its + // previous value. + // + // N.B. The minimum, maximum, and default values for the profile + // count are chosen such that count register only overflows + // after about 20 seconds at 50mhz. Therefore, there is never + // a problem with the counter wrapping in the following code. + // + + KeRaiseIrql(PROFILE_LEVEL, &OldIrql); + CurrentCount = HalpReadCountRegister(); + PerformanceCounter = HalpPerformanceCounter; + KeLowerIrql(OldIrql); + + // + // If the frequency parameter is specified, then return the performance + // counter frequency as the current system time frequency. + // + + if (ARGUMENT_PRESENT(Frequency) != FALSE) { + Frequency->QuadPart = HalpProfileCountRate; + } + + // + // Return the value of the performance counter. + // + + PerformanceCounter.QuadPart += CurrentCount; + return PerformanceCounter; +} + +VOID +HalCalibratePerformanceCounter ( + IN volatile PLONG Number + ) + +/*++ + +Routine Description: + + This routine resets the performance counter value for the current + processor to zero. The reset is done such that the resulting value + is closely synchronized with other processors in the configuration. + +Arguments: + + Number - Supplies a pointer to count of the number of processors in + the configuration. + +Return Value: + + None. + +--*/ + +{ + + // + // Write the compare register, clear the count register, and zero the + // performance counter for the current processor. + // + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + HalpPerformanceCounter.QuadPart = 0; + return; +} + +ULONG +HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval. + +--*/ + +{ + + LARGE_INTEGER TempValue; + + // + // If the specified profile interval is less that the minimum profile + // interval or greater than the maximum profile interval, then set the + // profile interval to the minimum or maximum as appropriate. + // + + if (Interval < MINIMUM_PROFILE_INTERVAL) { + Interval = MINIMUM_PROFILE_INTERVAL; + + } else if (Interval > MAXIMUM_PROFILE_INTERVAL) { + Interval = MAXIMUM_PROFILE_INTERVAL; + } + + // + // First compute the profile count value and then back calculate the + // actual profile interval. + // + + TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, Interval); + TempValue.QuadPart += ROUND_VALUE; + TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL); + TempValue.QuadPart = Int32x32To64(TempValue.LowPart, ONE_SECOND); + TempValue = RtlExtendedLargeIntegerDivide(TempValue, HalpProfileCountRate, NULL); + HalpProfileInterval = TempValue.LowPart; + return HalpProfileInterval; +} + +VOID +HalStartProfileInterrupt ( + KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + This routine computes the profile count value, writes the compare + register, clears the count register, and updates the performance + counter. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + Source - Supplies the profile source. + +Return Value: + + None. + +--*/ + +{ + + ULONG PreviousCount; + LARGE_INTEGER TempValue; + + // + // Compute the profile count from the current profile interval. + // + + TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, + HalpProfileInterval); + + TempValue.QuadPart += ROUND_VALUE; + TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL); + + // + // Write the compare register and clear the count register. + // + + PreviousCount = HalpWriteCompareRegisterAndClear(TempValue.LowPart); + + // + // Update the performance counter by adding in the previous count value. + // + + HalpPerformanceCounter.QuadPart += PreviousCount; + return; +} + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE Source + ) + +/*++ + +Routine Description: + + This routine sets the default count value, writes the compare + register, clears the count register, and updates the performance + counter. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + Source - Supplies the profile source. + +Return Value: + + None. + +--*/ + +{ + + ULONG PreviousCount; + + // + // Write the compare register and clear the count register. + // + + PreviousCount = HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + + // + // Update the performance counter by adding in the previous count value. + // + + HalpPerformanceCounter.QuadPart += PreviousCount; + return; +} diff --git a/private/ntos/nthals/halflex/mips/jxhalp.h b/private/ntos/nthals/halflex/mips/jxhalp.h new file mode 100644 index 000000000..83bcf38bd --- /dev/null +++ b/private/ntos/nthals/halflex/mips/jxhalp.h @@ -0,0 +1,122 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + jxhalp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + Jazz specific interfaces, defines and structures. + +Author: + + Jeff Havens (jhavens) 20-Jun-91 + + +Revision History: + +--*/ + +#ifndef _JXHALP_ +#define _JXHALP_ + +typedef enum _ADDRESS_SPACE_TYPE{ + BusMemory=0, + BusIo = 1, + UserBusMemory = 2, + UserBusIo = 3, + KernelPciDenseMemory = 4, + UserPciDenseMemory = 6, +} ADDRESS_SPACE_TYPE, *PADDRESS_SPACE_TYPE; + +extern PVOID HalpSecondaryCacheResetBase; +extern PVOID HalpFirmwareVirtualBase; +extern PVOID PciInterruptRegisterBase; + +extern ULONG HalpIoArchitectureType; +extern ULONG HalpMotherboardType; +extern UCHAR *HalpInterruptLineToBit; +extern UCHAR *HalpBitToInterruptLine; +extern UCHAR *HalpInterruptLineToVirtualIsa; +extern UCHAR *HalpVirtualIsaToInterruptLine; +extern ULONGLONG HalpPciConfig0BasePhysical; +extern ULONGLONG HalpPciConfig1BasePhysical; +extern ULONGLONG HalpIsaIoBasePhysical; +extern ULONGLONG HalpIsa1IoBasePhysical; +extern ULONGLONG HalpIsaMemoryBasePhysical; +extern ULONGLONG HalpIsa1MemoryBasePhysical; +extern ULONGLONG HalpPciIoBasePhysical; +extern ULONGLONG HalpPci1IoBasePhysical; +extern ULONGLONG HalpPciMemoryBasePhysical; +extern ULONGLONG HalpPci1MemoryBasePhysical; +extern PPLATFORM_RANGE_LIST HalpRangeList; +extern UCHAR HalpSecondPciBridgeBusNumber; +extern ULONG PCIMaxBus; +extern ULONG HalpIntel82378BusNumber; +extern ULONG HalpIntel82378DeviceNumber; +extern ULONG HalpSecondIntel82378DeviceNumber; +extern ULONG HalpNonExistentPciDeviceMask; +extern ULONG HalpNonExistentPci1DeviceMask; +extern ULONG HalpNonExistentPci2DeviceMask; + +extern PLATFORM_RANGE_LIST Gambit20Trebbia13RangeList[]; +extern PLATFORM_RANGE_LIST Gambit20Trebbia20RangeList[]; + +extern UCHAR Treb13InterruptLineToBit[]; +extern UCHAR Treb13BitToInterruptLine[]; +extern UCHAR Treb13InterruptLineToVirtualIsa[]; +extern UCHAR Treb13VirtualIsaToInterruptLine[]; +extern UCHAR Treb20InterruptLineToBit[]; +extern UCHAR Treb20BitToInterruptLine[]; +extern UCHAR Treb20InterruptLineToVirtualIsa[]; +extern UCHAR Treb20VirtualIsaToInterruptLine[]; +extern ULONG HalpNumberOfIsaBusses; +extern ULONG HalpVgaDecodeBusNumber; + +ULONG +HalpReadCountRegister ( + VOID + ); + +ULONG +HalpWriteCompareRegisterAndClear ( + IN ULONG Value + ); + +VOID +HalpInvalidateSecondaryCachePage ( + IN PVOID Color, + IN ULONG PageFrame, + IN ULONG Length + ); + +VOID +HalpArcsSetVirtualBase ( + IN ULONG Number, + IN PVOID Base + ); + +ULONG HalpPciLowLevelConfigRead( + IN ULONG BusNumber, + IN ULONG DeviceNumber, + IN ULONG FunctionNumber, + IN ULONG Register + ); + +// +// There is not need for Memory Barriers on MIPS, so just define them away. +// + +#define HalpMb() + +// +// Define used to determine if a page is within the DMA Cache range. +// + +#define HALP_PAGE_IN_DMA_CACHE(Page) \ + (Page>=0x0001c0 && Page<0x000200) + +#endif // _JXHALP_ diff --git a/private/ntos/nthals/halflex/mips/jxmapio.c b/private/ntos/nthals/halflex/mips/jxmapio.c new file mode 100644 index 000000000..f7c277ec4 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/jxmapio.c @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + jxmapio.c + +Abstract: + + This module implements the mapping of HAL I/O space a MIPS R3000 + or R4000 Jazz system. + +Author: + + David N. Cutler (davec) 28-Apr-1991 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + +// +// Define global data used to locate the EISA control space and the realtime +// clock registers. +// + +PVOID HalpEisaControlBase[MAX_EISA_BUSSES]; +PVOID HalpEisaMemoryBase[MAX_EISA_BUSSES]; +PVOID HalpPciControlBase[MAX_PCI_BUSSES]; +PVOID HalpPciMemoryBase[MAX_PCI_BUSSES]; +PVOID HalpRealTimeClockBase; +PVOID HalpFirmwareVirtualBase; +PVOID PciInterruptRegisterBase; +PVOID HalpSecondaryCacheResetBase; + + +BOOLEAN +HalpMapIoSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL I/O space for a MIPS R3000 or R4000 Jazz + 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 EISA control space. Map all 16 slots. This is done so the NMI + // code can probe the cards. + // + + physicalAddress.QuadPart = HalpIsaIoBasePhysical; + HalpEisaControlBase[0] = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + + if (HalpMotherboardType == TREBBIA20) { + physicalAddress.QuadPart = HalpIsa1IoBasePhysical; + HalpEisaControlBase[1] = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + } + + // + // Map realtime clock registers. + // + + physicalAddress.QuadPart = HalpIsaIoBasePhysical + 0x71; + HalpRealTimeClockBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + + // + // Map ISA Memory Space. + // + + physicalAddress.QuadPart = HalpIsaMemoryBasePhysical; + HalpEisaMemoryBase[0] = MmMapIoSpace(physicalAddress, + PAGE_SIZE*256, + FALSE); + + if (HalpMotherboardType == TREBBIA20) { + physicalAddress.QuadPart = HalpIsa1MemoryBasePhysical; + HalpEisaMemoryBase[1] = MmMapIoSpace(physicalAddress, + PAGE_SIZE*256, + FALSE); + } + + // + // Map PCI control space. Map all 16 slots. This is done so the NMI + // code can probe the cards. + // + + physicalAddress.QuadPart = HalpPciIoBasePhysical; + HalpPciControlBase[0] = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + + // + // Map PCI Memory Space. + // + + physicalAddress.QuadPart = HalpPciMemoryBasePhysical; + HalpPciMemoryBase[0] = MmMapIoSpace(physicalAddress, + PAGE_SIZE*256, + FALSE); + + if (HalpMotherboardType == TREBBIA20) { + physicalAddress.QuadPart = HalpPci1IoBasePhysical; + HalpPciControlBase[1] = MmMapIoSpace(physicalAddress, + PAGE_SIZE * 16, + FALSE); + + physicalAddress.QuadPart = HalpPci1MemoryBasePhysical; + HalpPciMemoryBase[1] = MmMapIoSpace(physicalAddress, + PAGE_SIZE*256, + FALSE); + } + + // + // Map PCI interrupt space. + // + + physicalAddress.QuadPart = GAMBIT_PCI_INTERRUPT_BASE_PHYSICAL; + PciInterruptRegisterBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + + // + // Map Secondary Cache Reset space. + // + + physicalAddress.QuadPart = GAMBIT_SECONDARY_CACHE_RESET_BASE_PHYSICAL; + HalpSecondaryCacheResetBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + + + // + // If either mapped address is NULL, then return FALSE as the function + // value. Otherwise, return TRUE. + // + + if ((HalpEisaControlBase[0] == NULL) || + (HalpRealTimeClockBase == NULL) || + (HalpEisaMemoryBase[0] == NULL) || + (HalpPciControlBase[0] == NULL) || + (HalpPciMemoryBase[0] == NULL) || + (HalpSecondaryCacheResetBase == NULL)) { + return FALSE; + } + + // + // Map 1 page of EISA control space to generate a virtual address that the firmware can use. + // + + physicalAddress.QuadPart = HalpIsaIoBasePhysical; + HalpFirmwareVirtualBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + +// HalpArcsSetVirtualBase(0,HalpEisaControlBase[0]); +// HalpArcsSetVirtualBase(1,HalpEisaMemoryBase[0]); +// HalpArcsSetVirtualBase(4,HalpPciControlBase); +// HalpArcsSetVirtualBase(5,HalpPciMemoryBase); + + HalpArcsSetVirtualBase(7,HalpFirmwareVirtualBase); + + return TRUE; +} diff --git a/private/ntos/nthals/halflex/mips/pcisup.c b/private/ntos/nthals/halflex/mips/pcisup.c new file mode 100644 index 000000000..117a85228 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/pcisup.c @@ -0,0 +1,1008 @@ +/*++ + +Copyright (c) 1995 DeskStation Technology + +Module Name: + + pcisup.c + +Abstract: + + This module contains the routines that support PCI configuration cycles and + PCI interrupts. + +Author: + + Michael D. Kinney 2-May-1995 + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +#define SP_VIRTUAL_BASE 0xffffa000 + +#define INVALID_PCI_CONFIGURATION_ADDRESS (0x00000000) +#define NO_PCI_DEVSEL_DATA_VALUE (0xffffffff) + +// +// The following tables are used to map between PCI interrupt pins, PCI interrupt lines, +// and virtual ISA interrupt indexes. The Uniflex architecture uses a 16 bit interrupt +// controller for ISA interrupts and all PCI interrupts. +// InterruptLine values between 0x10 and 0x20 are reserved +// for PCI devices. InterruptLine values between 0x00 and 0x10 are reserved for ISA IRQs. +// + +UCHAR Treb13InterruptLineToBit[0x11] = {0,1,2,3,8,9,10,11,12,12,12,12,12,12,4,5,12}; +UCHAR Treb13BitToInterruptLine[12] = {0x00,0x01,0x02,0x03,0x0e,0x0f,0x00,0x00,0x04,0x05,0x06,0x07}; +UCHAR Treb13InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0}; +UCHAR Treb13VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,0,0,0,0}; + +UCHAR Treb20InterruptLineToBit[0x11] = {3,1,2,8,9,10,0,5,11,12,12,12,12,12,12,12,12}; +UCHAR Treb20BitToInterruptLine[12] = {0x06,0x01,0x02,0x00,0x00,0x07,0x00,0x00,0x03,0x04,0x05,0x08}; +UCHAR Treb20InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0}; +UCHAR Treb20VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,0,0,0,0}; + +// +// Interrupt mask for all active PCI interrupts including ISA Bus PICs +// + +static volatile ULONG HalpPciInterruptMask; + +// +// Interrupt mask for PCI interrupts that have been connected through device drivers. +// + +static volatile ULONG HalpPciDeviceInterruptMask; + +// +// Interrupt mask showing which bit cooresponds to ISA Bus #0 PIC +// + +static volatile ULONG HalpEisaInterruptMask; + +// +// Interrupt mask showing which bit cooresponds to ISA Bus #1 PIC +// + +static volatile ULONG HalpEisa1InterruptMask; + +PVOID HalpAllocateIoMapping( + LONGLONG BaseAddress + ) + +{ + ENTRYLO HalpPte[2]; + ULONG KdPortEntry; + + // + // Map the PCI Configuration register into the system virtual address space by loading + // a TB entry. + // + + HalpPte[0].PFN = (ULONG)(BaseAddress >> 12); + HalpPte[0].G = 1; + HalpPte[0].V = 1; + HalpPte[0].D = 1; + + // + // Allocate a TB entry, set the uncached policy in the PTE that will + // map the serial controller, and initialize the second PTE. + // + + KdPortEntry = HalpAllocateTbEntry(); + HalpPte[0].C = UNCACHED_POLICY; + + HalpPte[1].PFN = 0; + HalpPte[1].G = 1; + HalpPte[1].V = 0; + HalpPte[1].D = 0; + HalpPte[1].C = 0; + + // + // Map the PCI Configuration register through a fixed TB entry. + // + + KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0], + (PVOID)SP_VIRTUAL_BASE, + KdPortEntry); + + + return((PVOID)(SP_VIRTUAL_BASE + (ULONG)(BaseAddress & 0xfff))); +} + +VOID HalpFreeIoMapping( + VOID + ) + +{ + HalpFreeTbEntry(); +} + +VOID +HalpWritePciInterruptMask ( + VOID + ) + +/*++ + +Routine Description: + + This function writes the interrupt mask register for PCI interrupts. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00,HalpPciInterruptMask&0x0f); + WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08,(HalpPciInterruptMask>>4)&0x0f); + WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10,(HalpPciInterruptMask>>8)&0x0f); +} + +ULONG +HalpReadPciInterruptStatus ( + VOID + ) + +/*++ + +Routine Description: + + This function reads the interrupt status register for PCI interrupts. + +Arguments: + + None. + +Return Value: + + The lower 12 bits contain the status of each interrupt line going to the PCI + interrupt controller. + +--*/ + +{ + return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00)<<0) & 0x00f | + (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08)<<4) & 0x030 | + (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10)<<8) & 0xf00 ); +} + +ULONG +HalpGetMemoryMode ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the status of the MemoryMode bit that is embedded within + the PCI interrupt controller. The status of this bit must be preserved on all + writes to the PCI interrupt mask register. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08) & 0x08) << 4 ); +} + +VOID +HalpSetPciInterruptBit ( + ULONG Bit + ) + +/*++ + +Routine Description: + + This function sets a bit in the PCI interrupt mask and writes the new mask + to the interrupt controller. + +Arguments: + + Bit - The bit number to set in the PCI interrupt mask. + +Return Value: + + None. + +--*/ + +{ + if (Bit==6 || Bit==7 || Bit>=12) { + return; + } + HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask | (1<<Bit); + HalpPciInterruptMask = HalpPciInterruptMask | (1<<Bit); + HalpWritePciInterruptMask(); +} + +VOID +HalpClearPciInterruptBit ( + ULONG Bit + ) + +/*++ + +Routine Description: + + This function clears a bit in the PCI interrupt mask and writes the new mask + to the interrupt controller. + +Arguments: + + Bit - The bit number to clear from the PCI interrupt mask. + +Return Value: + + None. + +--*/ + +{ + if (Bit==6 || Bit==7 || Bit>=12) { + return; + } + HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask & ~(1<<Bit); + HalpPciInterruptMask = HalpPciInterruptMask & ~(1<<Bit); + HalpWritePciInterruptMask(); +} + +VOID +HalpEnablePciInterrupt ( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function enables a PCI interrupt. + +Arguments: + + Vector - Specifies the interrupt to enable. + +Return Value: + + None. + +--*/ + +{ + if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) { + HalpSetPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]); + } +} + +VOID +HalpDisablePciInterrupt ( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function disables a PCI interrupt. + +Arguments: + + Vector - Specifies the interrupt to disable. + +Return Value: + + None. + +--*/ + +{ + if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) { + HalpClearPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]); + } +} + +ULONG +HalpVirtualIsaInterruptToInterruptLine ( + IN ULONG Index + ) + +/*++ + +Routine Description: + + This function maps a virtual ISA interrupt to a PCI interrupt line value. + This provides the ability to use an ISA device driver on a PCI device. + +Arguments: + + Index - Index into a platform specific table that maps PCI interrupts to + virtual ISA interrupts. + +Return Value: + + None. + +--*/ + +{ + return(HalpVirtualIsaToInterruptLine[Index]); +} + +BOOLEAN +HalpEisa0Dispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) + +/*++ + +Routine Description: + + This is the interrupt dispatcher for all ISA Bus #0 interrupts. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - not used. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ + +{ + return(HalpEisaDispatch(Interrupt,ServiceContext,0)); +} + +BOOLEAN +HalpPciDispatch( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) + +/*++ + +Routine Description: + + This is the interrupt dispatcher for all PCI interrupts. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object. + + ServiceContext - not used. + +Return Value: + + Returns the value returned from the second level routine. + +--*/ + +{ + ULONG PciInterruptStatus; + PULONG dispatchCode; + PKINTERRUPT interruptObject; + USHORT PCRInOffset; + BOOLEAN returnValue = FALSE; + ULONG i; + + // + // Get the active interrupt bits + // + + PciInterruptStatus = HalpReadPciInterruptStatus(); + + // + // See if this is the interrupt for ISA Bus #0 PIC + // + + if (PciInterruptStatus & HalpEisaInterruptMask) { + + returnValue = HalpEisaDispatch(Interrupt,ServiceContext,0); + + // + // If there really was an interrupt on ISA Bus #0, then return now. + // + + if (returnValue) { + return(returnValue); + } + } + + // + // See if this is the interrupt for ISA Bus #1 PIC + // + + if (PciInterruptStatus & HalpEisa1InterruptMask) { + + returnValue = HalpEisaDispatch(Interrupt,ServiceContext,1); + + // + // If there really was an interrupt on ISA Bus #1, then return now. + // + + if (returnValue) { + return(returnValue); + } + } + + // + // Only keep interrupt bits that have been connected by device drivers. + // + + PciInterruptStatus &= HalpPciDeviceInterruptMask; + + // + // Dispatch to the ISRs of interrupts that have been connected by device drivers. + // + + for(i=0;i<12;i++) { + if (PciInterruptStatus & (1<<i)) { + + PCRInOffset = UNIFLEX_PCI_VECTORS + HalpBitToInterruptLine[i]; + + // + // Dispatch to the secondary interrupt service routine. + // + + dispatchCode = (PULONG)(PCR->InterruptRoutine[PCRInOffset]); + interruptObject = CONTAINING_RECORD(dispatchCode, + KINTERRUPT, + DispatchCode); + + returnValue = + ((PSECONDARY_DISPATCH)interruptObject->DispatchAddress) + (interruptObject); + } + } + + return(returnValue); +} + +UCHAR HalpGetInterruptLine(ULONG BusNumber,ULONG DeviceNumber,ULONG InterruptPin) + +/*++ + +Routine Description: + + This routine maps a PCI interrupt described by the device's bus number, device number, and + interrupt pin into the interrupt line value that is stored in the PCI config header. + +Arguments: + + BusNumber - PCI bus number of the device. + + DeviceNumber - PCI device number of the device. + + InterruptPin - PCI interrupt pin of the device (A=1,B=2,C=3,D=4). + +Return Value: + + Returns the PCI Interrupt Line value for the PCI device. + +--*/ + +{ + UCHAR InterruptLine; + + if (HalpMotherboardType == TREBBIA13) { + + if (BusNumber > 1) + { + BusNumber = 1; + } + + switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) { + case 0x010401 : InterruptLine = 0x10; break; // Bus 1, Device 4, Int A + case 0x010601 : InterruptLine = 0x11; break; // Bus 1, Device 6, Int A + case 0x010501 : InterruptLine = 0x12; break; // Bus 1, Device 5, Int A + case 0x010701 : InterruptLine = 0x13; break; // Bus 1, Device 7, Int A + case 0x010402 : InterruptLine = 0x17; break; // Bus 1, Device 4, Int B + case 0x010602 : InterruptLine = 0x14; break; // Bus 1, Device 6, Int B + case 0x010502 : InterruptLine = 0x14; break; // Bus 1, Device 5, Int B + case 0x010702 : InterruptLine = 0x17; break; // Bus 1, Device 7, Int B + case 0x010403 : InterruptLine = 0x15; break; // Bus 1, Device 4, Int C + case 0x010603 : InterruptLine = 0x15; break; // Bus 1, Device 6, Int C + case 0x010503 : InterruptLine = 0x15; break; // Bus 1, Device 5, Int C + case 0x010703 : InterruptLine = 0x15; break; // Bus 1, Device 7, Int C + case 0x010404 : InterruptLine = 0x16; break; // Bus 1, Device 4, Int D + case 0x010604 : InterruptLine = 0x16; break; // Bus 1, Device 6, Int D + case 0x010504 : InterruptLine = 0x16; break; // Bus 1, Device 5, Int D + case 0x010704 : InterruptLine = 0x16; break; // Bus 1, Device 7, Int D + case 0x000d01 : InterruptLine = 0x1e; break; // Bus 0, Device 13, Int A + case 0x000f01 : InterruptLine = 0x1f; break; // Bus 0, Device 15, Int A + case 0x001001 : InterruptLine = 0x20; break; // Bus 0, Device 16, Int A + default : InterruptLine = 0xff; break; + } + } + + if (HalpMotherboardType == TREBBIA20) { + + if (BusNumber == 0) { + return(0xff); + } + + if (BusNumber >= HalpSecondPciBridgeBusNumber) { + BusNumber = 1; + } else { + BusNumber = 0; + } + + switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) { + case 0x000401 : InterruptLine = 0x20; break; + + case 0x000501 : + case 0x000603 : + case 0x000704 : InterruptLine = 0x10; break; + + case 0x000502 : + case 0x000604 : + case 0x000701 : InterruptLine = 0x11; break; + + case 0x000503 : + case 0x000601 : + case 0x000702 : InterruptLine = 0x12; break; + + case 0x000504 : + case 0x000602 : + case 0x000703 : InterruptLine = 0x13; break; + + case 0x010401 : + case 0x010504 : + case 0x010603 : InterruptLine = 0x14; break; + + case 0x010402 : + case 0x010501 : + case 0x010604 : InterruptLine = 0x15; break; + + case 0x010403 : + case 0x010502 : + case 0x010601 : InterruptLine = 0x16; break; + + case 0x010404 : + case 0x010503 : + case 0x010602 : InterruptLine = 0x17; break; + + case 0x010701 : InterruptLine = 0x18; break; + + default : InterruptLine = 0xff; break; + } + } + + return(InterruptLine); +} + +VOID +HalpConnectInterruptDispatchers ( + VOID + ) + +/*++ + +Routine Description: + + This function connects the PCI interrupt dispatch routine and enables + ISA interrupts so they will generate processor interrupts. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + UCHAR InterruptLine; + + // + // Initialize the EISA interrupt dispatcher and the PCI interrupt dispatcher + // + + PCR->InterruptRoutine[UNIFLEX_PCI_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpPciDispatch; + PCR->InterruptRoutine[UNIFLEX_EISA_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpEisa0Dispatch; + +DbgPrint("Intel82378 : Bus=%d Device=%d\n\r",HalpIntel82378BusNumber,HalpIntel82378DeviceNumber); +DbgPrint("SecondIntel82378 : Bus=%d Device=%d\n\r",HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber); + + InterruptLine = HalpGetInterruptLine(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,1); + HalpEisaInterruptMask = 0x0000; + if (InterruptLine != 0xff) { + HalpEisaInterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff; + } + + InterruptLine = HalpGetInterruptLine(HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber,1); + HalpEisa1InterruptMask = 0x0000; + if (InterruptLine != 0xff) { + HalpEisa1InterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff; + } + +DbgPrint("HalpEisaInterruptMask = %08x\n\r",HalpEisaInterruptMask); +DbgPrint("HalpEisa1InterruptMask = %08x\n\r",HalpEisa1InterruptMask); + + // + // Enable ISA Interrupts on Gambit's PIC + // + + HalpPciInterruptMask = HalpGetMemoryMode(); + HalpPciInterruptMask |= (HalpEisaInterruptMask | HalpEisa1InterruptMask); + HalpWritePciInterruptMask(); +} + +VOID +HalpDisableAllInterrupts( + VOID + ) + +/*++ + +Routine Description: + + This function disables all external interrupt sources. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG VirtualAddress; + + VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsaIoBasePhysical); + WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff); + WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff); + HalpFreeIoMapping(); + + if (HalpNumberOfIsaBusses > 1) { + VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsa1IoBasePhysical); + WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff); + WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff); + HalpFreeIoMapping(); + } + + VirtualAddress = (ULONG)HalpAllocateIoMapping(GAMBIT_PCI_INTERRUPT_BASE_PHYSICAL); + + HalpPciInterruptMask = ((READ_REGISTER_ULONG(VirtualAddress+0x08) & 0x08) << 4); + WRITE_REGISTER_ULONG(VirtualAddress+0x00,HalpPciInterruptMask&0x0f); + WRITE_REGISTER_ULONG(VirtualAddress+0x08,(HalpPciInterruptMask>>4)&0x0f); + WRITE_REGISTER_ULONG(VirtualAddress+0x10,(HalpPciInterruptMask>>8)&0x0f); + HalpFreeIoMapping(); + + HalpPciDeviceInterruptMask = 0x0000; +} + +ULONG HalpPciConfigStructuresInitialized = FALSE; +PVOID HalpPciConfig0BaseAddress[0x20]; +PVOID HalpPciConfig1BaseAddress[0x100]; + +PCI_CONFIGURATION_TYPES +HalpPCIConfigCycleType (IN ULONG BusNumber) +{ + if (BusNumber == 0) { + return PciConfigType0; + } else if (BusNumber < PCIMaxBus) { + return PciConfigType1; + } else { + return PciConfigTypeInvalid; + } +} + +VOID +HalpPCIConfigAddr ( + IN ULONG BusNumber, + IN PCI_SLOT_NUMBER Slot, + PPCI_CFG_CYCLE_BITS pPciAddr + ) +{ + + PCI_CONFIGURATION_TYPES ConfigType; + + // + // If the Configuration Base Address tables have not been initialized, then + // initialize them to NULL. + // + + if (HalpPciConfigStructuresInitialized == FALSE) { + + ULONG i; + + for(i=0;i<0x20;HalpPciConfig0BaseAddress[i++]=NULL); + for(i=0;i<0xff;HalpPciConfig1BaseAddress[i++]=NULL); + HalpPciConfigStructuresInitialized = TRUE; + } + + ConfigType = HalpPCIConfigCycleType(BusNumber); + + if (ConfigType == PciConfigType0) { + + // + // Initialize PciAddr for a type 0 configuration cycle + // + + // + // See if this is a nonexistant device on PCI Bus 0 + // + + if ( (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPciDeviceMask ) { + pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS; + return; + } + + if (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) { + + PHYSICAL_ADDRESS physicalAddress; + + physicalAddress.QuadPart = HalpPciConfig0BasePhysical; + physicalAddress.QuadPart += (1 << (11 + Slot.u.bits.DeviceNumber)); + HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] = MmMapIoSpace(physicalAddress,0x800,FALSE); + + // + // If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS. + // This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing. + // + + if (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) { + pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS; + return; + } + + } + pPciAddr->u.AsULONG = (ULONG)HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber]; + pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8); + pPciAddr->u.bits0.Reserved1 = PciConfigType0; + +#if DBG + DbgPrint("HalpPCIConfigAddr: Type 0 PCI Config Access @ %x\n", pPciAddr->u.AsULONG); +#endif // DBG + + } else { + + // + // See if this is a nonexistant PCI device on the otherside of the First PCI-PCI Bridge + // + + if (BusNumber == 1 && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci1DeviceMask) { + pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS; + return; + } + + // + // See if this is a nonexistant PCI device on the otherside of the Second PCI-PCI Bridge + // + + if (BusNumber == HalpSecondPciBridgeBusNumber && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci2DeviceMask) { + pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS; + return; + } + + // + // Initialize PciAddr for a type 1 configuration cycle + // + + if (HalpPciConfig1BaseAddress[BusNumber] == NULL) { + + PHYSICAL_ADDRESS physicalAddress; + + physicalAddress.QuadPart = HalpPciConfig1BasePhysical; + physicalAddress.QuadPart += ((BusNumber & 0xff) << 16); + HalpPciConfig1BaseAddress[BusNumber] = MmMapIoSpace(physicalAddress,0x10000,FALSE); + + // + // If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS. + // This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing. + // + + if (HalpPciConfig1BaseAddress[BusNumber] == NULL) { + pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS; + return; + } + + } + pPciAddr->u.AsULONG = (ULONG)HalpPciConfig1BaseAddress[BusNumber]; + pPciAddr->u.AsULONG += ((Slot.u.bits.DeviceNumber & 0x1f) << 11); + pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8); + pPciAddr->u.bits0.Reserved1 = PciConfigType1; + +#if DBG + DbgPrint("Type 1 PCI Config Access @ %x\n", pPciAddr->u.AsULONG); +#endif // DBG + + } + + return; +} + +UCHAR +READ_CONFIG_UCHAR( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) { + return((UCHAR)NO_PCI_DEVSEL_DATA_VALUE); + } + return(READ_REGISTER_UCHAR(ConfigurationAddress)); +} + +USHORT +READ_CONFIG_USHORT( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) { + return((USHORT)NO_PCI_DEVSEL_DATA_VALUE); + } + return(READ_REGISTER_USHORT(ConfigurationAddress)); +} + +ULONG +READ_CONFIG_ULONG( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) { + return((ULONG)NO_PCI_DEVSEL_DATA_VALUE); + } + return(READ_REGISTER_ULONG(ConfigurationAddress)); +} + +VOID +WRITE_CONFIG_UCHAR( + IN PVOID ConfigurationAddress, + IN UCHAR ConfigurationData, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) { + WRITE_REGISTER_UCHAR(ConfigurationAddress,ConfigurationData); + } +} + +VOID +WRITE_CONFIG_USHORT( + IN PVOID ConfigurationAddress, + IN USHORT ConfigurationData, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) { + WRITE_REGISTER_USHORT(ConfigurationAddress,ConfigurationData); + } +} + +VOID +WRITE_CONFIG_ULONG( + IN PVOID ConfigurationAddress, + IN ULONG ConfigurationData, + IN ULONG ConfigurationType + ) + +{ + if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) { + WRITE_REGISTER_ULONG(ConfigurationAddress,ConfigurationData); + } +} + +LONGLONG HalpMapPciConfigBaseAddress( + IN ULONG BusNumber, + IN ULONG DeviceNumber, + IN ULONG FunctionNumber, + IN ULONG Register + ) + +{ + LONGLONG BaseAddress; + + if (BusNumber == 0) { + BaseAddress = HalpPciConfig0BasePhysical + + (1 << (11+(DeviceNumber & 0x1f))) + + ((FunctionNumber & 0x07) << 8) + + Register; + } else { + BaseAddress = HalpPciConfig1BasePhysical + + ((BusNumber & 0xff) << 16) + + ((DeviceNumber & 0x1f) << 11) + + ((FunctionNumber & 0x07) << 8) + + Register; + } + return(BaseAddress); +} + +ULONG HalpPciLowLevelConfigRead( + IN ULONG BusNumber, + IN ULONG DeviceNumber, + IN ULONG FunctionNumber, + IN ULONG Register + ) + +/*++ + +Routine Description: + + This function allocates the resources needed to perform a single PCI + configuration read cycle. The read data is returned. For a MIPS processor, + a single TLB entry is borrowed so that I/O reads and writes can be performed + to PCI configuration space. + +Return Value: + + Data retuned by the PCI config cycle. + +--*/ + +{ + LONGLONG BaseAddress; + PVOID VirtualAddress; + ULONG ReturnValue; + + BaseAddress = HalpMapPciConfigBaseAddress(BusNumber,DeviceNumber,FunctionNumber,Register&0xfc); + VirtualAddress = HalpAllocateIoMapping(BaseAddress); + ReturnValue = READ_REGISTER_ULONG(VirtualAddress); + HalpFreeIoMapping(); + return(ReturnValue); +} + +VOID HalpPostCard(UCHAR Value) + +{ + LONGLONG BaseAddress; + PVOID VirtualAddress; + + BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f); + VirtualAddress = HalpAllocateIoMapping(BaseAddress); + WRITE_REGISTER_UCHAR(VirtualAddress,0xcf); + HalpFreeIoMapping(); + + VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0x420); + Value = (Value & 0x7f) | (READ_REGISTER_UCHAR(VirtualAddress) & 0x80); + HalpFreeIoMapping(); + + VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0xc00); + WRITE_REGISTER_UCHAR(VirtualAddress,Value); + HalpFreeIoMapping(); + + BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f); + VirtualAddress = HalpAllocateIoMapping(BaseAddress); + WRITE_REGISTER_UCHAR(VirtualAddress,0x4f); + HalpFreeIoMapping(); +} diff --git a/private/ntos/nthals/halflex/mips/portsup.c b/private/ntos/nthals/halflex/mips/portsup.c new file mode 100644 index 000000000..9e0171440 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/portsup.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1995 DeskStation Technology + +Module Name: + + portsup.c + +Abstract: + + This module implements the code that provides the resources required to + access the serial port that is used for the kernel debugger. + +Author: + + Michael D. Kinney 30-Apr-1995 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" + +#define HEADER_FILE +#include "kxmips.h" + +#define SP_VIRTUAL_BASE 0xffffa000 +#define SERIAL_PORT_COM1 0x3F8 + +VOID +HalpGetIoArchitectureType( + VOID + ); + +// +// Define hardware PTE's that map the serial port used by the debugger. +// + +ENTRYLO HalpPte[2]; + +PUCHAR HalpAllocateKdPortResources( + OUT PVOID *SP_READ, + OUT PVOID *SP_WRITE + ) + +/*++ + +Routine Description: + + This function allocates the resources needed by the kernel debugger to + access a serial port. For a MIPS processor, a single TLB entry is borrowed + so that I/O reads and writes can be performed to the serial port. + +Arguments: + + SP_READ - Kernel virtual address to use for I/O read operations. + + SP_WRITE - Kernel virtual address to use for I/O write operations. + +Return Value: + + The bus relative address of the COM port being used as a kernel debugger. + +--*/ + +{ + ULONG KdPortEntry; + + HalpGetIoArchitectureType(); + + // + // Map the serial port into the system virtual address space by loading + // a TB entry. + // + + HalpPte[0].PFN = (ULONG)(HalpIsaIoBasePhysical >> 12); + HalpPte[0].G = 1; + HalpPte[0].V = 1; + HalpPte[0].D = 1; + + // + // Allocate a TB entry, set the uncached policy in the PTE that will + // map the serial controller, and initialize the second PTE. + // + + KdPortEntry = HalpAllocateTbEntry(); + HalpPte[0].C = UNCACHED_POLICY; + + HalpPte[1].PFN = 0; + HalpPte[1].G = 1; + HalpPte[1].V = 0; + HalpPte[1].D = 0; + HalpPte[1].C = 0; + + // + // Map the serial controller through a fixed TB entry. + // + + KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0], + (PVOID)SP_VIRTUAL_BASE, + KdPortEntry); + + *SP_READ = (PVOID)(SP_VIRTUAL_BASE + SERIAL_PORT_COM1); + *SP_WRITE = (PVOID)(SP_VIRTUAL_BASE + SERIAL_PORT_COM1); + + return((PUCHAR)(SERIAL_PORT_COM1)); +} + +VOID HalpFreeKdPortResources( + VOID + ) + +/*++ + +Routine Description: + + This function deallocates the resources needed by the kernel debugger to + access a serial port. For a MIPS processor, this simply frees the TLB entry + that was borrowed. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + HalpFreeTbEntry(); +} diff --git a/private/ntos/nthals/halflex/mips/x4clock.s b/private/ntos/nthals/halflex/mips/x4clock.s new file mode 100644 index 000000000..0e8475007 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/x4clock.s @@ -0,0 +1,210 @@ +#if defined(R4000) + +// TITLE("Interval and Profile Clock Interrupts") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Module Name: +// +// x4clock.s +// +// Abstract: +// +// This module implements the code necessary to field and process the +// interval and profile clock interrupts on a MIPS R4000 system. +// +// Author: +// +// David N. Cutler (davec) 26-Apr-1991 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + SBTTL("System Clock Interrupt") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by +// the interval timer. Its function is to acknowledge the interrupt and +// transfer control to the standard system routine to update the system +// time and the execution time of the current thread and process. +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 +CiArgs: .space 4 * 4 // saved arguments + .space 3 * 4 // fill +CiRa: .space 4 // saved return address +CiFrameLength: // + + NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero) + + subu sp,sp,CiFrameLength // allocate stack frame + sw ra,CiRa(sp) // save return address + + PROLOGUE_END + + move a0,s8 // set address of trap frame + lw a1,HalpCurrentTimeIncrement // Get current time increment + jal KeUpdateSystemTime // update system time + lw t0,HalpNextTimeIncrement // Get NextTimeIncrement + sw t0,HalpCurrentTimeIncrement // Set CurrentTimeIncrement to NextTimeIncrement + lw a0,HalpNextIntervalCount // Get Next Interval Count. If 0, then no change required + beq zero,a0,5f // See if time increment is to be changed + jal HalpProgramIntervalTimer // Program timer with new interval count value + lw t0,HalpNewTimeIncrement // Get HalpNewTimeIncrement + sw t0,HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement + sw zero,HalpNextIntervalCount // Set HalpNextIntervalCount to 0 +5: + lw t0,KdDebuggerEnabled // check if debugger enabled + lbu t0,0(t0) // + beq zero,t0,10f // if eq, debugger not enabled + jal KdPollBreakIn // check if breakin is requested + beq zero,v0,10f // if eq, no breakin requested + li a0, DBG_STATUS_CONTROL_C // break in and send + jal DbgBreakPointWithStatus // status to debugger +10: lw ra,CiRa(sp) // restore return address + addu sp,sp,CiFrameLength // deallocate stack frame + j ra // return + + .end HalpClockInterrupt + + SBTTL("Profile Clock Interrupt") +//++ +// +// Routine Description: +// +// This routine is entered as the result of an interrupt generated by the +// profile clock. Its function is to acknowledge the profile interrupt, +// compute the next compare value, update the performance counter, and +// transfer control to the standard system routine to process any active +// profiles. +// +// Arguments: +// +// s8 - Supplies a pointer to a trap frame. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpProfileInterrupt) + + .set noreorder + .set noat + mfc0 t1,count // get current count value + mfc0 t0,compare // get current comparison value + addu t1,t1,8 // factor in lost cycles + subu t1,t1,t0 // compute initial count value + mtc0 t0,compare // dismiss interrupt + mtc0 t1,count // set new count register value + .set at + .set reorder + + la t1,HalpPerformanceCounter // get performance counter address + lw t2,LiLowPart(t1) // get low part of performance count + lw t3,LiHighPart(t1) // get high part of performance count + addu t2,t2,t0 // update low part of performance count + sw t2,LiLowPart(t1) // store low part of performance count + sltu t4,t2,t0 // generate carry into high part + addu t3,t3,t4 // update high part of performance count + sw t3,LiHighPart(t1) // store high part of performance count + move a0,s8 // set address of trap frame + j KeProfileInterrupt // process profile entries + + .end HalpProfileInterrupt + + SBTTL("Read Count Register") +//++ +// +// ULONG +// HalpReadCountRegister ( +// VOID +// ); +// +// Routine Description: +// +// This routine reads the current value of the count register and +// returns the value. +// +// Arguments: +// +// None. +// +// Return Value: +// +// Current value of the count register. +// +//-- + + LEAF_ENTRY(HalpReadCountRegister) + + .set noreorder + .set noat + mfc0 v0,count // get count register value + .set at + .set reorder + + j ra // return + + .end HalpReadCountRegister + + SBTTL("Write Compare Register And Clear") +//++ +// +// ULONG +// HalpWriteCompareRegisterAndClear ( +// IN ULONG Value +// ); +// +// Routine Description: +// +// This routine reads the current value of the count register, writes +// the value of the compare register, clears the count register, and +// returns the previous value of the count register. +// +// Arguments: +// +// Value - Supplies the value written to the compare register. +// +// Return Value: +// +// Previous value of the count register. +// +//-- + + LEAF_ENTRY(HalpWriteCompareRegisterAndClear) + + .set noreorder + .set noat + mfc0 v0,count // get count register value + mtc0 a0,compare // set compare register value + li t0,7 // set lost cycle count + mtc0 t0,count // set count register to zero + .set at + .set reorder + + j ra // return + + .end HalpWriteCompareRegisterAndClear + +#endif diff --git a/private/ntos/nthals/halflex/mips/x4tb.s b/private/ntos/nthals/halflex/mips/x4tb.s new file mode 100644 index 000000000..d399da2ac --- /dev/null +++ b/private/ntos/nthals/halflex/mips/x4tb.s @@ -0,0 +1,109 @@ +#if defined(R4000) + +// TITLE("AllocateFree TB Entry") +//++ +// +// Copyright (c) 1992-1993 Microsoft Corporation +// +// Module Name: +// +// x4tb.s +// +// Abstract: +// +// This module implements allocates and frees fixed TB entries using the +// wired register. +// +// Environment: +// +// Kernel mode only. +// +//-- + +#include "halmips.h" + + SBTTL("Allocate Tb Entry") +//++ +// +// ULONG +// HalpAllocateTbEntry ( +// VOID +// ) +// +// Routine Description: +// +// This function allocates the TB entry specified by the wired register +// and increments the wired register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// The index of the allocated TB entry. +// +//-- + + LEAF_ENTRY(HalpAllocateTbEntry) + + DISABLE_INTERRUPTS(t0) // disable interrupts + + .set noreorder + .set noat + mfc0 v0,wired // get contents of wired register + nop // fill + addu v1,v0,1 // allocate TB entry + mtc0 v1,wired // + .set at + .set reorder + + ENABLE_INTERRUPTS(t0) // enable interrupts + + j ra // return + + .end HalpAllocateTbEntry + + SBTTL("Free Tb Entry") +//++ +// +// VOID +// HalpAllocateTbEntry ( +// VOID +// ) +// +// Routine Description: +// +// This function frees the TB entry specified by the wired register +// and decrements the wired register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpFreeTbEntry) + + DISABLE_INTERRUPTS(t0) // disable interrupts + + .set noreorder + .set noat + mfc0 v0,wired // get contents of wired register + nop // fill + subu v1,v0,1 // free TB entry + mtc0 v1,wired // + .set at + .set reorder + + ENABLE_INTERRUPTS(t0) // enable interrupts + + j ra // return + + .end HalpFreeTbEntry + +#endif diff --git a/private/ntos/nthals/halflex/mips/xxcalstl.c b/private/ntos/nthals/halflex/mips/xxcalstl.c new file mode 100644 index 000000000..e1ce0b6b0 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/xxcalstl.c @@ -0,0 +1,253 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxcalstl.c + +Abstract: + + + This module implements the calibration of the stall execution HAL + service, computes the count rate for the profile clock, and connects + the clock and profile interrupts for a MIPS R3000 or R4000 system. + +Author: + + David N. Cutler (davec) 26-Apr-1991 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + +// +// Define global data used to calibrate and stall processor execution. +// + +ULONG HalpProfileCountRate; +ULONG volatile HalpStallEnd; +ULONG volatile HalpStallStart; + +BOOLEAN +HalpCalibrateStall ( + VOID + ) + +/*++ + +Routine Description: + + This function calibrates the stall execution HAL service and connects + the clock and profile interrupts to the appropriate NT service routines. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the calibration is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ + + ULONG Index; + KIRQL OldIrql; + PKPRCB Prcb; + + // + // Start the system clock to interrupt at MAXIMUM_INCREMENT intervals. + // + // N.B. MAXIMUM_INCREMENT is in 100ns units. + // + + HalSetTimeIncrement(MAXIMUM_INCREMENT); + HalpProgramIntervalTimer(HalpNextIntervalCount); + HalpEnableEisaInterrupt(UNIFLEX_CLOCK2_LEVEL,Latched); /* Enable Timer1,Counter0 interrupt */ + + // + // Use a range of scale factors from 50ns down to 10ns assuming a + // five instruction stall loop. + // + + for (Index = 50; Index > 0; Index -= 10) { + + // + // Disable all interrupts and establish calibration parameters. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // Set the scale factor, stall count, starting stall count, and + // ending stall count values. + // + + PCR->StallScaleFactor = 1000 / (Index * 5); + PCR->StallExecutionCount = 0; + HalpStallStart = 0; + HalpStallEnd = 0; + + // + // Enable interrupts and stall execution. + // + + KeLowerIrql(OldIrql); + + // + // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us. + // + + KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4); + + // + // If both the starting and ending stall counts have been captured, + // then break out of loop. + // + + if ((HalpStallStart != 0) && (HalpStallEnd != 0)) { + break; + } + + } + + // + // Compute the profile interrupt rate. + // + + HalpProfileCountRate = + HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT); + + // + // Compute the stall execution scale factor. + // + + PCR->StallScaleFactor = (HalpStallEnd - HalpStallStart + + ((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10); + + if (PCR->StallScaleFactor <= 0) { + PCR->StallScaleFactor = 1; + } + + // + // Get the address of the processor control block for the current + // processor. + // + + Prcb = PCR->Prcb; + + // + // Connect the real clock interrupt routine. + // + + PCR->InterruptRoutine[UNIFLEX_CLOCK2_LEVEL] = HalpClockInterrupt; + + // + // Write the compare register and clear the count register, and + // connect the profile interrupt. + // + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + PCR->InterruptRoutine[PROFILE_LEVEL] = HalpProfileInterrupt; + + return TRUE; +} + +VOID +KeStallExecutionProcessor ( + IN ULONG MicroSeconds + ) + +/*++ + +Routine Description: + + This function stalls execution of the current processor for the specified + number of microseconds. + +Arguments: + + MicroSeconds - Supplies the number of microseconds that execution is to + be stalled. + +Return Value: + + None. + +--*/ + +{ + + ULONG Index; + + // + // Use the stall scale factor to determine the number of iterations + // the wait loop must be executed to stall the processor for the + // specified number of microseconds. + // + + Index = MicroSeconds * PCR->StallScaleFactor; + do { + PCR->StallExecutionCount += 1; + Index -= 1; + } while (Index > 0); + + return; +} + +VOID +HalpStallInterrupt ( + VOID + ) + +/*++ + +Routine Description: + + This function serves as the stall calibration interrupt service + routine. It is executed in response to system clock interrupts + during the initialization of the HAL layer. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + // + // If this is the very first interrupt, then wait for the second + // interrupt before starting the timing interval. Else, if this + // the second interrupt, then capture the starting stall count + // and clear the count register on R4000 processors. Else, if this + // is the third interrupt, then capture the ending stall count and + // the ending count register on R4000 processors. Else, if this is + // the fourth or subsequent interrupt, then simply dismiss it. + // + + if ((HalpStallStart == 0) && (HalpStallEnd == 0)) { + HalpStallEnd = 1; + + } else if ((HalpStallStart == 0) && (HalpStallEnd != 0)) { + HalpStallStart = PCR->StallExecutionCount; + HalpStallEnd = 0; + HalpWriteCompareRegisterAndClear(0); + } else if ((HalpStallStart != 0) && (HalpStallEnd == 0)) { + HalpStallEnd = PCR->StallExecutionCount; + HalpProfileCountRate = HalpWriteCompareRegisterAndClear(0); + } + return; +} diff --git a/private/ntos/nthals/halflex/mips/xxidle.s b/private/ntos/nthals/halflex/mips/xxidle.s new file mode 100644 index 000000000..d0cd9c78b --- /dev/null +++ b/private/ntos/nthals/halflex/mips/xxidle.s @@ -0,0 +1,79 @@ +// TITLE("Processor Idle") +//++ +// +// Copyright (c) 1994 Microsoft Corporation +// +// Module Name: +// +// xxidle.s +// +// Abstract: +// +// This module implements system platform dependent power management +// support. +// +// Author: +// +// David N. Cutler (davec) 5-Mar-1994 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +#include "halmips.h" + + SBTTL("Processor Idle") +//++ +// +// VOID +// HalProcessorIdle( +// VOID +// ) +// +// Routine Description: +// +// This function is called when the current processor is idle with +// interrupts disabled. There is no thread active and there are no +// DPCs to process. Therefore, power can be switched to a standby +// mode until the the next interrupt occurs on the current processor. +// +// N.B. This routine is entered with IE in PSR clear. This routine +// must do any power management enabling necessary, set the IE +// bit in PSR, then either return or wait for an interrupt. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalProcessorIdle) + +// +// Perform power management enabling. +// + + .set noreorder + .set noat + mfc0 v0,psr // get current PSR + nop // fill + or v0,v0,1 << PSR_IE // set interrupt enable. + mtc0 v0,psr // enable interrupts + .set at + .set reorder + +// +// Wait for an interrupt if supported. +// + + j ra // return + + .end HalProcessorIdle diff --git a/private/ntos/nthals/halflex/mips/xxinitnt.c b/private/ntos/nthals/halflex/mips/xxinitnt.c new file mode 100644 index 000000000..b8b757141 --- /dev/null +++ b/private/ntos/nthals/halflex/mips/xxinitnt.c @@ -0,0 +1,159 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + xxinitnt.c + +Abstract: + + + This module implements the interrupt initialization for a MIPS R3000 + or R4000 system. + +Author: + + David N. Cutler (davec) 26-Apr-1991 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "halp.h" + +// +// Define the IRQL mask and level mapping table. +// +// These tables are transfered to the PCR and determine the priority of +// interrupts. +// +// N.B. The two software interrupt levels MUST be the lowest levels. +// + +UCHAR HalpIrqlMask[] = {4, 3, 3, 3, 3, 3, 3, 3, // 0000 - 0111 high 4-bits + 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits + 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits + 4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits + +UCHAR HalpIrqlTable[] = {0x8f, // IRQL 0 + 0x8e, // IRQL 1 + 0x8c, // IRQL 2 + 0x88, // IRQL 3 + 0x80, // IRQL 4 + 0x80, // IRQL 5 + 0x80, // IRQL 6 + 0x80, // IRQL 7 + 0x00}; // IRQL 8 + + +VOID +HalpCountInterrupt ( + VOID + ) + +/*++ + +Routine Description: + + This function serves as the R4000 count/compare interrupt service + routine early in the system initialization. Its only function is + to field and acknowledge count/compare interrupts during the system + boot process. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + // + // Acknowledge the R4000 count/compare interrupt. + // + + HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT); + return; +} + + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ) + +/*++ + +Routine Description: + + This function initializes interrupts for a MIPS R3000 or R4000 system. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the initialization is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +{ + ULONG Index; + PKPRCB Prcb; + + // + // Mask sure that all processor interrupts are inactive by masking off all device + // interrupts in the system's Programable Interrupt Controllers. + // + + HalpDisableAllInterrupts(); + + // + // Get the address of the processor control block for the current + // processor. + // + + Prcb = PCR->Prcb; + + // + // Initialize the IRQL translation tables in the PCR. These tables are + // used by the interrupt dispatcher to determine the new IRQL and the + // mask value that is to be loaded into the PSR. They are also used by + // the routines that raise and lower IRQL to load a new mask value into + // the PSR. + // + + for (Index = 0; Index < sizeof(HalpIrqlMask); Index += 1) { + PCR->IrqlMask[Index] = HalpIrqlMask[Index]; + } + + for (Index = 0; Index < sizeof(HalpIrqlTable); Index += 1) { + PCR->IrqlTable[Index] = HalpIrqlTable[Index]; + } + + // + // Connect the clock interrupt to the stall interrupt routine. + // + + PCR->InterruptRoutine[UNIFLEX_CLOCK2_LEVEL] = HalpStallInterrupt; + + // + // Connect the R4000 count/compare interrupt to the early interrupt + // routine. + // + + PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt; + + return TRUE; +} |