Source code of Windows XP (NT5)
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.

1323 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. gart.c
  5. Abstract:
  6. Routines for querying and setting the Intel 440xx GART aperture
  7. Author:
  8. John Vert (jvert) 10/30/1997
  9. Revision History:
  10. --*/
  11. #include "agp440.h"
  12. //
  13. // Local function prototypes
  14. //
  15. NTSTATUS
  16. Agp440CreateGart(
  17. IN PAGP440_EXTENSION AgpContext,
  18. IN ULONG MinimumPages
  19. );
  20. PGART_PTE
  21. Agp440FindRangeInGart(
  22. IN PGART_PTE StartPte,
  23. IN PGART_PTE EndPte,
  24. IN ULONG Length,
  25. IN BOOLEAN SearchBackward,
  26. IN ULONG SearchState
  27. );
  28. NTSTATUS
  29. Agp440SetRate(
  30. IN PVOID AgpContext,
  31. IN ULONG AgpRate
  32. );
  33. VOID
  34. Agp440SetGTLB_Enable(
  35. IN PAGP440_EXTENSION AgpContext,
  36. IN BOOLEAN Enable
  37. );
  38. #ifdef ALLOC_PRAGMA
  39. #pragma alloc_text(PAGE, AgpDisableAperture)
  40. #pragma alloc_text(PAGE, AgpQueryAperture)
  41. #pragma alloc_text(PAGE, AgpReserveMemory)
  42. #pragma alloc_text(PAGE, AgpReleaseMemory)
  43. #pragma alloc_text(PAGE, Agp440CreateGart)
  44. #pragma alloc_text(PAGE, AgpMapMemory)
  45. #pragma alloc_text(PAGE, AgpUnMapMemory)
  46. #pragma alloc_text(PAGE, Agp440FindRangeInGart)
  47. #pragma alloc_text(PAGE, AgpFindFreeRun)
  48. #pragma alloc_text(PAGE, AgpGetMappedPages)
  49. #endif
  50. #define Agp440EnableTB(_x_) Agp440SetGTLB_Enable((_x_), TRUE)
  51. #define Agp440DisableTB(_x_) Agp440SetGTLB_Enable((_x_), FALSE)
  52. NTSTATUS
  53. AgpQueryAperture(
  54. IN PAGP440_EXTENSION AgpContext,
  55. OUT PHYSICAL_ADDRESS *CurrentBase,
  56. OUT ULONG *CurrentSizeInPages,
  57. OUT OPTIONAL PIO_RESOURCE_LIST *pApertureRequirements
  58. )
  59. /*++
  60. Routine Description:
  61. Queries the current size of the GART aperture. Optionally returns
  62. the possible GART settings.
  63. Arguments:
  64. AgpContext - Supplies the AGP context.
  65. CurrentBase - Returns the current physical address of the GART.
  66. CurrentSizeInPages - Returns the current GART size.
  67. ApertureRequirements - if present, returns the possible GART settings
  68. Return Value:
  69. NTSTATUS
  70. --*/
  71. {
  72. ULONG ApBase;
  73. UCHAR ApSize;
  74. PIO_RESOURCE_LIST Requirements;
  75. ULONG i;
  76. ULONG Length;
  77. PAGED_CODE();
  78. //
  79. // Get the current APBASE and APSIZE settings
  80. //
  81. Read440Config(&ApBase, APBASE_OFFSET, sizeof(ApBase));
  82. Read440Config(&ApSize, APSIZE_OFFSET, sizeof(ApSize));
  83. ASSERT(ApBase != 0);
  84. CurrentBase->QuadPart = ApBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  85. //
  86. // Convert APSIZE into the actual size of the aperture
  87. //
  88. switch (ApSize) {
  89. case AP_SIZE_4MB:
  90. *CurrentSizeInPages = 4 * (1024*1024 / PAGE_SIZE);
  91. break;
  92. case AP_SIZE_8MB:
  93. *CurrentSizeInPages = 8 * (1024*1024 / PAGE_SIZE);
  94. break;
  95. case AP_SIZE_16MB:
  96. *CurrentSizeInPages = 16 * (1024*1024 / PAGE_SIZE);
  97. break;
  98. case AP_SIZE_32MB:
  99. *CurrentSizeInPages = 32 * (1024*1024 / PAGE_SIZE);
  100. break;
  101. case AP_SIZE_64MB:
  102. *CurrentSizeInPages = 64 * (1024*1024 / PAGE_SIZE);
  103. break;
  104. case AP_SIZE_128MB:
  105. *CurrentSizeInPages = 128 * (1024*1024 / PAGE_SIZE);
  106. break;
  107. case AP_SIZE_256MB:
  108. *CurrentSizeInPages = 256 * (1024*1024 / PAGE_SIZE);
  109. break;
  110. default:
  111. AGPLOG(AGP_CRITICAL,
  112. ("AGP440 - AgpQueryAperture - Unexpected value %x for ApSize!\n",
  113. ApSize));
  114. ASSERT(FALSE);
  115. AgpContext->ApertureStart.QuadPart = 0;
  116. AgpContext->ApertureLength = 0;
  117. return(STATUS_UNSUCCESSFUL);
  118. }
  119. //
  120. // Remember the current aperture settings
  121. //
  122. AgpContext->ApertureStart.QuadPart = CurrentBase->QuadPart;
  123. AgpContext->ApertureLength = *CurrentSizeInPages * PAGE_SIZE;
  124. if (pApertureRequirements != NULL) {
  125. ULONG VendorId;
  126. //
  127. // 440 supports 7 different aperture sizes, all must be
  128. // naturally aligned. Start with the largest aperture and
  129. // work downwards so that we get the biggest possible aperture.
  130. //
  131. Requirements = ExAllocatePoolWithTag(PagedPool,
  132. sizeof(IO_RESOURCE_LIST) + (AP_SIZE_COUNT-1)*sizeof(IO_RESOURCE_DESCRIPTOR),
  133. 'RpgA');
  134. if (Requirements == NULL) {
  135. return(STATUS_INSUFFICIENT_RESOURCES);
  136. }
  137. Requirements->Version = Requirements->Revision = 1;
  138. //
  139. // 815 only supports 64MB and 32MB Aperture sizes
  140. //
  141. Read440Config(&VendorId, 0, sizeof(VendorId));
  142. if (VendorId == AGP_815_IDENTIFIER) {
  143. Requirements->Count = AP_815_SIZE_COUNT;
  144. Length = AP_815_MAX_SIZE;
  145. } else {
  146. Requirements->Count = AP_SIZE_COUNT;
  147. Length = AP_MAX_SIZE;
  148. }
  149. for (i=0; i<Requirements->Count; i++) {
  150. Requirements->Descriptors[i].Option = IO_RESOURCE_ALTERNATIVE;
  151. Requirements->Descriptors[i].Type = CmResourceTypeMemory;
  152. Requirements->Descriptors[i].ShareDisposition = CmResourceShareDeviceExclusive;
  153. Requirements->Descriptors[i].Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_PREFETCHABLE;
  154. Requirements->Descriptors[i].u.Memory.Length = Length;
  155. Requirements->Descriptors[i].u.Memory.Alignment = Length;
  156. Requirements->Descriptors[i].u.Memory.MinimumAddress.QuadPart = 0;
  157. Requirements->Descriptors[i].u.Memory.MaximumAddress.QuadPart = (ULONG)-1;
  158. Length = Length/2;
  159. }
  160. *pApertureRequirements = Requirements;
  161. }
  162. return(STATUS_SUCCESS);
  163. }
  164. NTSTATUS
  165. AgpSetAperture(
  166. IN PAGP440_EXTENSION AgpContext,
  167. IN PHYSICAL_ADDRESS NewBase,
  168. IN ULONG NewSizeInPages
  169. )
  170. /*++
  171. Routine Description:
  172. Sets the GART aperture to the supplied settings
  173. Arguments:
  174. AgpContext - Supplies the AGP context
  175. NewBase - Supplies the new physical memory base for the GART.
  176. NewSizeInPages - Supplies the new size for the GART
  177. Return Value:
  178. NTSTATUS
  179. --*/
  180. {
  181. PACCFG PACConfig;
  182. UCHAR ApSize;
  183. ULONG ApBase;
  184. //
  185. // Figure out the new APSIZE setting, make sure it is valid.
  186. //
  187. switch (NewSizeInPages) {
  188. case 4 * 1024 * 1024 / PAGE_SIZE:
  189. ApSize = AP_SIZE_4MB;
  190. break;
  191. case 8 * 1024 * 1024 / PAGE_SIZE:
  192. ApSize = AP_SIZE_8MB;
  193. break;
  194. case 16 * 1024 * 1024 / PAGE_SIZE:
  195. ApSize = AP_SIZE_16MB;
  196. break;
  197. case 32 * 1024 * 1024 / PAGE_SIZE:
  198. ApSize = AP_SIZE_32MB;
  199. break;
  200. case 64 * 1024 * 1024 / PAGE_SIZE:
  201. ApSize = AP_SIZE_64MB;
  202. break;
  203. case 128 * 1024 * 1024 / PAGE_SIZE:
  204. ApSize = AP_SIZE_128MB;
  205. break;
  206. case 256 * 1024 * 1024 / PAGE_SIZE:
  207. ApSize = AP_SIZE_256MB;
  208. break;
  209. default:
  210. AGPLOG(AGP_CRITICAL,
  211. ("AgpSetAperture - invalid GART size of %lx pages specified, aperture at %I64X.\n",
  212. NewSizeInPages,
  213. NewBase.QuadPart));
  214. ASSERT(FALSE);
  215. return(STATUS_INVALID_PARAMETER);
  216. }
  217. //
  218. // Make sure the supplied size is aligned on the appropriate boundary.
  219. //
  220. ASSERT(NewBase.HighPart == 0);
  221. ASSERT((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) == 0);
  222. if ((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) != 0 ) {
  223. AGPLOG(AGP_CRITICAL,
  224. ("AgpSetAperture - invalid base %I64X specified for GART aperture of %lx pages\n",
  225. NewBase.QuadPart,
  226. NewSizeInPages));
  227. return(STATUS_INVALID_PARAMETER);
  228. }
  229. //
  230. // Reprogram Special Target settings when the chip
  231. // is powered off, but ignore rate changes as those were already
  232. // applied during MasterInit
  233. //
  234. if (AgpContext->SpecialTarget & ~AGP_FLAG_SPECIAL_RESERVE) {
  235. AgpSpecialTarget(AgpContext,
  236. AgpContext->SpecialTarget &
  237. ~AGP_FLAG_SPECIAL_RESERVE);
  238. }
  239. //
  240. // Need to reset the hardware to match the supplied settings
  241. //
  242. // If the aperture is enabled, disable it, write the new settings, then reenable the aperture
  243. //
  244. Read440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  245. PACConfig.GlobalEnable = 0;
  246. Write440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  247. //
  248. // Write APSIZE first, as this will enable the correct bits in APBASE that need to
  249. // be written next.
  250. //
  251. Write440Config(&ApSize, APSIZE_OFFSET, sizeof(ApSize));
  252. //
  253. // Now we can update APBASE
  254. //
  255. ApBase = NewBase.LowPart & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  256. Write440Config(&ApBase, APBASE_OFFSET, sizeof(ApBase));
  257. #if DBG
  258. //
  259. // Read back what we wrote, make sure it worked
  260. //
  261. {
  262. ULONG DbgBase;
  263. UCHAR DbgSize;
  264. Read440Config(&DbgSize, APSIZE_OFFSET, sizeof(ApSize));
  265. Read440Config(&DbgBase, APBASE_OFFSET, sizeof(ApBase));
  266. ASSERT(DbgSize == ApSize);
  267. ASSERT((DbgBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK) == ApBase);
  268. }
  269. #endif
  270. //
  271. // Now enable the aperture if it was enabled before
  272. //
  273. if (AgpContext->GlobalEnable) {
  274. Read440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  275. ASSERT(PACConfig.GlobalEnable == 0);
  276. PACConfig.GlobalEnable = 1;
  277. Write440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  278. }
  279. //
  280. // Update our extension to reflect the new GART setting
  281. //
  282. AgpContext->ApertureStart = NewBase;
  283. AgpContext->ApertureLength = NewSizeInPages * PAGE_SIZE;
  284. //
  285. // Enable the TB in case we are resuming from S3 or S4
  286. //
  287. Agp440EnableTB(AgpContext);
  288. //
  289. // If the GART has been allocated, rewrite the ATTBASE
  290. //
  291. if (AgpContext->Gart != NULL) {
  292. Write440Config(&AgpContext->GartPhysical.LowPart,
  293. ATTBASE_OFFSET,
  294. sizeof(AgpContext->GartPhysical.LowPart));
  295. }
  296. return(STATUS_SUCCESS);
  297. }
  298. VOID
  299. AgpDisableAperture(
  300. IN PAGP440_EXTENSION AgpContext
  301. )
  302. /*++
  303. Routine Description:
  304. Disables the GART aperture so that this resource is available
  305. for other devices
  306. Arguments:
  307. AgpContext - Supplies the AGP context
  308. Return Value:
  309. None - this routine must always succeed.
  310. --*/
  311. {
  312. PACCFG PACConfig;
  313. //
  314. // Disable the aperture
  315. //
  316. Read440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  317. if (PACConfig.GlobalEnable == 1) {
  318. PACConfig.GlobalEnable = 0;
  319. Write440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  320. }
  321. AgpContext->GlobalEnable = FALSE;
  322. //
  323. // Nuke the Gart! (It's meaningless now...)
  324. //
  325. if (AgpContext->Gart != NULL) {
  326. MmFreeContiguousMemory(AgpContext->Gart);
  327. AgpContext->Gart = NULL;
  328. AgpContext->GartLength = 0;
  329. }
  330. }
  331. NTSTATUS
  332. AgpReserveMemory(
  333. IN PAGP440_EXTENSION AgpContext,
  334. IN OUT AGP_RANGE *Range
  335. )
  336. /*++
  337. Routine Description:
  338. Reserves a range of memory in the GART.
  339. Arguments:
  340. AgpContext - Supplies the AGP Context
  341. Range - Supplies the AGP_RANGE structure. AGPLIB
  342. will have filled in NumberOfPages and Type. This
  343. routine will fill in MemoryBase and Context.
  344. Return Value:
  345. NTSTATUS
  346. --*/
  347. {
  348. ULONG Index;
  349. ULONG NewState;
  350. NTSTATUS Status;
  351. PGART_PTE FoundRange;
  352. BOOLEAN Backwards;
  353. PAGED_CODE();
  354. ASSERT((Range->Type == MmNonCached) || (Range->Type == MmWriteCombined));
  355. if (Range->NumberOfPages > (AgpContext->ApertureLength / PAGE_SIZE)) {
  356. return STATUS_INSUFFICIENT_RESOURCES;
  357. }
  358. //
  359. // If we have not allocated our GART yet, now is the time to do so
  360. //
  361. if (AgpContext->Gart == NULL) {
  362. ASSERT(AgpContext->GartLength == 0);
  363. Status = Agp440CreateGart(AgpContext,Range->NumberOfPages);
  364. if (!NT_SUCCESS(Status)) {
  365. AGPLOG(AGP_CRITICAL,
  366. ("Agp440CreateGart failed %08lx to create GART of size %lx\n",
  367. Status,
  368. AgpContext->ApertureLength));
  369. return(Status);
  370. }
  371. }
  372. ASSERT(AgpContext->GartLength != 0);
  373. //
  374. // Now that we have a GART, try and find enough contiguous entries to satisfy
  375. // the request. Requests for uncached memory will scan from high addresses to
  376. // low addresses. Requests for write-combined memory will scan from low addresses
  377. // to high addresses. We will use a first-fit algorithm to try and keep the allocations
  378. // packed and contiguous.
  379. //
  380. Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE;
  381. FoundRange = Agp440FindRangeInGart(&AgpContext->Gart[0],
  382. &AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
  383. Range->NumberOfPages,
  384. Backwards,
  385. GART_ENTRY_FREE);
  386. if (FoundRange == NULL) {
  387. //
  388. // A big enough chunk was not found.
  389. //
  390. AGPLOG(AGP_CRITICAL,
  391. ("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n",
  392. Range->NumberOfPages,
  393. Range->Type,
  394. AgpContext->Gart));
  395. //
  396. // This is where we could try and grow the GART
  397. //
  398. return(STATUS_INSUFFICIENT_RESOURCES);
  399. }
  400. AGPLOG(AGP_NOISE,
  401. ("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n",
  402. Range->NumberOfPages,
  403. FoundRange));
  404. //
  405. // Set these pages to reserved
  406. //
  407. if (Range->Type == MmNonCached) {
  408. NewState = GART_ENTRY_RESERVED_UC;
  409. } else {
  410. NewState = GART_ENTRY_RESERVED_WC;
  411. }
  412. for (Index = 0;Index < Range->NumberOfPages; Index++) {
  413. ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE);
  414. FoundRange[Index].AsUlong = 0;
  415. FoundRange[Index].Soft.State = NewState;
  416. }
  417. Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart + (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE;
  418. Range->Context = FoundRange;
  419. ASSERT(Range->MemoryBase.HighPart == 0);
  420. AGPLOG(AGP_NOISE,
  421. ("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
  422. FoundRange,
  423. Range->MemoryBase.LowPart));
  424. return(STATUS_SUCCESS);
  425. }
  426. NTSTATUS
  427. AgpReleaseMemory(
  428. IN PAGP440_EXTENSION AgpContext,
  429. IN PAGP_RANGE Range
  430. )
  431. /*++
  432. Routine Description:
  433. Releases memory previously reserved with AgpReserveMemory
  434. Arguments:
  435. AgpContext - Supplies the AGP context
  436. AgpRange - Supplies the range to be released.
  437. Return Value:
  438. NTSTATUS
  439. --*/
  440. {
  441. PGART_PTE Pte;
  442. ULONG Start;
  443. PAGED_CODE();
  444. //
  445. // Go through and free all the PTEs. None of these should still
  446. // be valid at this point.
  447. //
  448. for (Pte = Range->Context;
  449. Pte < (PGART_PTE)Range->Context + Range->NumberOfPages;
  450. Pte++) {
  451. if (Range->Type == MmNonCached) {
  452. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
  453. } else {
  454. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
  455. }
  456. Pte->Soft.State = GART_ENTRY_FREE;
  457. }
  458. Range->MemoryBase.QuadPart = 0;
  459. return(STATUS_SUCCESS);
  460. }
  461. NTSTATUS
  462. Agp440CreateGart(
  463. IN PAGP440_EXTENSION AgpContext,
  464. IN ULONG MinimumPages
  465. )
  466. /*++
  467. Routine Description:
  468. Allocates and initializes an empty GART. The current implementation
  469. attempts to allocate the entire GART on the first reserve.
  470. Arguments:
  471. AgpContext - Supplies the AGP context
  472. MinimumPages - Supplies the minimum size (in pages) of the GART to be
  473. created.
  474. Return Value:
  475. NTSTATUS
  476. --*/
  477. {
  478. PGART_PTE Gart;
  479. ULONG GartLength;
  480. PHYSICAL_ADDRESS HighestAcceptable;
  481. PHYSICAL_ADDRESS LowestAcceptable;
  482. PHYSICAL_ADDRESS BoundaryMultiple;
  483. PHYSICAL_ADDRESS GartPhysical;
  484. ULONG i;
  485. PAGED_CODE();
  486. //
  487. // Try and get a chunk of contiguous memory big enough to map the
  488. // entire aperture.
  489. //
  490. LowestAcceptable.QuadPart = 0;
  491. BoundaryMultiple.QuadPart = 0;
  492. HighestAcceptable.QuadPart = 0xFFFFFFFF;
  493. GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);
  494. Gart = MmAllocateContiguousMemorySpecifyCache(GartLength,
  495. LowestAcceptable,
  496. HighestAcceptable,
  497. BoundaryMultiple,
  498. MmNonCached);
  499. if (Gart == NULL) {
  500. AGPLOG(AGP_CRITICAL,
  501. ("Agp440CreateGart - MmAllocateContiguousMemorySpecifyCache %lx failed\n",
  502. GartLength));
  503. return(STATUS_INSUFFICIENT_RESOURCES);
  504. }
  505. //
  506. // We successfully allocated a contiguous chunk of memory.
  507. // It should be page aligned already.
  508. //
  509. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  510. //
  511. // Get the physical address.
  512. //
  513. GartPhysical = MmGetPhysicalAddress(Gart);
  514. AGPLOG(AGP_NOISE,
  515. ("Agp440CreateGart - GART of length %lx created at VA %08lx, PA %08lx\n",
  516. GartLength,
  517. Gart,
  518. GartPhysical.LowPart));
  519. ASSERT(GartPhysical.HighPart == 0);
  520. ASSERT((GartPhysical.LowPart & (PAGE_SIZE-1)) == 0);
  521. //
  522. // Initialize all the PTEs to free
  523. //
  524. for (i=0; i<GartLength/sizeof(GART_PTE); i++) {
  525. Gart[i].Soft.State = GART_ENTRY_FREE;
  526. }
  527. Write440Config(&GartPhysical.LowPart, ATTBASE_OFFSET, sizeof(GartPhysical.LowPart));
  528. //
  529. // Update our extension to reflect the current state.
  530. //
  531. AgpContext->Gart = Gart;
  532. AgpContext->GartLength = GartLength;
  533. AgpContext->GartPhysical = GartPhysical;
  534. return(STATUS_SUCCESS);
  535. }
  536. NTSTATUS
  537. AgpMapMemory(
  538. IN PAGP440_EXTENSION AgpContext,
  539. IN PAGP_RANGE Range,
  540. IN PMDL Mdl,
  541. IN ULONG OffsetInPages,
  542. OUT PHYSICAL_ADDRESS *MemoryBase
  543. )
  544. /*++
  545. Routine Description:
  546. Maps physical memory into the GART somewhere in the specified range.
  547. Arguments:
  548. AgpContext - Supplies the AGP context
  549. Range - Supplies the AGP range that the memory should be mapped into
  550. Mdl - Supplies the MDL describing the physical pages to be mapped
  551. OffsetInPages - Supplies the offset into the reserved range where the
  552. mapping should begin.
  553. MemoryBase - Returns the physical memory in the aperture where the pages
  554. were mapped.
  555. Return Value:
  556. NTSTATUS
  557. --*/
  558. {
  559. ULONG PageCount;
  560. PGART_PTE Pte;
  561. PGART_PTE StartPte;
  562. ULONG Index;
  563. ULONG TargetState;
  564. PPFN_NUMBER Page;
  565. BOOLEAN Backwards;
  566. GART_PTE NewPte;
  567. PACCFG PACConfig;
  568. PAGED_CODE();
  569. ASSERT(Mdl->Next == NULL);
  570. StartPte = Range->Context;
  571. PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
  572. ASSERT(PageCount <= Range->NumberOfPages);
  573. ASSERT(OffsetInPages <= Range->NumberOfPages);
  574. ASSERT(PageCount + OffsetInPages <= Range->NumberOfPages);
  575. ASSERT(PageCount > 0);
  576. TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
  577. Pte = StartPte + OffsetInPages;
  578. //
  579. // We have a suitable range, now fill it in with the supplied MDL.
  580. //
  581. ASSERT(Pte >= StartPte);
  582. ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages);
  583. NewPte.AsUlong = 0;
  584. NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC :
  585. GART_ENTRY_VALID_WC;
  586. Page = (PPFN_NUMBER)(Mdl + 1);
  587. //
  588. // Disable the TB as per the 440 spec. This is probably unnecessary
  589. // as there should be no valid entries in this range, and there should
  590. // be no invalid entries still in the TB. So flushing the TB seems
  591. // a little gratuitous but that's what the 440 spec says to do.
  592. //
  593. Agp440DisableTB(AgpContext);
  594. for (Index = 0; Index < PageCount; Index++) {
  595. ASSERT(Pte[Index].Soft.State == TargetState);
  596. NewPte.Hard.Page = (ULONG)(*Page++);
  597. Pte[Index].AsUlong = NewPte.AsUlong;
  598. ASSERT(Pte[Index].Hard.Valid == 1);
  599. }
  600. //
  601. // We have filled in all the PTEs. Read back the last one we wrote
  602. // in order to flush the write buffers.
  603. //
  604. NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
  605. //
  606. // Re-enable the TB
  607. //
  608. Agp440EnableTB(AgpContext);
  609. //
  610. // If we have not yet gotten around to enabling the GART aperture, do it now.
  611. //
  612. if (!AgpContext->GlobalEnable) {
  613. AGPLOG(AGP_NOISE,
  614. ("AgpMapMemory - Enabling global aperture access\n"));
  615. Read440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  616. PACConfig.GlobalEnable = 1;
  617. Write440Config(&PACConfig, PACCFG_OFFSET, sizeof(PACConfig));
  618. AgpContext->GlobalEnable = TRUE;
  619. }
  620. MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
  621. return(STATUS_SUCCESS);
  622. }
  623. NTSTATUS
  624. AgpUnMapMemory(
  625. IN PAGP440_EXTENSION AgpContext,
  626. IN PAGP_RANGE AgpRange,
  627. IN ULONG NumberOfPages,
  628. IN ULONG OffsetInPages
  629. )
  630. /*++
  631. Routine Description:
  632. Unmaps previously mapped memory in the GART.
  633. Arguments:
  634. AgpContext - Supplies the AGP context
  635. AgpRange - Supplies the AGP range that the memory should be freed from
  636. NumberOfPages - Supplies the number of pages in the range to be freed.
  637. OffsetInPages - Supplies the offset into the range where the freeing should begin.
  638. Return Value:
  639. NTSTATUS
  640. --*/
  641. {
  642. ULONG i;
  643. PGART_PTE Pte;
  644. PGART_PTE LastChanged=NULL;
  645. PGART_PTE StartPte;
  646. ULONG NewState;
  647. PAGED_CODE();
  648. ASSERT(OffsetInPages + NumberOfPages <= AgpRange->NumberOfPages);
  649. StartPte = AgpRange->Context;
  650. Pte = &StartPte[OffsetInPages];
  651. if (AgpRange->Type == MmNonCached) {
  652. NewState = GART_ENTRY_RESERVED_UC;
  653. } else {
  654. NewState = GART_ENTRY_RESERVED_WC;
  655. }
  656. //
  657. // Disable the TB to flush it
  658. //
  659. Agp440DisableTB(AgpContext);
  660. for (i=0; i<NumberOfPages; i++) {
  661. if (Pte[i].Hard.Valid) {
  662. Pte[i].Soft.State = NewState;
  663. LastChanged = Pte;
  664. } else {
  665. //
  666. // This page is not mapped, just skip it.
  667. //
  668. AGPLOG(AGP_NOISE,
  669. ("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n",
  670. &Pte[i],
  671. Pte[i].AsUlong,
  672. i));
  673. ASSERT(Pte[i].Soft.State == NewState);
  674. }
  675. }
  676. //
  677. // We have invalidated all the PTEs. Read back the last one we wrote
  678. // in order to flush the write buffers.
  679. //
  680. if (LastChanged != NULL) {
  681. ULONG Temp;
  682. Temp = *(volatile ULONG *)(&LastChanged->AsUlong);
  683. }
  684. //
  685. // Reenable the TB
  686. //
  687. Agp440EnableTB(AgpContext);
  688. return(STATUS_SUCCESS);
  689. }
  690. PGART_PTE
  691. Agp440FindRangeInGart(
  692. IN PGART_PTE StartPte,
  693. IN PGART_PTE EndPte,
  694. IN ULONG Length,
  695. IN BOOLEAN SearchBackward,
  696. IN ULONG SearchState
  697. )
  698. /*++
  699. Routine Description:
  700. Finds a contiguous range in the GART. This routine can
  701. search either from the beginning of the GART forwards or
  702. the end of the GART backwards.
  703. Arguments:
  704. StartIndex - Supplies the first GART pte to search
  705. EndPte - Supplies the last GART to search (inclusive)
  706. Length - Supplies the number of contiguous free entries
  707. to search for.
  708. SearchBackward - TRUE indicates that the search should begin
  709. at EndPte and search backwards. FALSE indicates that the
  710. search should begin at StartPte and search forwards
  711. SearchState - Supplies the PTE state to look for.
  712. Return Value:
  713. Pointer to the first PTE in the GART if a suitable range
  714. is found.
  715. NULL if no suitable range exists.
  716. --*/
  717. {
  718. PGART_PTE Current;
  719. PGART_PTE Last;
  720. LONG Delta;
  721. ULONG Found;
  722. PGART_PTE Candidate;
  723. PAGED_CODE();
  724. ASSERT(EndPte >= StartPte);
  725. ASSERT(Length <= (ULONG)(EndPte - StartPte + 1));
  726. ASSERT(Length != 0);
  727. if (SearchBackward) {
  728. Current = EndPte;
  729. Last = StartPte-1;
  730. Delta = -1;
  731. } else {
  732. Current = StartPte;
  733. Last = EndPte+1;
  734. Delta = 1;
  735. }
  736. Found = 0;
  737. while (Current != Last) {
  738. if (Current->Soft.State == SearchState) {
  739. if (++Found == Length) {
  740. //
  741. // A suitable range was found, return it
  742. //
  743. if (SearchBackward) {
  744. return(Current);
  745. } else {
  746. return(Current - Length + 1);
  747. }
  748. }
  749. } else {
  750. Found = 0;
  751. }
  752. Current += Delta;
  753. }
  754. //
  755. // A suitable range was not found.
  756. //
  757. return(NULL);
  758. }
  759. VOID
  760. Agp440SetGTLB_Enable(
  761. IN PAGP440_EXTENSION AgpContext,
  762. IN BOOLEAN Enable
  763. )
  764. /*++
  765. Routine Description:
  766. Enables or disables the GTLB by setting or clearing the GTLB_Enable bit
  767. in the AGPCTRL register
  768. Arguments:
  769. AgpContext - Supplies the AGP context
  770. Enable - TRUE, GTLB_Enable is set to 1
  771. FALSE, GTLB_Enable is set to 0
  772. Return Value:
  773. None
  774. --*/
  775. {
  776. AGPCTRL AgpCtrl;
  777. Read440Config(&AgpCtrl, AGPCTRL_OFFSET, sizeof(AgpCtrl));
  778. if (Enable) {
  779. AgpCtrl.GTLB_Enable = 1;
  780. } else {
  781. AgpCtrl.GTLB_Enable = 0;
  782. }
  783. Write440Config(&AgpCtrl, AGPCTRL_OFFSET, sizeof(AgpCtrl));
  784. }
  785. VOID
  786. AgpFindFreeRun(
  787. IN PVOID AgpContext,
  788. IN PAGP_RANGE AgpRange,
  789. IN ULONG NumberOfPages,
  790. IN ULONG OffsetInPages,
  791. OUT ULONG *FreePages,
  792. OUT ULONG *FreeOffset
  793. )
  794. /*++
  795. Routine Description:
  796. Finds the first contiguous run of free pages in the specified
  797. part of the reserved range.
  798. Arguments:
  799. AgpContext - Supplies the AGP context
  800. AgpRange - Supplies the AGP range
  801. NumberOfPages - Supplies the size of the region to be searched for free pages
  802. OffsetInPages - Supplies the start of the region to be searched for free pages
  803. FreePages - Returns the length of the first contiguous run of free pages
  804. FreeOffset - Returns the start of the first contiguous run of free pages
  805. Return Value:
  806. None. FreePages == 0 if there are no free pages in the specified range.
  807. --*/
  808. {
  809. PGART_PTE Pte;
  810. ULONG i;
  811. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  812. //
  813. // Find the first free PTE
  814. //
  815. for (i=0; i<NumberOfPages; i++) {
  816. if (Pte[i].Hard.Valid == 0) {
  817. //
  818. // Found a free PTE, count the contiguous ones.
  819. //
  820. *FreeOffset = i + OffsetInPages;
  821. *FreePages = 0;
  822. while ((i<NumberOfPages) && (Pte[i].Hard.Valid == 0)) {
  823. *FreePages += 1;
  824. ++i;
  825. }
  826. return;
  827. }
  828. }
  829. //
  830. // No free PTEs in the specified range
  831. //
  832. *FreePages = 0;
  833. return;
  834. }
  835. VOID
  836. AgpGetMappedPages(
  837. IN PVOID AgpContext,
  838. IN PAGP_RANGE AgpRange,
  839. IN ULONG NumberOfPages,
  840. IN ULONG OffsetInPages,
  841. OUT PMDL Mdl
  842. )
  843. /*++
  844. Routine Description:
  845. Returns the list of physical pages mapped into the specified
  846. range in the GART.
  847. Arguments:
  848. AgpContext - Supplies the AGP context
  849. AgpRange - Supplies the AGP range
  850. NumberOfPages - Supplies the number of pages to be returned
  851. OffsetInPages - Supplies the start of the region
  852. Mdl - Returns the list of physical pages mapped in the specified range.
  853. Return Value:
  854. None
  855. --*/
  856. {
  857. PGART_PTE Pte;
  858. ULONG i;
  859. PULONG Pages;
  860. ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
  861. Pages = (PULONG)(Mdl + 1);
  862. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  863. for (i=0; i<NumberOfPages; i++) {
  864. ASSERT(Pte[i].Hard.Valid == 1);
  865. Pages[i] = Pte[i].Hard.Page;
  866. }
  867. return;
  868. }
  869. NTSTATUS
  870. AgpSpecialTarget(
  871. IN PAGP440_EXTENSION AgpContext,
  872. IN ULONGLONG DeviceFlags
  873. )
  874. /*++
  875. Routine Description:
  876. This routine makes "special" tweaks to the AGP chipset
  877. Arguments:
  878. AgpContext - Supplies the AGP context
  879. DeviceFlags - Flags indicating what tweaks to perform
  880. Return Value:
  881. STATUS_SUCCESS, or error
  882. --*/
  883. {
  884. NTSTATUS Status;
  885. //
  886. // Should we change the AGP rate?
  887. //
  888. if (DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) {
  889. Status = Agp440SetRate(AgpContext,
  890. (ULONG)((DeviceFlags & AGP_FLAG_SPECIAL_RESERVE)
  891. >> AGP_FLAG_SET_RATE_SHIFT));
  892. if (!NT_SUCCESS(Status)) {
  893. return Status;
  894. }
  895. }
  896. //
  897. // Add more tweaks here...
  898. //
  899. AgpContext->SpecialTarget |= DeviceFlags;
  900. return STATUS_SUCCESS;
  901. }
  902. NTSTATUS
  903. Agp440SetRate(
  904. IN PAGP440_EXTENSION AgpContext,
  905. IN ULONG AgpRate
  906. )
  907. /*++
  908. Routine Description:
  909. This routine sets the AGP rate
  910. Arguments:
  911. AgpContext - Supplies the AGP context
  912. AgpRate - Rate to set
  913. Return Value:
  914. STATUS_SUCCESS, or error status
  915. --*/
  916. {
  917. NTSTATUS Status;
  918. ULONG TargetEnable;
  919. ULONG MasterEnable;
  920. PCI_AGP_CAPABILITY TargetCap;
  921. PCI_AGP_CAPABILITY MasterCap;
  922. BOOLEAN ReverseInit;
  923. //
  924. // Read capabilities
  925. //
  926. Status = AgpLibGetPciDeviceCapability(0, 0, &TargetCap);
  927. if (!NT_SUCCESS(Status)) {
  928. AGPLOG(AGP_WARNING, ("AGP440SetRate: AgpLibGetPciDeviceCapability "
  929. "failed %08lx\n", Status));
  930. return Status;
  931. }
  932. Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
  933. if (!NT_SUCCESS(Status)) {
  934. AGPLOG(AGP_WARNING, ("AGP440SetRate: AgpLibGetMasterCapability "
  935. "failed %08lx\n", Status));
  936. return Status;
  937. }
  938. //
  939. // Verify the requested rate is supported by both master and target
  940. //
  941. if (!(AgpRate & TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate)) {
  942. return STATUS_INVALID_PARAMETER;
  943. }
  944. //
  945. // Disable AGP while the pull the rug out from underneath
  946. //
  947. TargetEnable = TargetCap.AGPCommand.AGPEnable;
  948. TargetCap.AGPCommand.AGPEnable = 0;
  949. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  950. if (!NT_SUCCESS(Status)) {
  951. AGPLOG(AGP_WARNING,
  952. ("AGP440SetRate: AgpLibSetPciDeviceCapability %08lx for "
  953. "Target failed %08lx\n",
  954. &TargetCap,
  955. Status));
  956. return Status;
  957. }
  958. MasterEnable = MasterCap.AGPCommand.AGPEnable;
  959. MasterCap.AGPCommand.AGPEnable = 0;
  960. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  961. if (!NT_SUCCESS(Status)) {
  962. AGPLOG(AGP_WARNING,
  963. ("AGP440SetRate: AgpLibSetMasterCapability %08lx failed "
  964. "%08lx\n",
  965. &MasterCap,
  966. Status));
  967. return Status;
  968. }
  969. //
  970. // Fire up AGP with new rate
  971. //
  972. ReverseInit =
  973. (AgpContext->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) ==
  974. AGP_FLAG_REVERSE_INITIALIZATION;
  975. if (ReverseInit) {
  976. MasterCap.AGPCommand.Rate = AgpRate;
  977. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  978. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  979. if (!NT_SUCCESS(Status)) {
  980. AGPLOG(AGP_WARNING,
  981. ("AGP440SetRate: AgpLibSetMasterCapability %08lx failed "
  982. "%08lx\n",
  983. &MasterCap,
  984. Status));
  985. }
  986. }
  987. TargetCap.AGPCommand.Rate = AgpRate;
  988. TargetCap.AGPCommand.AGPEnable = TargetEnable;
  989. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  990. if (!NT_SUCCESS(Status)) {
  991. AGPLOG(AGP_WARNING,
  992. ("AGP440SetRate: AgpLibSetPciDeviceCapability %08lx for "
  993. "Target failed %08lx\n",
  994. &TargetCap,
  995. Status));
  996. return Status;
  997. }
  998. if (!ReverseInit) {
  999. MasterCap.AGPCommand.Rate = AgpRate;
  1000. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1001. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1002. if (!NT_SUCCESS(Status)) {
  1003. AGPLOG(AGP_WARNING,
  1004. ("AGP440SetRate: AgpLibSetMasterCapability %08lx failed "
  1005. "%08lx\n",
  1006. &MasterCap,
  1007. Status));
  1008. }
  1009. }
  1010. return Status;
  1011. }