265 lines
6.6 KiB
C
265 lines
6.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 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 system.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 24-Apr-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
|
||
|
||
extern PVOID SecondaryCachePurgeBaseAddress;
|
||
|
||
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;
|
||
KIRQL OldIrql;
|
||
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) &&
|
||
(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))) {
|
||
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();
|
||
}
|
||
|
||
} 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);
|
||
|
||
} 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);
|
||
}
|
||
|
||
// If this is a read operation involving a DMA device, then purge the
|
||
// secondary write through cache by performing read operations in the
|
||
// appropriate range of SecondaryCachePurgeBaseAddress
|
||
|
||
if (ReadOperation != FALSE && DmaOperation != FALSE) {
|
||
|
||
volatile ULONG i;
|
||
volatile ULONG j;
|
||
ULONG PurgeOffset;
|
||
|
||
Offset = Mdl->ByteOffset & PCR->DcacheAlignment;
|
||
|
||
Length = (Mdl->ByteCount +
|
||
PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment;
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
PurgeOffset = ((((*PageFrame)<<12) | (Source&0xfff)) & 0x7fff0);
|
||
|
||
HalpPurgeSecondaryCachePage((PVOID)((ULONG)SecondaryCachePurgeBaseAddress + PurgeOffset),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;
|
||
}
|