/*++ 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; iGart = 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 ((iByteCount); 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; }