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.

1475 lines
36 KiB

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