mirror of https://github.com/tongzx/nt5src
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.
1303 lines
32 KiB
1303 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gart.c
|
|
|
|
Abstract:
|
|
|
|
Routines for querying and setting the Intel 460xx GART aperture
|
|
|
|
Author:
|
|
|
|
Sunil A Kulkarni - 3/08/2000
|
|
|
|
Initial Version:
|
|
Naga Gurumoorthy - 6/11/1999
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "agp460.h"
|
|
|
|
//
|
|
// Local function prototypes
|
|
//
|
|
NTSTATUS
|
|
Agp460CreateGart(
|
|
IN PAGP460_EXTENSION AgpContext,
|
|
IN ULONG MinimumPages
|
|
);
|
|
|
|
NTSTATUS
|
|
Agp460SetRate(
|
|
IN PVOID AgpContext,
|
|
IN ULONG AgpRate
|
|
);
|
|
|
|
PGART_PTE
|
|
Agp460FindRangeInGart(
|
|
IN PGART_PTE StartPte,
|
|
IN PGART_PTE EndPte,
|
|
IN ULONG Length,
|
|
IN BOOLEAN SearchBackward,
|
|
IN ULONG SearchState
|
|
);
|
|
|
|
VOID
|
|
Agp460SetGTLB_Enable(
|
|
IN PAGP460_EXTENSION AgpContext,
|
|
IN BOOLEAN Enable
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, AgpQueryAperture)
|
|
#pragma alloc_text(PAGE, AgpReserveMemory)
|
|
#pragma alloc_text(PAGE, AgpReleaseMemory)
|
|
#pragma alloc_text(PAGE, Agp460CreateGart)
|
|
#pragma alloc_text(PAGE, AgpMapMemory)
|
|
#pragma alloc_text(PAGE, AgpUnMapMemory)
|
|
#pragma alloc_text(PAGE, Agp460FindRangeInGart)
|
|
#pragma alloc_text(PAGE, AgpFindFreeRun)
|
|
#pragma alloc_text(PAGE, AgpGetMappedPages)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
AgpQueryAperture(
|
|
IN PAGP460_EXTENSION AgpContext,
|
|
OUT PHYSICAL_ADDRESS *CurrentBase,
|
|
OUT ULONG *CurrentSizeInPages,
|
|
OUT OPTIONAL PIO_RESOURCE_LIST *pApertureRequirements
|
|
)
|
|
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG ApBase; //Aperture Base registers (APBASE & BAPBASE) are 64bit wide
|
|
UCHAR ApSize; //AGPSIZ register is 8bits
|
|
PIO_RESOURCE_LIST Requirements;
|
|
ULONG i;
|
|
ULONG Index;
|
|
ULONG Length;
|
|
ULONG CBN;
|
|
ULONG uiAp_Size_Count;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: AgpQueryAperture entered.\n"));
|
|
|
|
//
|
|
// Get the current APBASE and APSIZE settings
|
|
//
|
|
Read460CBN((PVOID)&CBN);
|
|
EXTRACT_LSBYTE(CBN); // Zero out bits (32-8) as CBN is 8-bit wide - Sunil
|
|
|
|
// Read the Aperture Size (AGPSIZ) first.
|
|
Read460Config(CBN,(PVOID) &ApSize, APSIZE_OFFSET, sizeof(ApSize));
|
|
EXTRACT_LSBYTE(ApSize); // Zero out bits (32-8) as ApSize is 8-bit wide - Sunil
|
|
|
|
// If AGPSIZ[3] is 1, then Aperture Base is stored in BAPBASE.
|
|
// else (when AGPSIZE[3] = 0, APBASE has the Aperture base address.
|
|
if (ABOVE_TOM(ApSize)){
|
|
Read460Config(CBN, (PVOID)&ApBase, BAPBASE_OFFSET, sizeof(ApBase));
|
|
}else{
|
|
Read460Config(CBN, (PVOID)&ApBase, APBASE_OFFSET, sizeof(ApBase));
|
|
}
|
|
|
|
ASSERT(ApBase != 0);
|
|
CurrentBase->QuadPart = ApBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK_64;
|
|
|
|
//
|
|
// Convert APSIZE into the actual size of the aperture.
|
|
// TO DO: Should we return the Current Size in OS page size or chipset page
|
|
// size ? - Naga G
|
|
//
|
|
*CurrentSizeInPages = 0;
|
|
|
|
if (ApSize & AP_SIZE_256MB) {
|
|
*CurrentSizeInPages = (AP_256MB / PAGE_SIZE);
|
|
|
|
} else {
|
|
if (ApSize & AP_SIZE_1GB) {
|
|
*CurrentSizeInPages = (AP_1GB / PAGE_SIZE);
|
|
}
|
|
|
|
// BUGBUG !32GB Aperture size is possible only with 4MB page size.
|
|
// Currently this is not handled. Once this case is included, the
|
|
// size of CurrentSizeInPages must be changed to ULONGLONG and there
|
|
// should be corresponding changes in the structures where this value
|
|
// will be stored - Sunil 3/16/00
|
|
//else{
|
|
// if (ApSize & AP_SIZE_32GB)
|
|
// *CurrentSizeInPages = (AP_32GB / PAGE_SIZE);
|
|
//}
|
|
}
|
|
|
|
//
|
|
// Remember the current aperture settings
|
|
//
|
|
AgpContext->ApertureStart.QuadPart = CurrentBase->QuadPart;
|
|
AgpContext->ApertureLength = *CurrentSizeInPages * PAGE_SIZE;
|
|
|
|
if (pApertureRequirements != NULL) {
|
|
|
|
//
|
|
// 460 supports only the boot config, or "preferred" descriptor
|
|
//
|
|
*pApertureRequirements = NULL;
|
|
}
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPQueryAperture.\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpSetAperture(
|
|
IN PAGP460_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
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR ApSize;
|
|
ULONGLONG ApBase;
|
|
ULONG CBN;
|
|
UCHAR ulTemp;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: AgpSetAperture entered.\n"));
|
|
|
|
//
|
|
// Figure out the new APSIZE setting, make sure it is valid.
|
|
//
|
|
switch (NewSizeInPages)
|
|
{
|
|
case AP_256MB / PAGE_SIZE:
|
|
ApSize = AP_SIZE_256MB;
|
|
break;
|
|
case AP_1GB / PAGE_SIZE:
|
|
ApSize = AP_SIZE_1GB;
|
|
break;
|
|
// TO DO: 4MB pages are not supported at this time. In the future,
|
|
// we might have to support it. - Naga G
|
|
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.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);
|
|
}
|
|
|
|
//
|
|
// Having validated the arguments now we need to reset the hardware
|
|
// to match the supplied settings.
|
|
//
|
|
// Unlike 440, 460GX has no hardware support to disable the use of GART table when
|
|
// we are writing the new settings.
|
|
//
|
|
|
|
//
|
|
// Read the CBN first
|
|
//
|
|
Read460CBN((PVOID)&CBN);
|
|
EXTRACT_LSBYTE(CBN); // Sunil
|
|
|
|
//
|
|
// Write APSIZE first, as this will enable the correct bits in APBASE that need to
|
|
// be written next.
|
|
//
|
|
|
|
Read460Config(CBN, &ulTemp, APSIZE_OFFSET, sizeof(ulTemp));
|
|
|
|
ulTemp &= 0xff;
|
|
|
|
ulTemp &= 0xF8; // To mask everything but the last 3 bits which contain
|
|
// the aperture size.
|
|
|
|
ulTemp |= ApSize; // Now, incorporate the new aperture size into the AGPSIZ
|
|
// keeping the first 5 bits as the same.
|
|
Write460Config(CBN, &ulTemp, APSIZE_OFFSET, sizeof(ulTemp));
|
|
|
|
|
|
//
|
|
// Now we can update APBASE
|
|
//
|
|
ApBase = NewBase.QuadPart & PCI_ADDRESS_MEMORY_ADDRESS_MASK_64;
|
|
|
|
if (ABOVE_TOM(ulTemp)){
|
|
Write460Config(CBN, &ApBase, BAPBASE_OFFSET, sizeof(ApBase));
|
|
}else{
|
|
Write460Config(CBN, &ApBase, APBASE_OFFSET, sizeof(ApBase));
|
|
}
|
|
|
|
|
|
#if DBG
|
|
//
|
|
// Read back what we wrote, make sure it worked
|
|
//
|
|
{
|
|
ULONGLONG DbgBase;
|
|
UCHAR DbgSize;
|
|
|
|
Read460Config(CBN,&DbgSize, APSIZE_OFFSET, sizeof(ApSize));
|
|
|
|
if (ABOVE_TOM(DbgSize)){
|
|
Read460Config(CBN, &DbgBase, BAPBASE_OFFSET, sizeof(ApBase));
|
|
}else{
|
|
Read460Config(CBN, &DbgBase, APBASE_OFFSET, sizeof(ApBase));
|
|
}
|
|
|
|
AGPLOG(AGP_NOISE, ("APBase %08lx, DbgBase %08lx\n",ApBase,DbgBase));
|
|
|
|
DbgSize &= 0x7; //Check only against size bits - Sunil
|
|
ASSERT(DbgSize == ApSize);
|
|
ASSERT((DbgBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK_64) == ApBase);
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Update our extension to reflect the new GART setting
|
|
//
|
|
AgpContext->ApertureStart = NewBase;
|
|
AgpContext->ApertureLength = NewSizeInPages * PAGE_SIZE;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AgpSetAperture.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
AgpDisableAperture(
|
|
IN PAGP460_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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AgpDisableAperture.\n"));
|
|
|
|
//
|
|
// In 82460GX there exists no hardware means to enable/disable the Graphics
|
|
// Aperture & GART Translation.
|
|
//
|
|
AgpContext->GlobalEnable = FALSE;
|
|
|
|
//
|
|
// TO DO: The only thing that could possibly be done is to set AGPSIZ[2:0] to 000
|
|
// which would indicate that there exists no GART. Need to try it out. - Naga G
|
|
//
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AgpDisableAperture.\n"));
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpReserveMemory(
|
|
IN PAGP460_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;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
|
|
PAGED_CODE();
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPReserveMemory.\n"));
|
|
|
|
ASSERT((Range->Type == MmNonCached) ||
|
|
(Range->Type == MmWriteCombined) ||
|
|
(Range->Type == MmCached));
|
|
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 = Agp460CreateGart(AgpContext,Range->NumberOfPages);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AGPLOG(AGP_CRITICAL,
|
|
("Agp460CreateGart failed %08lx to create GART of size %lx\n",
|
|
Status,
|
|
AgpContext->ApertureLength));
|
|
return(Status);
|
|
}
|
|
}
|
|
ASSERT(AgpContext->GartLength != 0);
|
|
|
|
// if OS page size is 8KB then, OS_ChipsetPagesizeRatio would be 2. To map x OS pages
|
|
// into the GART, we need x * OS_ChipsetPagesizeRatio of GART entries.
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
|
|
//
|
|
// 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 = Agp460FindRangeInGart(&AgpContext->Gart[0],
|
|
&AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
|
|
Range->NumberOfPages * OS_ChipsetPagesizeRatio,
|
|
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 * OS_ChipsetPagesizeRatio,
|
|
Range->Type,
|
|
AgpContext->Gart));
|
|
|
|
//
|
|
// BUGBUG John Vert (jvert) 11/4/1997
|
|
// This is the point where we should try and grow the GART
|
|
//
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
AGPLOG(AGP_NOISE,
|
|
("AgpReserveMemory - reserved %d pages at GART PTE %p\n",
|
|
Range->NumberOfPages * OS_ChipsetPagesizeRatio,
|
|
FoundRange));
|
|
|
|
//
|
|
// Set these pages to reserved
|
|
//
|
|
if (Range->Type == MmNonCached) {
|
|
NewState = GART_ENTRY_RESERVED_UC;
|
|
} else if (Range->Type == MmWriteCombined) {
|
|
NewState = GART_ENTRY_RESERVED_WC;
|
|
} else {
|
|
NewState = GART_ENTRY_RESERVED_WB;
|
|
}
|
|
|
|
for (Index = 0;Index < (Range->NumberOfPages * OS_ChipsetPagesizeRatio); Index++)
|
|
{
|
|
ASSERT( (FoundRange[Index].Soft.Valid == 0) &&
|
|
(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]) * AGP460_PAGE_SIZE_4KB;
|
|
Range->Context = FoundRange;
|
|
|
|
AGPLOG(AGP_NOISE,
|
|
("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
|
|
FoundRange,
|
|
Range->MemoryBase.QuadPart));
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPReserveMemory.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpReleaseMemory(
|
|
IN PAGP460_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;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
|
|
PAGED_CODE();
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPReleaseMemory.\n"));
|
|
|
|
// if OS page size is 8KB then, OS_ChipsetPagesizeRatio would be 2. To map x OS pages
|
|
// into the GART, we need x * OS_ChipsetPagesizeRatio of GART entries.
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
|
|
//
|
|
// 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 * OS_ChipsetPagesizeRatio);
|
|
Pte++) {
|
|
if (Range->Type == MmNonCached) {
|
|
ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
|
|
} else if (Range->Type == MmWriteCombined) {
|
|
ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
|
|
} else {
|
|
ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WB);
|
|
}
|
|
|
|
Pte->Soft.State = GART_ENTRY_FREE;
|
|
Pte->Soft.Valid = GART_ENTRY_FREE;
|
|
}
|
|
|
|
Range->MemoryBase.QuadPart = 0;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPReleaseMemory.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Agp460CreateGart(
|
|
IN PAGP460_EXTENSION AgpContext,
|
|
IN ULONG MinimumPages
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and initializes an empty GART. The 82460GX has a 2MB region for
|
|
GART. This memory starts at 0xFE20 0000h. In reality, this memory is a
|
|
SRAM that hangs off the GXB. The minimum pages argument is ignored.
|
|
|
|
Arguments:
|
|
|
|
AgpContext - Supplies the AGP context
|
|
|
|
MinimumPages - Supplies the minimum size (in pages) of the GART to be
|
|
created.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PGART_PTE Gart;
|
|
ULONG GartLength;
|
|
PHYSICAL_ADDRESS HighestAcceptable;
|
|
ULONG i;
|
|
PHYSICAL_ADDRESS GartStartingLocation;
|
|
|
|
PAGED_CODE();
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGP460CreateGART.\n"));
|
|
|
|
// Set the GArtLength to actual SRAM size on the GXB and not fixed size - Sunil
|
|
//GartLength = 1 * 1024 * 1024;
|
|
GartLength = AgpContext->ApertureLength / ONE_KB;
|
|
GartStartingLocation.QuadPart = ATTBASE;
|
|
|
|
Gart = MmMapIoSpace(GartStartingLocation,GartLength,MmNonCached);
|
|
|
|
if (Gart == NULL) {
|
|
AGPLOG(AGP_CRITICAL,
|
|
("Agp460CreateGart - couldn't map GART \n"));
|
|
} else {
|
|
|
|
AGPLOG(AGP_NOISE,
|
|
("Agp460CreateGart - GART of length %lx created at "
|
|
"VA %p, "
|
|
"PA %I64x\n",
|
|
GartLength,
|
|
Gart,
|
|
GartStartingLocation.QuadPart));
|
|
}
|
|
|
|
//
|
|
// Initialize all the PTEs to free
|
|
//
|
|
for (i=0; i<GartLength/sizeof(GART_PTE); i++) {
|
|
Gart[i].Soft.State = GART_ENTRY_FREE;
|
|
Gart[i].Soft.Valid = GART_ENTRY_FREE;
|
|
}
|
|
|
|
|
|
//
|
|
// Update our extension to reflect the current state.
|
|
//
|
|
|
|
AgpContext->Gart = Gart;
|
|
AgpContext->GartLength = GartLength;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGP460CreateGART.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpMapMemory(
|
|
IN PAGP460_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
|
|
|
|
OffsetInPages - Supplies the offset into the reserved range where the
|
|
mapping should begin.
|
|
|
|
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;
|
|
PULONGLONG Page;
|
|
BOOLEAN Backwards;
|
|
GART_PTE NewPte;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
ULONG RunningCounter;
|
|
|
|
PAGED_CODE();
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPMapMemory.\n"));
|
|
|
|
ASSERT(Mdl->Next == NULL);
|
|
|
|
StartPte = Range->Context;
|
|
PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
|
|
ASSERT(PageCount <= Range->NumberOfPages);
|
|
ASSERT(OffsetInPages <= Range->NumberOfPages);
|
|
ASSERT(PageCount + OffsetInPages <= Range->NumberOfPages);
|
|
ASSERT(PageCount > 0);
|
|
|
|
if (Range->Type == MmNonCached)
|
|
TargetState = GART_ENTRY_RESERVED_UC;
|
|
else if (Range->Type == MmWriteCombined)
|
|
TargetState = GART_ENTRY_RESERVED_WC;
|
|
else
|
|
TargetState = GART_ENTRY_RESERVED_WB;
|
|
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
|
|
Pte = StartPte + (OffsetInPages * OS_ChipsetPagesizeRatio);
|
|
|
|
//
|
|
// We have a suitable range, now fill it in with the supplied MDL.
|
|
//
|
|
ASSERT(Pte >= StartPte);
|
|
ASSERT(Pte + PageCount * OS_ChipsetPagesizeRatio <= StartPte + Range->NumberOfPages * OS_ChipsetPagesizeRatio);
|
|
NewPte.AsUlong = 0;
|
|
NewPte.Soft.Valid = TRUE;
|
|
if (Range->Type == MmCached) {
|
|
NewPte.Hard.Coherency = TRUE;
|
|
}
|
|
|
|
Page = (PULONGLONG)(Mdl + 1);
|
|
|
|
RunningCounter = 0;
|
|
//AGPLOG(AGP_NOISE, ("AGP460: Entering AGPMapMemory -- LOOP: Pte: %0x, newPte: %0x.\n",Pte,NewPte));
|
|
|
|
for (Index = 0; Index < (PageCount * OS_ChipsetPagesizeRatio); Index++)
|
|
{
|
|
ASSERT(Pte[Index].Soft.State == TargetState);
|
|
|
|
//NewPte.Hard.Page = *Page++;
|
|
NewPte.Hard.Page = (ULONG) (*Page << (PAGE_SHIFT - GART_PAGESHIFT_460GX)) + RunningCounter;
|
|
Pte[Index].AsUlong = NewPte.AsUlong;
|
|
ASSERT(Pte[Index].Hard.Valid == 1);
|
|
//AGPLOG(AGP_NOISE, ("AGP460: Page: %0x, newPte: %0x\n",Page,NewPte));
|
|
RunningCounter++;
|
|
|
|
if (RunningCounter == OS_ChipsetPagesizeRatio){
|
|
RunningCounter = 0;
|
|
Page++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
|
|
|
|
AgpContext->GlobalEnable = TRUE;
|
|
|
|
MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPMapMemory.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpUnMapMemory(
|
|
IN PAGP460_EXTENSION AgpContext,
|
|
IN PAGP_RANGE AgpRange,
|
|
IN ULONG NumberOfPages,
|
|
IN ULONG OffsetInPages
|
|
)
|
|
/*++
|
|
|
|
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 freed from
|
|
|
|
NumberOfPages - Supplies the number of pages in the range to be freed.
|
|
|
|
OffsetInPages - 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;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPUnMapMemory.\n"));
|
|
|
|
ASSERT(OffsetInPages + NumberOfPages <= AgpRange->NumberOfPages);
|
|
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
|
|
StartPte = AgpRange->Context;
|
|
Pte = &StartPte[OffsetInPages * OS_ChipsetPagesizeRatio];
|
|
|
|
if (AgpRange->Type == MmNonCached) {
|
|
NewState = GART_ENTRY_RESERVED_UC;
|
|
} else if (AgpRange->Type == MmWriteCombined) {
|
|
NewState = GART_ENTRY_RESERVED_WC;
|
|
} else {
|
|
NewState = GART_ENTRY_RESERVED_WB;
|
|
}
|
|
|
|
|
|
for (i=0; i < NumberOfPages * OS_ChipsetPagesizeRatio; i++) {
|
|
if (Pte[i].Hard.Valid) {
|
|
Pte[i].Soft.State = NewState;
|
|
Pte[i].Soft.Valid = FALSE;
|
|
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));
|
|
ASSERT(Pte[i].Soft.State == NewState);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPUnMapMemory.\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
PGART_PTE
|
|
Agp460FindRangeInGart(
|
|
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();
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGP460FindRangeInGART.\n"));
|
|
|
|
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) && (Current->Soft.Valid == 0))
|
|
{
|
|
if (++Found == Length) {
|
|
//
|
|
// A suitable range was found, return it
|
|
//
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGP460FindRangeInGart.\n"));
|
|
if (SearchBackward) {
|
|
return(Current);
|
|
} else {
|
|
return(Current - Length + 1);
|
|
}
|
|
}
|
|
} else {
|
|
Found = 0;
|
|
}
|
|
Current += Delta;
|
|
}
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGP460FindRangeInGART.\n"));
|
|
//
|
|
// A suitable range was not found.
|
|
//
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
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;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPFindFreeRun.\n"));
|
|
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
|
|
Pte = (PGART_PTE)(AgpRange->Context) + (OffsetInPages * OS_ChipsetPagesizeRatio);
|
|
|
|
//
|
|
// Find the first free PTE
|
|
//
|
|
for (i=0; i< (NumberOfPages * OS_ChipsetPagesizeRatio); i++) {
|
|
if (Pte[i].Hard.Valid == FALSE) {
|
|
//
|
|
// Found a free PTE, count the contiguous ones.
|
|
//
|
|
*FreeOffset = i/OS_ChipsetPagesizeRatio + OffsetInPages;
|
|
*FreePages = 0;
|
|
while ((i<NumberOfPages * OS_ChipsetPagesizeRatio ) && (Pte[i].Hard.Valid == 0)) {
|
|
*FreePages += 1;
|
|
Pte[i].Hard.Valid = GART_ENTRY_VALID; // Sunil
|
|
++i;
|
|
}
|
|
*FreePages /= OS_ChipsetPagesizeRatio;
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPFindFreeRun - 1 Length: %0x, Offset: %0x\n",NumberOfPages,OffsetInPages));
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No free PTEs in the specified range
|
|
//
|
|
*FreePages = 0;
|
|
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPFindFreeRun - 0 Length: %0x, Offset: %0x\n",NumberOfPages,OffsetInPages));
|
|
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;
|
|
PULONGLONG Pages;
|
|
ULONG OS_ChipsetPagesizeRatio;
|
|
ULONGLONG AddressFromPFN;
|
|
NTSTATUS ProbeStatus;
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Entering AGPGetMappedPages.\n"));
|
|
|
|
ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
|
|
|
|
Pages = (PULONGLONG)(Mdl + 1);
|
|
|
|
OS_ChipsetPagesizeRatio = PAGE_SIZE / PAGESIZE_460GX_CHIPSET;
|
|
Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages * OS_ChipsetPagesizeRatio;
|
|
|
|
for (i=0; i< NumberOfPages ; i++) {
|
|
ASSERT(Pte[i*OS_ChipsetPagesizeRatio].Hard.Valid == 1);
|
|
AddressFromPFN = Pte[i*OS_ChipsetPagesizeRatio].Hard.Page << GART_PAGESHIFT_460GX;
|
|
Pages[i] = AddressFromPFN >> PAGE_SHIFT;
|
|
}
|
|
|
|
//Mdl->MdlFlags |= MDL_PAGES_LOCKED; sunil - either you can set the bit here, or in ..../port/agp.c
|
|
|
|
AGPLOG(AGP_NOISE, ("AGP460: Leaving AGPGetMappedPages.\n"));
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AgpSpecialTarget(
|
|
IN PAGP460_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 = Agp460SetRate(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
|
|
Agp460SetRate(
|
|
IN PAGP460_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, ("AGP460SetRate: AgpLibGetPciDeviceCapability "
|
|
"failed %08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AGPLOG(AGP_WARNING, ("AGP460SetRate: 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,
|
|
("AGP460SetRate: 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,
|
|
("AGP460SetRate: 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,
|
|
("AGP460SetRate: 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,
|
|
("AGP460SetRate: 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,
|
|
("AGP460SetRate: AgpLibSetMasterCapability %08lx failed "
|
|
"%08lx\n",
|
|
&MasterCap,
|
|
Status));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|