mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
610 lines
14 KiB
610 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
j4flshio.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the system dependent kernel function to flush
|
|
the data cache for I/O transfers on a MIPS R4000 Jazz, Fision, Fusion,
|
|
or Duo system.
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a wrapper for the HalpSweepIcache() routine
|
|
implemented in j4cache.s
|
|
|
|
It was necessary to implement this wrapper in order to allow
|
|
us to get a TLB mapping for the ECache invalidate register without
|
|
having to steal (hack) an R4x00 tlb entry from the kernel without
|
|
it knowing.
|
|
|
|
The wrapper is somewhat complicated in that depending on which
|
|
point in the initialization stages (Phase 0 or Phase 1) the sweep
|
|
routine is called, the tlb mapping must be gotten either through
|
|
an a call to KeFillFixedEntryTb() which uses a "wired" entry or
|
|
through MmMapIoSpace() which is the normal method for mapping
|
|
registers, buffers, etc.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
HalSweepDcache(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Temp;
|
|
PVOID SavedAddress, BaseAddress;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
|
|
//
|
|
// Determine who is the caller:
|
|
//
|
|
// - the HAL
|
|
// - the kernel
|
|
//
|
|
|
|
if (HalpPmpHalFlushIoBuffer) {
|
|
|
|
//
|
|
// There are 3 cases:
|
|
//
|
|
// case 1: before HalpMapIoSpace() is called
|
|
//
|
|
// case 2: after HalpMapIoSpace() is called
|
|
//
|
|
// case 3: before HalpMapFixedTbEntries() is called
|
|
//
|
|
|
|
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
|
|
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(1);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
|
|
HalpExtPmpControl = (PVOID)NULL;
|
|
|
|
} else if ((HalpPmpExternalCachePresent == 0) || (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(HalpPmpExternalCachePresent);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
SavedAddress = HalpExtPmpControl;
|
|
|
|
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
|
|
|
|
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
|
|
|
|
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
|
|
|
|
//
|
|
// Unap ECache invalidate register
|
|
//
|
|
|
|
HalpUnMapSysCtrlReg();
|
|
|
|
HalpExtPmpControl = SavedAddress;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// There are 3 cases:
|
|
//
|
|
// case 1: before HalpMapIoSpace() is called
|
|
//
|
|
// case 2: after HalpMapIoSpace() is called
|
|
//
|
|
// case 3: before HalpMapFixedTbEntries() is called
|
|
//
|
|
|
|
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
|
|
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(1);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
|
|
HalpExtPmpControl = (PVOID)NULL;
|
|
|
|
} else if ((HalpPmpExternalCachePresent == 1) || (HalpPmpExternalCachePresent == 0)) {
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(HalpPmpExternalCachePresent);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
SavedAddress = HalpExtPmpControl;
|
|
|
|
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
|
|
|
|
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
|
|
|
|
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepDcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
HalpUnMapSysCtrlReg();
|
|
|
|
HalpExtPmpControl = SavedAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a wrapper for the HalpSweepIcache() routine
|
|
implemented in j4cache.s
|
|
|
|
It was necessary to implement this wrapper in order to allow
|
|
us to get a TLB mapping for the ECache invalidate register without
|
|
having to steal (hack) an R4x00 tlb entry from the kernel without
|
|
it knowing.
|
|
|
|
The wrapper is somewhat complicated in that depending on which
|
|
point in the initialization stages (Phase 0 or Phase 1) the sweep
|
|
routine is called, the tlb mapping must be gotten either through
|
|
an a call to KeFillFixedEntryTb() which uses a "wired" entry or
|
|
through MmMapIoSpace() which is the normal method for mapping
|
|
registers, buffers, etc.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
VOID
|
|
HalSweepIcache(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Temp;
|
|
PVOID SavedAddress, BaseAddress;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
|
|
//
|
|
// Determine who is the caller:
|
|
//
|
|
// - the HAL
|
|
// - the kernel
|
|
//
|
|
|
|
if (HalpPmpHalFlushIoBuffer) {
|
|
|
|
//
|
|
// There are 3 cases:
|
|
//
|
|
// case 1: before HalpMapIoSpace() is called
|
|
//
|
|
// case 2: after HalpMapIoSpace() is called
|
|
//
|
|
// case 3: before HalpMapFixedTbEntries() is called
|
|
//
|
|
|
|
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
|
|
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepIcache(1);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
|
|
HalpExtPmpControl = (PVOID)NULL;
|
|
|
|
} else if ((HalpPmpExternalCachePresent == 0) || (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepIcache(HalpPmpExternalCachePresent);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
SavedAddress = HalpExtPmpControl;
|
|
|
|
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
|
|
|
|
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
|
|
|
|
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepIcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
HalpUnMapSysCtrlReg();
|
|
|
|
HalpExtPmpControl = SavedAddress;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// There are 3 cases:
|
|
//
|
|
// case 1: before HalpMapIoSpace() is called
|
|
//
|
|
// case 2: after HalpMapIoSpace() is called
|
|
//
|
|
// case 3: before HalpMapFixedTbEntries() is called
|
|
//
|
|
|
|
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
|
|
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
|
|
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
|
|
|
|
//
|
|
// Sweep Icache and ECache
|
|
//
|
|
|
|
HalpSweepIcache(1);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
|
|
HalpExtPmpControl = (PVOID)NULL;
|
|
|
|
} else if ((HalpPmpExternalCachePresent == 1) || (HalpPmpExternalCachePresent == 0)) {
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepIcache(HalpPmpExternalCachePresent);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Map ECache invalidate register
|
|
//
|
|
|
|
SavedAddress = HalpExtPmpControl;
|
|
|
|
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
|
|
|
|
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
|
|
|
|
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
|
|
|
|
//
|
|
// Sweep caches
|
|
//
|
|
|
|
HalpSweepIcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
|
|
|
|
//
|
|
// Unmap ECache invalidate register
|
|
//
|
|
|
|
HalpUnMapSysCtrlReg();
|
|
|
|
HalpExtPmpControl = SavedAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
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, flush 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) &&
|
|
(Length > PCR->SecondLevelDcacheSize)) {
|
|
|
|
//
|
|
// 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))) {
|
|
|
|
HalpPmpHalFlushIoBuffer = 1;
|
|
HalSweepDcache();
|
|
HalpPmpHalFlushIoBuffer = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// 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)) {
|
|
|
|
HalpPmpHalFlushIoBuffer = 1;
|
|
HalSweepIcache();
|
|
HalpPmpHalFlushIoBuffer = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Flush 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;
|
|
|
|
//
|
|
// Flush 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 flush the data cache.
|
|
//
|
|
|
|
if (DmaOperation != FALSE) {
|
|
HalPurgeDcachePage((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;
|
|
}
|