/*++ Copyright (c) 1997 Microsoft Corporation Module Name: gart.c Abstract: Routines for querying and setting the Intel 440xx GART aperture Author: John Vert (jvert) 10/30/1997 Modified by: Chi-Ming Cheng 06/24/1998 Acer Labs, Inc. Wang-Kai Tsai 08/28/2000 Acer Labs, Inc. - ACPI power up GART reinitialization Revision History: --*/ #include "ALiM1541.h" // // Local function prototypes // NTSTATUS AgpALiSetRate( IN PVOID AgpContext, IN ULONG AgpRate ); NTSTATUS AgpALiCreateGart( IN PAGPALi_EXTENSION AgpContext, IN ULONG MinimumPages ); PGART_PTE AgpALiFindRangeInGart( IN PGART_PTE StartPte, IN PGART_PTE EndPte, IN ULONG Length, IN BOOLEAN SearchBackward, IN ULONG SearchState ); NTSTATUS AgpQueryAperture( IN PAGPALi_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 ApBase; APCTRL ApCtrl; PIO_RESOURCE_LIST Requirements; ULONG i; ULONG Length; // // Get the current APBASE and APSIZE settings // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApBase, APBASE_OFFSET); ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); ASSERT(ApBase != 0); CurrentBase->QuadPart = ApBase & 0xFFFFFFF0; //PCI_ADDRESS_MEMORY_ADDRESS_MASK; // // Convert APSIZE into the actual size of the aperture // switch (ApCtrl.ApSize) { case AP_SIZE_4MB: *CurrentSizeInPages = (4 * 1024*1024) / PAGE_SIZE; break; case AP_SIZE_8MB: *CurrentSizeInPages = 8 * (1024*1024 / PAGE_SIZE); break; case AP_SIZE_16MB: *CurrentSizeInPages = 16 * (1024*1024 / PAGE_SIZE); break; case AP_SIZE_32MB: *CurrentSizeInPages = 32 * (1024*1024 / PAGE_SIZE); break; case AP_SIZE_64MB: *CurrentSizeInPages = 64 * (1024*1024 / PAGE_SIZE); break; case AP_SIZE_128MB: *CurrentSizeInPages = 128 * (1024*1024 / PAGE_SIZE); break; case AP_SIZE_256MB: *CurrentSizeInPages = 256 * (1024*1024 / PAGE_SIZE); break; default: AGPLOG(AGP_CRITICAL, ("AGPALi - AgpQueryAperture - Unexpected value %x for ApSize!\n", ApCtrl.ApSize)); 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) { // // 1541 supports 7 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) + (AP_SIZE_COUNT-1)*sizeof(IO_RESOURCE_DESCRIPTOR), 'RpgA'); if (Requirements == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); } Requirements->Version = Requirements->Revision = 1; Requirements->Count = AP_SIZE_COUNT; Length = AP_MAX_SIZE; for (i=0; iDescriptors[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 PAGPALi_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 --*/ { ULONG ApBase; ULONG ApSize; APCTRL ApCtrl; GTLBCTRL GTLBCtrl; ULONG GTLBDisable; PHYSICAL_ADDRESS GartPhysical; GartPhysical = AgpContext->GartPhysical; // // 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); } // // Set GART base // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); ApCtrl.ATTBase = GartPhysical.LowPart / PAGE_SIZE; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); // // If the new settings match the current settings, leave everything // alone. // if ((NewBase.QuadPart == AgpContext->ApertureStart.QuadPart) && (NewSizeInPages == AgpContext->ApertureLength / PAGE_SIZE)) { // // Enable GART table // if ((AgpContext->ChipsetType != ALi1647) && (AgpContext->ChipsetType != ALi1651) && (AgpContext->ChipsetType != ALi1644) && (AgpContext->ChipsetType != ALi1646) && (AgpContext->ChipsetType != ALi1661) && (AgpContext->ChipsetType != ALi1667)) { if (AgpContext->Gart) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBCtrl.GTLB_ENJ = 0; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } } AgpWorkaround(AgpContext); return(STATUS_SUCCESS); } // // Figure out the new APSIZE setting, make sure it is valid. // switch (NewSizeInPages) { case 4 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_4MB; break; case 8 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_8MB; break; case 16 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_16MB; break; case 32 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_32MB; break; case 64 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_64MB; break; case 128 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_SIZE_128MB; break; case 256 * 1024 * 1024 / PAGE_SIZE: ApSize = AP_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); } // // Need to reset the hardware to match the supplied settings // // If the GTLB is enabled, disable it, write the new settings, then reenable the GTLB // if ((AgpContext->ChipsetType != ALi1647) && (AgpContext->ChipsetType != ALi1651) && (AgpContext->ChipsetType != ALi1644) && (AgpContext->ChipsetType != ALi1646) && (AgpContext->ChipsetType != ALi1661) && (AgpContext->ChipsetType != ALi1667)) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBDisable = GTLBCtrl.GTLB_ENJ; if (!GTLBDisable) { GTLBCtrl.GTLB_ENJ = 1; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } } // // update APBASE // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApBase, APBASE_OFFSET); ApBase = (ApBase & 0x0000000F) | NewBase.LowPart; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApBase, APBASE_OFFSET); // // update APSIZE // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); ApCtrl.ApSize = ApSize; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); // // Only 1541 chipset supports NLVM_BASE and NLVM_TOP // if (AgpContext->ChipsetType == ALi1541) { // // update NLVM_BASE and NLVM_TOP // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBCtrl.NLVM_Base = NewBase.LowPart >> 20; GTLBCtrl.NLVM_Top = (NewBase.LowPart + NewSizeInPages * PAGE_SIZE - 0x100000) >> 20; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } #if DBG // // Read back what we wrote, make sure it worked // { APCTRL DbgSize; ULONG DbgBase; ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &DbgSize, APCTRL_OFFSET); ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &DbgBase, APBASE_OFFSET); ASSERT(DbgSize.ApSize == ApSize); ASSERT(DbgBase == ApBase); } #endif // // Now enable the GTLB if it was enabled before // if ((AgpContext->ChipsetType != ALi1647) && (AgpContext->ChipsetType != ALi1651) && (AgpContext->ChipsetType != ALi1644) && (AgpContext->ChipsetType != ALi1646) && (AgpContext->ChipsetType != ALi1661) && (AgpContext->ChipsetType != ALi1667)) { if (!GTLBDisable) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBCtrl.GTLB_ENJ = 0; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } } // // Update our extension to reflect the new GART setting // AgpContext->ApertureStart = NewBase; AgpContext->ApertureLength = NewSizeInPages * PAGE_SIZE; return(STATUS_SUCCESS); } VOID AgpDisableAperture( IN PAGPALi_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. --*/ { GTLBCTRL GTLBCtrl; ULONG GTLBDisable; // // Disable the aperture // if ((AgpContext->ChipsetType != ALi1647) && (AgpContext->ChipsetType != ALi1651) && (AgpContext->ChipsetType != ALi1644) && (AgpContext->ChipsetType != ALi1646) && (AgpContext->ChipsetType != ALi1661) && (AgpContext->ChipsetType != ALi1667)) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBDisable = GTLBCtrl.GTLB_ENJ; if (!GTLBDisable) { GTLBCtrl.GTLB_ENJ = 1; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } } // // Nuke the Gart! (It's meaningless now...) // if (AgpContext->Gart != NULL) { MmFreeContiguousMemory(AgpContext->Gart); AgpContext->Gart = NULL; AgpContext->GartLength = 0; } } NTSTATUS AgpReserveMemory( IN PAGPALi_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; 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 = AgpALiCreateGart(AgpContext,Range->NumberOfPages); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_CRITICAL, ("AgpALiCreateGart 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 = AgpALiFindRangeInGart(&AgpContext->Gart[0], &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 PAGPALi_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; GTLBTAGCLR ClearTag; // // 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; } // // Clear All Tag // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ClearTag, GTLBTAGCLR_OFFSET); ClearTag.GTLBTagClear = 1; ClearTag.ClearAllTag = 1; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ClearTag, GTLBTAGCLR_OFFSET); Range->MemoryBase.QuadPart = 0; return(STATUS_SUCCESS); } NTSTATUS AgpALiCreateGart( IN PAGPALi_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 --*/ { PGART_PTE Gart; ULONG GartLength; PHYSICAL_ADDRESS LowestAcceptable; PHYSICAL_ADDRESS BoundaryMultiple; PHYSICAL_ADDRESS HighestAcceptable; PHYSICAL_ADDRESS GartPhysical; ULONG i; CACHECTRL FlushCache; APCTRL ApCtrl; GTLBCTRL GTLBCtrl; // // Try and get a chunk of contiguous memory big enough to map the // entire aperture. // HighestAcceptable.QuadPart = 0xFFFFFFFF; LowestAcceptable.QuadPart = 0; BoundaryMultiple.QuadPart = 0; GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE); Gart = MmAllocateContiguousMemorySpecifyCache(GartLength, LowestAcceptable, HighestAcceptable, BoundaryMultiple, MmNonCached); if (Gart == NULL) { AGPLOG(AGP_CRITICAL, ("AgpALiCreateGart - 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, ("AgpALiCreateGart - GART of length %lx created at VA %08lx, PA %08lx\n", GartLength, Gart, GartPhysical.LowPart)); ASSERT(GartPhysical.HighPart == 0); ASSERT((GartPhysical.LowPart & (PAGE_SIZE-1)) == 0); // // Initialize all the PTEs to free // for (i=0; iChipsetType == ALi1541) { // // Flush GART table region // FlushCache.Flush_Enable = 1; for (i=0; i < GartLength/PAGE_SIZE; i++) { FlushCache.Address = (GartPhysical.LowPart / PAGE_SIZE) + i; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &FlushCache, L1_2_CACHE_FLUSH_CTRL); } } // // Set GART base // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); ApCtrl.ATTBase = GartPhysical.LowPart / PAGE_SIZE; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ApCtrl, APCTRL_OFFSET); // // Enable GART table // if ((AgpContext->ChipsetType != ALi1647) && (AgpContext->ChipsetType != ALi1651) && (AgpContext->ChipsetType != ALi1644) && (AgpContext->ChipsetType != ALi1646) && (AgpContext->ChipsetType != ALi1661) && (AgpContext->ChipsetType != ALi1667)) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); GTLBCtrl.GTLB_ENJ = 0; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, >LBCtrl, GTLBCTRL_OFFSET); } // // Update our extension to reflect the current state. // AgpContext->Gart = Gart; AgpContext->GartLength = GartLength; AgpContext->GartPhysical = GartPhysical; return(STATUS_SUCCESS); } NTSTATUS Agp1541FlushPages( IN PAGPALi_EXTENSION AgpContext, IN PMDL Mdl ) /*++ Routine Description: Flush entries in the GART. Arguments: AgpContext - Supplies the AGP context Mdl - Supplies the MDL describing the physical pages to be flushed Return Value: VOID --*/ { ULONG PageCount; CACHECTRL FlushCache; ULONG Index; PULONG Page; ASSERT(Mdl->Next == NULL); PageCount = BYTES_TO_PAGES(Mdl->ByteCount); Page = (PULONG)(Mdl + 1); // // Flush GART table entry // FlushCache.Flush_Enable = 1; for (Index = 0; Index < PageCount; Index++) { FlushCache.Address = Page[Index]; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &FlushCache, L1_2_CACHE_FLUSH_CTRL); } return STATUS_SUCCESS; } NTSTATUS AgpMapMemory( IN PAGPALi_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; PULONG Page; BOOLEAN Backwards; GART_PTE NewPte; GTLBTAGCLR ClearTag; 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); 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); // Fill the physical memory address into GART for (Index = 0; Index < PageCount; Index++) { AGPLOG(AGP_NOISE, ("AgpMapMemory: Pte=%p, Page=%x\n", &Pte[Index], *Page)); NewPte.Hard.Page = *Page++; Pte[Index].AsUlong = NewPte.AsUlong; } // // Clear All Tag // ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ClearTag, GTLBTAGCLR_OFFSET); ClearTag.GTLBTagClear = 1; ClearTag.ClearAllTag = 1; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ClearTag, GTLBTAGCLR_OFFSET); MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE; return(STATUS_SUCCESS); } NTSTATUS AgpUnMapMemory( IN PAGPALi_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 StartPte; GTLBTAGCLR ClearTag; ULONG NewState; 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; } // // Clear the GART entry. // for (i=0; i= 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 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; Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages; // // Find the first free PTE // for (i=0; iByteCount); Pages = (PULONG)(Mdl + 1); Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages; for (i=0; iChipsetType) { case ALi1541: ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, AGP_STATUS_OFFSET); // adjust queue depth to avoid ambiguous if (((ulTemp & 0xFF000000) >= 0x1C000000) && ((ulTemp & 0xFF000000) <= 0x20000000)) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulLockRW, M1541_Lock_WR); ulTemp1 = ulLockRW | 0x40; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp1, M1541_Lock_WR); ulTemp = (ulTemp & 0x00FFFFFF) | 0x1B000000; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, AGP_STATUS_OFFSET); ulLockRW = ulLockRW & 0xFFFFFFBF; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulLockRW, M1541_Lock_WR); } ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x40); // 0x43 bit 7 -> 1 ulTemp = ulTemp | 0x80000000; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x40); ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x88); // P2P 0x88 bit 7,5,3 -> 1 ulTemp = ulTemp | 0x000000A8; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x88); // fix frame buffer here i=0; blPrefetchFound=FALSE; while ((i<6) && (!blPrefetchFound)) // Jump out loop when first prefetch found { // Two or more prefetch case should be considered in the future ReadConfigUlong(AGP_VGA_BUS_ID, AGP_VGA_SLOT_ID, &ulTemp1, 0x10+i*0x4); // read VGA base address if ((ulTemp1 & 0x0000000F) == 0x8) blPrefetchFound=TRUE; i++; } if (blPrefetchFound) // AGP VGA prefetchable address is found. Modify M1541 write buffer { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x84); if ((ulTemp & 0x00010000) == 0x00010000) // Write buffer is enabled { ulTemp = (ulTemp & 0xFFFF0000) | ((ulTemp1 & 0xFFF00000) >> 16) | 0x4; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x84); } } else // AGP VGA prefetchable address is not found. Disable M1541 write buffer { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x84); ulTemp = ulTemp & 0xFFFE0000; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_P2P_SLOT_ID, &ulTemp, 0x84); } if (blnVidia) // Set aperture size to 4M as a temporatory solution { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, APCTRL_OFFSET); ulTemp = (ulTemp & 0xFFFFFFF0) | AP_SIZE_4MB; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, APCTRL_OFFSET); } break; case ALi1621: // Check AGP VGA is a pipeline(SBA disabled) device. If yes, adjust queue depth to 0x2(3 queues) ReadConfigUlong(AGP_VGA_BUS_ID, AGP_VGA_SLOT_ID, &ulTemp1, PCI_STATUS_REG); ulQD = 0; blSupportAGP = FALSE; if ((ulTemp1 & 0x00100000) != 0) { ReadConfigUlong(AGP_VGA_BUS_ID, AGP_VGA_SLOT_ID, &ulTemp1, CAP_PTR); ulTemp = ulTemp1 & 0xFF; while (!blSupportAGP) { if ((ulTemp < 0x40) || (ulTemp > 0xF4)) break; ReadConfigUlong(AGP_VGA_BUS_ID, AGP_VGA_SLOT_ID, &ulTemp1, ulTemp); if ((ulTemp1 & 0xFF) == AGP_ID) blSupportAGP = TRUE; else ulTemp = (ulTemp1 & 0xFF00) >> 8; } if (blSupportAGP) { ReadConfigUlong(AGP_VGA_BUS_ID, AGP_VGA_SLOT_ID, &ulTemp1, ulTemp+4); // Read AGP status register if ((ulTemp1 & 0x00000200) == 0x0) ulQD = 0x2; // AGP VGA supports pipeline only } } ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, AGP_STATUS_OFFSET); // adjust queue depth to avoid ambiguous if ((((ulTemp & 0xFF000000) >= 0x1C000000) && ((ulTemp & 0xFF000000) <= 0x20000000)) || (ulQD != 0)) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulLockRW, M1621_Lock_WR); ulTemp1 = ulLockRW | 0x1000; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp1, M1621_Lock_WR); if (ulQD != 0) ulTemp = (ulTemp & 0x00FFFFFF) | (ulQD << 24); else ulTemp = (ulTemp & 0x00FFFFFF) | 0x1B000000; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, AGP_STATUS_OFFSET); ulLockRW = ulLockRW & 0xFFFFEFFF; WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulLockRW, M1621_Lock_WR); } ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x80); ulTemp = ulTemp & 0xFFFFF3FF; // set offset 0x81 bit 2~3 to 0 WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x80); if (blnVidia) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); ulTemp = ulTemp | 0x40; // set M1621 index 0x50 bit 6 to 1 WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x60); ulTemp = ulTemp | 0x40; // set M1621 index 0x60 bit 6 to 1 WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x60); ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x7C); ulTemp = ulTemp & 0xCFFFFFFF; // set M1621 index 0x7F bit 4~5 to 0 WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x7C); } if (blMatrox) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); ulTemp = ulTemp | 0xFF000000; // set M1621 index 0x53 to 0xFF WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); } break; case ALi1631: case ALi1632: break; case ALi1641: if (blMatrox) { ReadConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); ulTemp = ulTemp | 0xFF000000; // set M1621 index 0x53 to 0xFF WriteConfigUlong(AGP_ALi_GART_BUS_ID, AGP_ALi_GART_SLOT_ID, &ulTemp, 0x50); } break; case ALi1644: case ALi1646: case ALi1647: case ALi1651: case ALi1661: case ALi1667: break; default: break; } } NTSTATUS AgpSpecialTarget( IN PAGPALi_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 = AgpALiSetRate(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 AgpALiSetRate( IN PAGPALi_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, ("AGPALiSetRate: AgpLibGetPciDeviceCapability " "failed %08lx\n", Status)); return Status; } Status = AgpLibGetMasterCapability(AgpContext, &MasterCap); if (!NT_SUCCESS(Status)) { AGPLOG(AGP_WARNING, ("AGPALiSetRate: 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, ("AGPALiSetRate: 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, ("AGPALiSetRate: 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, ("AGPALiSetRate: 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, ("AGPALiSetRate: 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, ("AGPALiSetRate: AgpLibSetMasterCapability %08lx failed " "%08lx\n", &MasterCap, Status)); } } return Status; }