|
|
/*++
Copyright (c) 1998 VIA Technologies, Inc. and Microsoft Corporation
Module Name:
gart.c
Abstract:
Routines for querying and setting the VIA VT82C597 ... GART aperture
Revision History:
--*/ #include "viaagp.h"
//
// Local function prototypes
//
NTSTATUS AgpVIACreateGart( IN PAGPVIA_EXTENSION AgpContext, IN ULONG MinimumPages );
NTSTATUS AgpVIASetRate( IN PVOID AgpContext, IN ULONG AgpRate );
PGART_PTE AgpVIAFindRangeInGart( IN PGART_PTE StartPte, IN PGART_PTE EndPte, IN ULONG Length, IN BOOLEAN SearchBackward, IN ULONG SearchState );
VOID AgpVIAFlushPageTLB( IN PAGPVIA_EXTENSION AgpContext );
VOID AgpVIAFlushData( IN PAGPVIA_EXTENSION AgpContext );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, AgpDisableAperture)
#pragma alloc_text(PAGE, AgpQueryAperture)
#pragma alloc_text(PAGE, AgpVIAFlushData)
#pragma alloc_text(PAGE, AgpVIAFlushPageTLB)
#pragma alloc_text(PAGE, AgpMapMemory)
#pragma alloc_text(PAGE, AgpUnMapMemory)
#pragma alloc_text(PAGE, AgpReserveMemory)
#pragma alloc_text(PAGE, AgpReleaseMemory)
#pragma alloc_text(PAGE, AgpVIACreateGart)
#pragma alloc_text(PAGE, AgpVIAFindRangeInGart)
#pragma alloc_text(PAGE, AgpFindFreeRun)
#pragma alloc_text(PAGE, AgpGetMappedPages)
#endif
#define VIA_FIRST_AVAILABLE_PTE 0
NTSTATUS AgpQueryAperture( IN PAGPVIA_EXTENSION AgpContext, OUT PHYSICAL_ADDRESS *CurrentBase, OUT ULONG *CurrentSizeInPages, OUT OPTIONAL PIO_RESOURCE_LIST *ApertureRequirements ) /*++
Routine Description:
Queries the current size of the GART aperture. Optionally returns the possible GART settings.
Arguments:
AgpContext - Supplies the AGP context.
CurrentBase - Returns the current physical address of the GART.
CurrentSizeInPages - Returns the current GART size.
ApertureRequirements - if present, returns the possible GART settings
Return Value:
NTSTATUS
--*/
{ ULONG GaBase; UCHAR GaSize; PIO_RESOURCE_LIST Requirements; ULONG i; ULONG Length;
PAGED_CODE();
//
// Get the current GABASE and GASIZE settings
//
ReadVIAConfig(&GaBase, GABASE_OFFSET, sizeof(GaBase)); ReadVIAConfig(&GaSize, GASIZE_OFFSET, sizeof(GaSize));
ASSERT(GaBase != 0); CurrentBase->QuadPart = GaBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
//
// Convert APSIZE into the actual size of the aperture
//
switch (GaSize) { case GA_SIZE_1MB: *CurrentSizeInPages = (1 * 1024*1024) / PAGE_SIZE; break; case GA_SIZE_2MB: *CurrentSizeInPages = (2 * 1024*1024) / PAGE_SIZE; break; case GA_SIZE_4MB: *CurrentSizeInPages = (4 * 1024*1024) / PAGE_SIZE; break; case GA_SIZE_8MB: *CurrentSizeInPages = 8 * (1024*1024 / PAGE_SIZE); break; case GA_SIZE_16MB: *CurrentSizeInPages = 16 * (1024*1024 / PAGE_SIZE); break; case GA_SIZE_32MB: *CurrentSizeInPages = 32 * (1024*1024 / PAGE_SIZE); break; case GA_SIZE_64MB: *CurrentSizeInPages = 64 * (1024*1024 / PAGE_SIZE); break; case GA_SIZE_128MB: *CurrentSizeInPages = 128 * (1024*1024 / PAGE_SIZE); break; case GA_SIZE_256MB: *CurrentSizeInPages = 256 * (1024*1024 / PAGE_SIZE); break;
default: AGPLOG(AGP_CRITICAL, ("VIAAGP - AgpQueryAperture - Unexpected value %x for GaSize!\n", GaSize)); ASSERT(FALSE); AgpContext->ApertureStart.QuadPart = 0; AgpContext->ApertureLength = 0; return(STATUS_UNSUCCESSFUL); }
//
// Remember the current aperture settings
//
AgpContext->ApertureStart.QuadPart = CurrentBase->QuadPart; AgpContext->ApertureLength = *CurrentSizeInPages * PAGE_SIZE;
if (ApertureRequirements != NULL) {
//
// VIA supports 9 different aperture sizes, all must be
// naturally aligned. Start with the largest aperture and
// work downwards so that we get the biggest possible aperture.
//
Requirements = ExAllocatePoolWithTag(PagedPool, sizeof(IO_RESOURCE_LIST) + (GA_SIZE_COUNT-1)*sizeof(IO_RESOURCE_DESCRIPTOR), 'RpgA');
if (Requirements == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); } Requirements->Version = Requirements->Revision = 1; Requirements->Count = GA_SIZE_COUNT; Length = GA_MAX_SIZE; for (i=0; i<GA_SIZE_COUNT; i++) { Requirements->Descriptors[i].Option = IO_RESOURCE_ALTERNATIVE; Requirements->Descriptors[i].Type = CmResourceTypeMemory; Requirements->Descriptors[i].ShareDisposition = CmResourceShareDeviceExclusive; Requirements->Descriptors[i].Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_PREFETCHABLE;
Requirements->Descriptors[i].u.Memory.Length = Length; Requirements->Descriptors[i].u.Memory.Alignment = Length; Requirements->Descriptors[i].u.Memory.MinimumAddress.QuadPart = 0; Requirements->Descriptors[i].u.Memory.MaximumAddress.QuadPart = (ULONG)-1;
Length = Length/2; } *ApertureRequirements = Requirements; }
return(STATUS_SUCCESS); }
NTSTATUS AgpSetAperture( IN PAGPVIA_EXTENSION AgpContext, IN PHYSICAL_ADDRESS NewBase, IN ULONG NewSizeInPages ) /*++
Routine Description:
Sets the GART aperture to the supplied settings
Arguments:
AgpContext - Supplies the AGP context
NewBase - Supplies the new physical memory base for the GART.
NewSizeInPages - Supplies the new size for the GART
Return Value:
NTSTATUS
--*/
{ VIA_GATT_BASE GATTBase; UCHAR GaSize; ULONG GaBase;
//
// Figure out the new APSIZE setting, make sure it is valid.
//
switch (NewSizeInPages) { case 1 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_1MB; break; case 2 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_2MB; break; case 4 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_4MB; break; case 8 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_8MB; break; case 16 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_16MB; break; case 32 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_32MB; break; case 64 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_64MB; break; case 128 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_128MB; break; case 256 * 1024 * 1024 / PAGE_SIZE: GaSize = GA_SIZE_256MB; break; default: AGPLOG(AGP_CRITICAL, ("AgpSetAperture - invalid GART size of %lx pages specified, aperture at %I64X.\n", NewSizeInPages, NewBase.QuadPart)); ASSERT(FALSE); return(STATUS_INVALID_PARAMETER); }
//
// Make sure the supplied size is aligned on the appropriate boundary.
//
ASSERT(NewBase.HighPart == 0); ASSERT((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) == 0); if ((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) != 0 ) { AGPLOG(AGP_CRITICAL, ("AgpSetAperture - invalid base %I64X specified for GART aperture of %lx pages\n", NewBase.QuadPart, NewSizeInPages)); return(STATUS_INVALID_PARAMETER); }
//
// Reprogram Special Target settings when the chip
// is powered off, but ignore rate changes as those were already
// applied during MasterInit
//
if (AgpContext->SpecialTarget & ~AGP_FLAG_SPECIAL_RESERVE) { AgpSpecialTarget(AgpContext, AgpContext->SpecialTarget & ~AGP_FLAG_SPECIAL_RESERVE); }
//
// Need to reset the hardware to match the supplied settings
//
// If the aperture is enabled, disable it, write the new settings, then
// reenable the aperture
//
ViaApertureEnable(OFF);
//
// Write GASIZE first, as this will enable the correct bits in GABASE that
// need to be written next.
//
WriteVIAConfig(&GaSize, GASIZE_OFFSET, sizeof(GaSize));
//
// While the aperture base address is changed, 88[1] must be set as 1,
// otherwise the high aperture address will not change.
//
ViaGartEnable(ON);
//
// Now we can update GABASE
//
GaBase = NewBase.LowPart & PCI_ADDRESS_MEMORY_ADDRESS_MASK; WriteVIAConfig(&GaBase, GABASE_OFFSET, sizeof(GaBase));
#if DBG
//
// Read back what we wrote, make sure it worked
//
{ ULONG DbgBase; UCHAR DbgSize;
ReadVIAConfig(&DbgSize, GASIZE_OFFSET, sizeof(GaSize)); ReadVIAConfig(&DbgBase, GABASE_OFFSET, sizeof(GaBase)); ASSERT(DbgSize == GaSize); ASSERT((DbgBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK) == GaBase); } #endif
//
// Now enable the aperture if it was enabled before
//
// EFNfix: Apparently code was added (above) which indiscriminantly
// enables aperture, so we must turn it off if !GlobalEnable
//
if (AgpContext->GlobalEnable == FALSE) { ViaApertureEnable(OFF); } else { ViaApertureEnable(ON); }
//
// Update our extension to reflect the new GART setting
//
AgpContext->ApertureStart = NewBase; AgpContext->ApertureLength = NewSizeInPages * PAGE_SIZE;
//
// Enable the TB in case we are resuming from S3 or S4
//
//
// If the GART has been allocated, rewrite the GARTBASE
//
if (AgpContext->Gart != NULL) { ULONG uTmpPhysAddr;
ReadVIAConfig(&uTmpPhysAddr, GATTBASE_OFFSET, sizeof(uTmpPhysAddr)); uTmpPhysAddr = (AgpContext->GartPhysical.LowPart & 0xFFFFF000) | (uTmpPhysAddr & 0x00000FFF); WriteVIAConfig(&uTmpPhysAddr, GATTBASE_OFFSET, sizeof(uTmpPhysAddr)); }
return(STATUS_SUCCESS); }
VOID AgpDisableAperture( IN PAGPVIA_EXTENSION AgpContext ) /*++
Routine Description:
Disables the GART aperture so that this resource is available for other devices
Arguments:
AgpContext - Supplies the AGP context
Return Value:
None - this routine must always succeed.
--*/
{ //
// Disable the aperture
//
ViaApertureEnable(OFF); AgpContext->GlobalEnable = FALSE;
//
// Nuke the Gart! (It's meaningless now...)
//
if (AgpContext->Gart != NULL) { MmFreeContiguousMemory(AgpContext->Gart); AgpContext->Gart = NULL; AgpContext->GartLength = 0; } }
NTSTATUS AgpReserveMemory( IN PAGPVIA_EXTENSION AgpContext, IN OUT AGP_RANGE *Range ) /*++
Routine Description:
Reserves a range of memory in the GART.
Arguments:
AgpContext - Supplies the AGP Context
Range - Supplies the AGP_RANGE structure. AGPLIB will have filled in NumberOfPages and Type. This routine will fill in MemoryBase and Context.
Return Value:
NTSTATUS
--*/
{ ULONG Index; ULONG NewState; NTSTATUS Status; PGART_PTE FoundRange; BOOLEAN Backwards;
PAGED_CODE();
ASSERT((Range->Type == MmNonCached) || (Range->Type == MmWriteCombined)); ASSERT(Range->NumberOfPages <= (AgpContext->ApertureLength / PAGE_SIZE));
//
// If we have not allocated our GART yet, now is the time to do so
//
if (AgpContext->Gart == NULL) { ASSERT(AgpContext->GartLength == 0); Status = AgpVIACreateGart(AgpContext,Range->NumberOfPages); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_CRITICAL, ("AgpVIACreateGart failed %08lx to create GART of size %lx\n", Status, AgpContext->ApertureLength)); return(Status); } } ASSERT(AgpContext->GartLength != 0);
//
// Now that we have a GART, try and find enough contiguous entries to satisfy
// the request. Requests for uncached memory will scan from high addresses to
// low addresses. Requests for write-combined memory will scan from low addresses
// to high addresses. We will use a first-fit algorithm to try and keep the allocations
// packed and contiguous.
//
Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE; FoundRange = AgpVIAFindRangeInGart(&AgpContext->Gart[VIA_FIRST_AVAILABLE_PTE], &AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1], Range->NumberOfPages, Backwards, GART_ENTRY_FREE);
if (FoundRange == NULL) { //
// A big enough chunk was not found.
//
AGPLOG(AGP_CRITICAL, ("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n", Range->NumberOfPages, Range->Type, AgpContext->Gart));
//
// This is where we could try and grow the GART
//
return(STATUS_INSUFFICIENT_RESOURCES); }
AGPLOG(AGP_NOISE, ("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n", Range->NumberOfPages, FoundRange));
//
// Set these pages to reserved
//
if (Range->Type == MmNonCached) { NewState = GART_ENTRY_RESERVED_UC; } else { NewState = GART_ENTRY_RESERVED_WC; }
for (Index = 0;Index < Range->NumberOfPages; Index++) { ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE); FoundRange[Index].AsUlong = 0; FoundRange[Index].Soft.State = NewState; }
Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart + (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE; Range->Context = FoundRange;
ASSERT(Range->MemoryBase.HighPart == 0); AGPLOG(AGP_NOISE, ("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n", FoundRange, Range->MemoryBase.LowPart));
return(STATUS_SUCCESS); }
NTSTATUS AgpReleaseMemory( IN PAGPVIA_EXTENSION AgpContext, IN PAGP_RANGE Range ) /*++
Routine Description:
Releases memory previously reserved with AgpReserveMemory
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the range to be released.
Return Value:
NTSTATUS
--*/
{ PGART_PTE Pte; ULONG Start;
PAGED_CODE()
//
// Go through and free all the PTEs. None of these should still
// be valid at this point.
//
for (Pte = Range->Context; Pte < (PGART_PTE)Range->Context + Range->NumberOfPages; Pte++) { if (Range->Type == MmNonCached) { ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC); } else { ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC); } Pte->Soft.State = GART_ENTRY_FREE; }
Range->MemoryBase.QuadPart = 0; return(STATUS_SUCCESS); }
#define AGP_TEST_SIGNATURE 0xAA55AA55
NTSTATUS AgpVIACreateGart( IN PAGPVIA_EXTENSION AgpContext, IN ULONG MinimumPages ) /*++
Routine Description:
Allocates and initializes an empty GART. The current implementation attempts to allocate the entire GART on the first reserve.
Arguments:
AgpContext - Supplies the AGP context
MinimumPages - Supplies the minimum size (in pages) of the GART to be created.
Return Value:
NTSTATUS
--*/
{ PHYSICAL_ADDRESS LowestAcceptable; PHYSICAL_ADDRESS BoundaryMultiple; PGART_PTE Gart; ULONG GartLength; ULONG TempPhysAddr; PHYSICAL_ADDRESS HighestAcceptable; PHYSICAL_ADDRESS GartPhysical; PULONG TestPage; ULONG i;
PAGED_CODE(); //
// Try and get a chunk of contiguous memory big enough to map the
// entire aperture.
//
LowestAcceptable.QuadPart = 0; BoundaryMultiple.QuadPart = (ULONGLONG)VIA_GART_ALIGN(AgpContext->ApertureLength); HighestAcceptable.QuadPart = 0xFFFFFFFF; GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);
Gart = MmAllocateContiguousMemorySpecifyCache(GartLength, LowestAcceptable, HighestAcceptable, BoundaryMultiple, MmNonCached); if (Gart == NULL) { AGPLOG(AGP_CRITICAL, ("AgpVIACreateGart - MmAllocateContiguousMemory %lx failed\n", GartLength)); return(STATUS_INSUFFICIENT_RESOURCES); }
//
// We successfully allocated a contiguous chunk of memory.
// It should be page aligned already.
//
ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
//
// Get the physical address.
//
GartPhysical = MmGetPhysicalAddress(Gart); AGPLOG(AGP_NOISE, ("AgpVIACreateGart - GART of length %lx created at VA %08lx, PA %08lx\n", GartLength, Gart, GartPhysical.LowPart)); ASSERT(GartPhysical.HighPart == 0); ASSERT(VIA_VERIFY_GART_ALIGN(GartPhysical.LowPart, AgpContext->ApertureLength));
//
// Initialize all the PTEs to free
//
for (i=0; i<GartLength/sizeof(GART_PTE); i++) { Gart[i].AsUlong = 0; Gart[i].Soft.State = GART_ENTRY_FREE; }
ReadVIAConfig(&TempPhysAddr, GATTBASE_OFFSET, sizeof(TempPhysAddr)); TempPhysAddr = (GartPhysical.LowPart & 0xFFFFF000) | (TempPhysAddr & 0x00000FFF); WriteVIAConfig(&TempPhysAddr, GATTBASE_OFFSET, sizeof(TempPhysAddr));
//
// Update our extension to reflect the current state.
//
AgpContext->Gart = Gart; AgpContext->GartLength = GartLength; AgpContext->GartPhysical = GartPhysical;
#if 0
//
// Test if AGP is working
//
LowestAcceptable.QuadPart = 0; BoundaryMultiple.QuadPart = 0; HighestAcceptable.QuadPart = 0xFFFFFFFF; TestPage = (PULONG)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowestAcceptable, HighestAcceptable, BoundaryMultiple, MmNonCached); if (TestPage) { PVOID ApertureVa; ULONG TestPte;
TestPage[0] = AGP_TEST_SIGNATURE; TestPte = MmGetPhysicalAddress(TestPage).LowPart; //
// Setup a translation so the first page at aperture base points
// to our test page
//
Gart[0].AsUlong = (((UINT_PTR)TestPte >> PAGE_SHIFT) * PAGE_SIZE) | GART_ENTRY_VALID; //
// Flush the write buffer
//
i = Gart[0].AsUlong;
//
// Flush the TLB
//
AgpVIAFlushPageTLB(AgpContext);
//
// Try to read our signature through the aperture/gart translation
//
ApertureVa = MmMapIoSpace(AgpContext->ApertureStart, PAGE_SIZE, MmNonCached); ASSERT(ApertureVa != NULL);
i = *(PULONG)ApertureVa;
AGPLOG(AGP_NOISE, ("AgpVIACreateGart AGP test: wrote (%08x) PA %08x=badceede, " "mapped gart[0] %08x=%08x, read AP_BASE (%08x) VA %08x=%08x\n", TestPage, TestPte, Gart, Gart[0].AsUlong, AgpContext->ApertureStart.LowPart, ApertureVa, i));
MmUnmapIoSpace(ApertureVa, PAGE_SIZE);
//
// Cleanup
//
Gart[0].AsUlong = 0; Gart[0].Soft.State = GART_ENTRY_FREE; TestPage[0] = Gart[0].AsUlong; AgpVIAFlushPageTLB(AgpContext); MmFreeContiguousMemory(TestPage);
//
// Turn off everything, and bail, AGP is broken
//
if (i != AGP_TEST_SIGNATURE) {
AGPLOG(AGP_CRITICAL, ("AgpVIACreateGart - AGP failed: Read=%08x\n", i));
AgpDisableAperture(AgpContext); //
// Need to let the user know what happened here
//
//AgpLogGenericHwFailure();
return STATUS_DEVICE_CONFIGURATION_ERROR; } } #endif
return(STATUS_SUCCESS); }
NTSTATUS AgpMapMemory( IN PAGPVIA_EXTENSION AgpContext, IN PAGP_RANGE Range, IN PMDL Mdl, IN ULONG OffsetInPages, OUT PHYSICAL_ADDRESS *MemoryBase ) /*++
Routine Description:
Maps physical memory into the GART somewhere in the specified range.
Arguments:
AgpContext - Supplies the AGP context
Range - Supplies the AGP range that the memory should be mapped into
Mdl - Supplies the MDL describing the physical pages to be mapped
MemoryBase - Returns the physical memory in the aperture where the pages were mapped.
Return Value:
NTSTATUS
--*/
{ ULONG PageCount; PGART_PTE Pte; PGART_PTE StartPte; ULONG Index; ULONG TargetState; PULONG Page; BOOLEAN Backwards; GART_PTE NewPte; VIA_GATT_BASE GATTBase; NTSTATUS Status;
PAGED_CODE();
ASSERT(Mdl->Next == NULL);
StartPte = Range->Context; PageCount = BYTES_TO_PAGES(Mdl->ByteCount); ASSERT(PageCount <= Range->NumberOfPages); ASSERT(PageCount > 0);
TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
Pte = StartPte + OffsetInPages;
//
// We have a suitable range, now fill it in with the supplied MDL.
//
ASSERT(Pte >= StartPte); ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages); NewPte.AsUlong = 0; NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC : GART_ENTRY_VALID_WC; Page = (PULONG)(Mdl + 1);
for (Index = 0; Index < PageCount; Index++) { ASSERT(Pte[Index].Soft.State == TargetState);
NewPte.Hard.Page = *Page++; Pte[Index].AsUlong = NewPte.AsUlong; ASSERT(Pte[Index].Hard.Valid == 1); }
//
// We have filled in all the PTEs. Read back the last one we wrote
// in order to flush the write buffers.
//
NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
//
// If we have not yet gotten around to enabling the GART aperture, do it now.
//
if (!AgpContext->GlobalEnable) { VIA_GATT_BASE GARTBASE_Config;
AGPLOG(AGP_NOISE, ("AgpMapMemory - Enabling global aperture access\n"));
ViaApertureEnable(ON);
ReadVIAConfig(&GARTBASE_Config, GATTBASE_OFFSET, sizeof(GARTBASE_Config));
GARTBASE_Config.TT_NonCache = 1;
WriteVIAConfig(&GARTBASE_Config, GATTBASE_OFFSET, sizeof(GARTBASE_Config));
ViaGartEnable(ON);
AgpContext->GlobalEnable = TRUE; }
MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
return(STATUS_SUCCESS); }
NTSTATUS AgpUnMapMemory( IN PAGPVIA_EXTENSION AgpContext, IN PAGP_RANGE AgpRange, IN ULONG NumberOfPages, IN ULONG PageOffset ) /*++
Routine Description:
Unmaps previously mapped memory in the GART.
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the AGP range that the memory should be mapped into
NumberOfPages - Supplies the number of pages in the range to be freed.
PageOffset - Supplies the offset into the range where the freeing should begin.
Return Value:
NTSTATUS
--*/
{ ULONG i; PGART_PTE Pte; PGART_PTE LastChanged=NULL; PGART_PTE StartPte; ULONG NewState;
PAGED_CODE();
ASSERT(PageOffset + NumberOfPages <= AgpRange->NumberOfPages);
StartPte = AgpRange->Context; Pte = &StartPte[PageOffset];
if (AgpRange->Type == MmNonCached) { NewState = GART_ENTRY_RESERVED_UC; } else { NewState = GART_ENTRY_RESERVED_WC; }
//
// Flush TLB
//
AgpVIAFlushPageTLB(AgpContext);
for (i=0; i<NumberOfPages; i++) { if (Pte[i].Hard.Valid) { Pte[i].Soft.State = NewState; LastChanged = Pte; } else { //
// This page is not mapped, just skip it.
//
AGPLOG(AGP_NOISE, ("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n", &Pte[i], Pte[i].AsUlong, i)); } }
//
// We have invalidated all the PTEs. Read back the last one we wrote
// in order to flush the write buffers.
//
if (LastChanged != NULL) { ULONG Temp; Temp = *(volatile ULONG *)(&LastChanged->AsUlong); }
return(STATUS_SUCCESS); }
PGART_PTE AgpVIAFindRangeInGart( IN PGART_PTE StartPte, IN PGART_PTE EndPte, IN ULONG Length, IN BOOLEAN SearchBackward, IN ULONG SearchState ) /*++
Routine Description:
Finds a contiguous range in the GART. This routine can search either from the beginning of the GART forwards or the end of the GART backwards.
Arguments:
StartIndex - Supplies the first GART pte to search
EndPte - Supplies the last GART to search (inclusive)
Length - Supplies the number of contiguous free entries to search for.
SearchBackward - TRUE indicates that the search should begin at EndPte and search backwards. FALSE indicates that the search should begin at StartPte and search forwards
SearchState - Supplies the PTE state to look for.
Return Value:
Pointer to the first PTE in the GART if a suitable range is found.
NULL if no suitable range exists.
--*/
{ PGART_PTE Current; PGART_PTE Last; LONG Delta; ULONG Found; PGART_PTE Candidate;
PAGED_CODE();
ASSERT(EndPte >= StartPte); ASSERT(Length <= (ULONG)(EndPte - StartPte + 1)); ASSERT(Length != 0);
if (SearchBackward) { Current = EndPte; Last = StartPte-1; Delta = -1; } else { Current = StartPte; Last = EndPte+1; Delta = 1; }
Found = 0; while (Current != Last) { if (Current->Soft.State == SearchState) { if (++Found == Length) { //
// A suitable range was found, return it
//
if (SearchBackward) { return(Current); } else { return(Current - Length + 1); } } } else { Found = 0; } Current += Delta; }
//
// A suitable range was not found.
//
return(NULL); }
VOID AgpVIAFlushPageTLB( IN PAGPVIA_EXTENSION AgpContext ) /*++
Routine Description:
Flush the AGP TLB (16 entries) if hardware does not support FLUSH TLB, then read Aperture 32 times
Arguments:
AgpContext - Supplies the AGP context
Return Value:
None
--*/
{ VIA_GART_TLB_CTRL GARTCTRL_Config;
PAGED_CODE();
if (AgpContext->Cap_FlushTLB) {
ReadVIAConfig(&GARTCTRL_Config, GARTCTRL_OFFSET, sizeof(GARTCTRL_Config));
//Flush TLB
GARTCTRL_Config.FlushPageTLB = 1; WriteVIAConfig(&GARTCTRL_Config, GARTCTRL_OFFSET, sizeof(GARTCTRL_Config));
//Stop Flush TLB
GARTCTRL_Config.FlushPageTLB = 0; WriteVIAConfig(&GARTCTRL_Config, GARTCTRL_OFFSET, sizeof(GARTCTRL_Config));
} else { AgpVIAFlushData(AgpContext); } }
VOID AgpFindFreeRun( IN PVOID AgpContext, IN PAGP_RANGE AgpRange, IN ULONG NumberOfPages, IN ULONG OffsetInPages, OUT ULONG *FreePages, OUT ULONG *FreeOffset ) /*++
Routine Description:
Finds the first contiguous run of free pages in the specified part of the reserved range.
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the AGP range
NumberOfPages - Supplies the size of the region to be searched for free pages
OffsetInPages - Supplies the start of the region to be searched for free pages
FreePages - Returns the length of the first contiguous run of free pages
FreeOffset - Returns the start of the first contiguous run of free pages
Return Value:
None. FreePages == 0 if there are no free pages in the specified range.
--*/
{ PGART_PTE Pte; ULONG i;
PAGED_CODE(); Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
//
// Find the first free PTE
//
for (i=0; i<NumberOfPages; i++) { if (Pte[i].Hard.Valid == 0) { //
// Found a free PTE, count the contiguous ones.
//
*FreeOffset = i + OffsetInPages; *FreePages = 0; while ((i<NumberOfPages) && (Pte[i].Hard.Valid == 0)) { *FreePages += 1; ++i; } return; } }
//
// No free PTEs in the specified range
//
*FreePages = 0; return;
}
VOID AgpGetMappedPages( IN PVOID AgpContext, IN PAGP_RANGE AgpRange, IN ULONG NumberOfPages, IN ULONG OffsetInPages, OUT PMDL Mdl ) /*++
Routine Description:
Returns the list of physical pages mapped into the specified range in the GART.
Arguments:
AgpContext - Supplies the AGP context
AgpRange - Supplies the AGP range
NumberOfPages - Supplies the number of pages to be returned
OffsetInPages - Supplies the start of the region
Mdl - Returns the list of physical pages mapped in the specified range.
Return Value:
None
--*/
{ PGART_PTE Pte; ULONG i; PULONG Pages;
PAGED_CODE();
ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
Pages = (PULONG)(Mdl + 1); Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
for (i=0; i<NumberOfPages; i++) { ASSERT(Pte[i].Hard.Valid == 1); Pages[i] = Pte[i].Hard.Page; } }
VOID AgpVIAFlushData( IN PAGPVIA_EXTENSION AgpContext ) /*++
Routine Description:
Flushes the chipset TB by reading 32 pages of aperture memory space.
Arguments:
AgpContext - Supplies the AGP context
Return Value:
NTSTATUS
--*/
{ PVOID ApertureVirtAddr, TempVirtualAddr; ULONG ReadData; ULONG Index;
PAGED_CODE();
ApertureVirtAddr = MmMapIoSpace(AgpContext->ApertureStart, 32 * PAGE_SIZE, MmNonCached);
ASSERT(ApertureVirtAddr != NULL);
if (ApertureVirtAddr != NULL) {
TempVirtualAddr = ApertureVirtAddr; for (Index = 0; Index < 32; Index++) { ReadData = *(PULONG)TempVirtualAddr; TempVirtualAddr = (PVOID)((PCCHAR)TempVirtualAddr + PAGE_SIZE); } MmUnmapIoSpace(ApertureVirtAddr, 32 * PAGE_SIZE); } else { AGPLOG(AGP_CRITICAL,("Agp440FlushPageTLB: Invalid address\n")); } }
NTSTATUS AgpSpecialTarget( IN PAGPVIA_EXTENSION AgpContext, IN ULONGLONG DeviceFlags ) /*++
Routine Description:
This routine makes "special" tweaks to the AGP chipset
Arguments:
AgpContext - Supplies the AGP context
DeviceFlags - Flags indicating what tweaks to perform
Return Value:
STATUS_SUCCESS, or error
--*/ { NTSTATUS Status;
//
// Should we change the AGP rate?
//
if (DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) {
Status = AgpVIASetRate(AgpContext, (ULONG)((DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) >> AGP_FLAG_SET_RATE_SHIFT)); if (!NT_SUCCESS(Status)) { return Status; } }
//
// Add more tweaks here...
//
AgpContext->SpecialTarget |= DeviceFlags;
return STATUS_SUCCESS; }
NTSTATUS AgpVIASetRate( IN PAGPVIA_EXTENSION AgpContext, IN ULONG AgpRate ) /*++
Routine Description:
This routine sets the AGP rate
Arguments:
AgpContext - Supplies the AGP context
AgpRate - Rate to set
note: this routine assumes that AGP has already been enabled, and that whatever rate we've been asked to set is supported by master
Return Value:
STATUS_SUCCESS, or error status
--*/ { NTSTATUS Status; ULONG TargetEnable; ULONG MasterEnable; PCI_AGP_CAPABILITY TargetCap; PCI_AGP_CAPABILITY MasterCap; BOOLEAN ReverseInit;
//
// Read capabilities
//
Status = AgpLibGetPciDeviceCapability(0, 0, &TargetCap);
if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibGetPciDeviceCapability " "failed %08lx\n", Status)); return Status; }
Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibGetMasterCapability " "failed %08lx\n", Status)); return Status; }
//
// Verify the requested rate is supported by both master and target
//
if (!(AgpRate & TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate)) { return STATUS_INVALID_PARAMETER; }
//
// Disable AGP while the pull the rug out from underneath
//
TargetEnable = TargetCap.AGPCommand.AGPEnable; TargetCap.AGPCommand.AGPEnable = 0;
Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibSetPciDeviceCapability %08lx for " "Target failed %08lx\n", &TargetCap, Status)); return Status; } MasterEnable = MasterCap.AGPCommand.AGPEnable; MasterCap.AGPCommand.AGPEnable = 0;
Status = AgpLibSetMasterCapability(AgpContext, &MasterCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed " "%08lx\n", &MasterCap, Status)); return Status; }
//
// Fire up AGP with new rate
//
ReverseInit = (AgpContext->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) == AGP_FLAG_REVERSE_INITIALIZATION; if (ReverseInit) { MasterCap.AGPCommand.Rate = AgpRate; MasterCap.AGPCommand.AGPEnable = MasterEnable; Status = AgpLibSetMasterCapability(AgpContext, &MasterCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed " "%08lx\n", &MasterCap, Status)); } }
TargetCap.AGPCommand.Rate = AgpRate; TargetCap.AGPCommand.AGPEnable = TargetEnable; Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibSetPciDeviceCapability %08lx for " "Target failed %08lx\n", &TargetCap, Status)); return Status; }
if (!ReverseInit) { MasterCap.AGPCommand.Rate = AgpRate; MasterCap.AGPCommand.AGPEnable = MasterEnable; Status = AgpLibSetMasterCapability(AgpContext, &MasterCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed " "%08lx\n", &MasterCap, Status)); } }
return Status; }
|