summaryrefslogblamecommitdiffstats
path: root/private/ntos/nthals/halflex/mips/flushio.c
blob: 985601ccce860046424bfdd3688bbe697c01bec8 (plain) (tree)

























































































































































































































































































                                                                                                  
/*++

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;
}