Leaked source code of windows server 2003
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.

1478 lines
37 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. if (Range->NumberOfPages > (AgpContext->ApertureLength / PAGE_SIZE)) {
  362. return STATUS_INSUFFICIENT_RESOURCES;
  363. }
  364. //
  365. // If we have not allocated our GART yet, now is the time to do so
  366. //
  367. if (AgpContext->Gart == NULL) {
  368. ASSERT(AgpContext->GartLength == 0);
  369. Status = AgpVIACreateGart(AgpContext,Range->NumberOfPages);
  370. if (!NT_SUCCESS(Status)) {
  371. AGPLOG(AGP_CRITICAL,
  372. ("AgpVIACreateGart failed %08lx to create GART of size %lx\n",
  373. Status,
  374. AgpContext->ApertureLength));
  375. return(Status);
  376. }
  377. }
  378. ASSERT(AgpContext->GartLength != 0);
  379. //
  380. // Now that we have a GART, try and find enough contiguous entries to satisfy
  381. // the request. Requests for uncached memory will scan from high addresses to
  382. // low addresses. Requests for write-combined memory will scan from low addresses
  383. // to high addresses. We will use a first-fit algorithm to try and keep the allocations
  384. // packed and contiguous.
  385. //
  386. Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE;
  387. FoundRange = AgpVIAFindRangeInGart(&AgpContext->Gart[VIA_FIRST_AVAILABLE_PTE],
  388. &AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
  389. Range->NumberOfPages,
  390. Backwards,
  391. GART_ENTRY_FREE);
  392. if (FoundRange == NULL) {
  393. //
  394. // A big enough chunk was not found.
  395. //
  396. AGPLOG(AGP_CRITICAL,
  397. ("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n",
  398. Range->NumberOfPages,
  399. Range->Type,
  400. AgpContext->Gart));
  401. //
  402. // This is where we could try and grow the GART
  403. //
  404. return(STATUS_INSUFFICIENT_RESOURCES);
  405. }
  406. AGPLOG(AGP_NOISE,
  407. ("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n",
  408. Range->NumberOfPages,
  409. FoundRange));
  410. //
  411. // Set these pages to reserved
  412. //
  413. if (Range->Type == MmNonCached) {
  414. NewState = GART_ENTRY_RESERVED_UC;
  415. } else {
  416. NewState = GART_ENTRY_RESERVED_WC;
  417. }
  418. for (Index = 0;Index < Range->NumberOfPages; Index++) {
  419. ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE);
  420. FoundRange[Index].AsUlong = 0;
  421. FoundRange[Index].Soft.State = NewState;
  422. }
  423. Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart + (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE;
  424. Range->Context = FoundRange;
  425. ASSERT(Range->MemoryBase.HighPart == 0);
  426. AGPLOG(AGP_NOISE,
  427. ("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
  428. FoundRange,
  429. Range->MemoryBase.LowPart));
  430. return(STATUS_SUCCESS);
  431. }
  432. NTSTATUS
  433. AgpReleaseMemory(
  434. IN PAGPVIA_EXTENSION AgpContext,
  435. IN PAGP_RANGE Range
  436. )
  437. /*++
  438. Routine Description:
  439. Releases memory previously reserved with AgpReserveMemory
  440. Arguments:
  441. AgpContext - Supplies the AGP context
  442. AgpRange - Supplies the range to be released.
  443. Return Value:
  444. NTSTATUS
  445. --*/
  446. {
  447. PGART_PTE Pte;
  448. ULONG Start;
  449. PAGED_CODE()
  450. //
  451. // Go through and free all the PTEs. None of these should still
  452. // be valid at this point.
  453. //
  454. for (Pte = Range->Context;
  455. Pte < (PGART_PTE)Range->Context + Range->NumberOfPages;
  456. Pte++) {
  457. if (Range->Type == MmNonCached) {
  458. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
  459. } else {
  460. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
  461. }
  462. Pte->Soft.State = GART_ENTRY_FREE;
  463. }
  464. Range->MemoryBase.QuadPart = 0;
  465. return(STATUS_SUCCESS);
  466. }
  467. #define AGP_TEST_SIGNATURE 0xAA55AA55
  468. NTSTATUS
  469. AgpVIACreateGart(
  470. IN PAGPVIA_EXTENSION AgpContext,
  471. IN ULONG MinimumPages
  472. )
  473. /*++
  474. Routine Description:
  475. Allocates and initializes an empty GART. The current implementation
  476. attempts to allocate the entire GART on the first reserve.
  477. Arguments:
  478. AgpContext - Supplies the AGP context
  479. MinimumPages - Supplies the minimum size (in pages) of the GART to be
  480. created.
  481. Return Value:
  482. NTSTATUS
  483. --*/
  484. {
  485. PHYSICAL_ADDRESS LowestAcceptable;
  486. PHYSICAL_ADDRESS BoundaryMultiple;
  487. PGART_PTE Gart;
  488. ULONG GartLength;
  489. ULONG TempPhysAddr;
  490. PHYSICAL_ADDRESS HighestAcceptable;
  491. PHYSICAL_ADDRESS GartPhysical;
  492. PULONG TestPage;
  493. ULONG i;
  494. PAGED_CODE();
  495. //
  496. // Try and get a chunk of contiguous memory big enough to map the
  497. // entire aperture.
  498. //
  499. LowestAcceptable.QuadPart = 0;
  500. BoundaryMultiple.QuadPart =
  501. (ULONGLONG)VIA_GART_ALIGN(AgpContext->ApertureLength);
  502. HighestAcceptable.QuadPart = 0xFFFFFFFF;
  503. GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);
  504. Gart = MmAllocateContiguousMemorySpecifyCache(GartLength,
  505. LowestAcceptable,
  506. HighestAcceptable,
  507. BoundaryMultiple,
  508. MmNonCached);
  509. if (Gart == NULL) {
  510. AGPLOG(AGP_CRITICAL,
  511. ("AgpVIACreateGart - MmAllocateContiguousMemory %lx failed\n",
  512. GartLength));
  513. return(STATUS_INSUFFICIENT_RESOURCES);
  514. }
  515. //
  516. // We successfully allocated a contiguous chunk of memory.
  517. // It should be page aligned already.
  518. //
  519. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  520. //
  521. // Get the physical address.
  522. //
  523. GartPhysical = MmGetPhysicalAddress(Gart);
  524. AGPLOG(AGP_NOISE,
  525. ("AgpVIACreateGart - GART of length %lx created at VA %08lx, PA %08lx\n",
  526. GartLength,
  527. Gart,
  528. GartPhysical.LowPart));
  529. ASSERT(GartPhysical.HighPart == 0);
  530. ASSERT(VIA_VERIFY_GART_ALIGN(GartPhysical.LowPart,
  531. AgpContext->ApertureLength));
  532. //
  533. // Initialize all the PTEs to free
  534. //
  535. for (i=0; i<GartLength/sizeof(GART_PTE); i++) {
  536. Gart[i].AsUlong = 0;
  537. Gart[i].Soft.State = GART_ENTRY_FREE;
  538. }
  539. ReadVIAConfig(&TempPhysAddr, GATTBASE_OFFSET, sizeof(TempPhysAddr));
  540. TempPhysAddr = (GartPhysical.LowPart & 0xFFFFF000) |
  541. (TempPhysAddr & 0x00000FFF);
  542. WriteVIAConfig(&TempPhysAddr, GATTBASE_OFFSET, sizeof(TempPhysAddr));
  543. //
  544. // Update our extension to reflect the current state.
  545. //
  546. AgpContext->Gart = Gart;
  547. AgpContext->GartLength = GartLength;
  548. AgpContext->GartPhysical = GartPhysical;
  549. #if 0
  550. //
  551. // Test if AGP is working
  552. //
  553. LowestAcceptable.QuadPart = 0;
  554. BoundaryMultiple.QuadPart = 0;
  555. HighestAcceptable.QuadPart = 0xFFFFFFFF;
  556. TestPage =
  557. (PULONG)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE,
  558. LowestAcceptable,
  559. HighestAcceptable,
  560. BoundaryMultiple,
  561. MmNonCached);
  562. if (TestPage) {
  563. PVOID ApertureVa;
  564. ULONG TestPte;
  565. TestPage[0] = AGP_TEST_SIGNATURE;
  566. TestPte = MmGetPhysicalAddress(TestPage).LowPart;
  567. //
  568. // Setup a translation so the first page at aperture base points
  569. // to our test page
  570. //
  571. Gart[0].AsUlong =
  572. (((UINT_PTR)TestPte >> PAGE_SHIFT) * PAGE_SIZE) | GART_ENTRY_VALID;
  573. //
  574. // Flush the write buffer
  575. //
  576. i = Gart[0].AsUlong;
  577. //
  578. // Flush the TLB
  579. //
  580. AgpVIAFlushPageTLB(AgpContext);
  581. //
  582. // Try to read our signature through the aperture/gart translation
  583. //
  584. ApertureVa = MmMapIoSpace(AgpContext->ApertureStart,
  585. PAGE_SIZE,
  586. MmNonCached);
  587. ASSERT(ApertureVa != NULL);
  588. i = *(PULONG)ApertureVa;
  589. AGPLOG(AGP_NOISE,
  590. ("AgpVIACreateGart AGP test: wrote (%08x) PA %08x=badceede, "
  591. "mapped gart[0] %08x=%08x, read AP_BASE (%08x) VA %08x=%08x\n",
  592. TestPage,
  593. TestPte,
  594. Gart,
  595. Gart[0].AsUlong,
  596. AgpContext->ApertureStart.LowPart,
  597. ApertureVa,
  598. i));
  599. MmUnmapIoSpace(ApertureVa, PAGE_SIZE);
  600. //
  601. // Cleanup
  602. //
  603. Gart[0].AsUlong = 0;
  604. Gart[0].Soft.State = GART_ENTRY_FREE;
  605. TestPage[0] = Gart[0].AsUlong;
  606. AgpVIAFlushPageTLB(AgpContext);
  607. MmFreeContiguousMemory(TestPage);
  608. //
  609. // Turn off everything, and bail, AGP is broken
  610. //
  611. if (i != AGP_TEST_SIGNATURE) {
  612. AGPLOG(AGP_CRITICAL,
  613. ("AgpVIACreateGart - AGP failed: Read=%08x\n", i));
  614. AgpDisableAperture(AgpContext);
  615. //
  616. // Need to let the user know what happened here
  617. //
  618. //AgpLogGenericHwFailure();
  619. return STATUS_DEVICE_CONFIGURATION_ERROR;
  620. }
  621. }
  622. #endif
  623. return(STATUS_SUCCESS);
  624. }
  625. NTSTATUS
  626. AgpMapMemory(
  627. IN PAGPVIA_EXTENSION AgpContext,
  628. IN PAGP_RANGE Range,
  629. IN PMDL Mdl,
  630. IN ULONG OffsetInPages,
  631. OUT PHYSICAL_ADDRESS *MemoryBase
  632. )
  633. /*++
  634. Routine Description:
  635. Maps physical memory into the GART somewhere in the specified range.
  636. Arguments:
  637. AgpContext - Supplies the AGP context
  638. Range - Supplies the AGP range that the memory should be mapped into
  639. Mdl - Supplies the MDL describing the physical pages to be mapped
  640. MemoryBase - Returns the physical memory in the aperture where the pages
  641. were mapped.
  642. Return Value:
  643. NTSTATUS
  644. --*/
  645. {
  646. ULONG PageCount;
  647. PGART_PTE Pte;
  648. PGART_PTE StartPte;
  649. ULONG Index;
  650. ULONG TargetState;
  651. PULONG Page;
  652. BOOLEAN Backwards;
  653. GART_PTE NewPte;
  654. VIA_GATT_BASE GATTBase;
  655. NTSTATUS Status;
  656. PAGED_CODE();
  657. ASSERT(Mdl->Next == NULL);
  658. StartPte = Range->Context;
  659. PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
  660. ASSERT(PageCount <= Range->NumberOfPages);
  661. ASSERT(PageCount > 0);
  662. TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
  663. Pte = StartPte + OffsetInPages;
  664. //
  665. // We have a suitable range, now fill it in with the supplied MDL.
  666. //
  667. ASSERT(Pte >= StartPte);
  668. ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages);
  669. NewPte.AsUlong = 0;
  670. NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC :
  671. GART_ENTRY_VALID_WC;
  672. Page = (PULONG)(Mdl + 1);
  673. for (Index = 0; Index < PageCount; Index++) {
  674. ASSERT(Pte[Index].Soft.State == TargetState);
  675. NewPte.Hard.Page = *Page++;
  676. Pte[Index].AsUlong = NewPte.AsUlong;
  677. ASSERT(Pte[Index].Hard.Valid == 1);
  678. }
  679. //
  680. // We have filled in all the PTEs. Read back the last one we wrote
  681. // in order to flush the write buffers.
  682. //
  683. NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
  684. //
  685. // If we have not yet gotten around to enabling the GART aperture, do it now.
  686. //
  687. if (!AgpContext->GlobalEnable) {
  688. VIA_GATT_BASE GARTBASE_Config;
  689. AGPLOG(AGP_NOISE,
  690. ("AgpMapMemory - Enabling global aperture access\n"));
  691. ViaApertureEnable(ON);
  692. ReadVIAConfig(&GARTBASE_Config,
  693. GATTBASE_OFFSET,
  694. sizeof(GARTBASE_Config));
  695. GARTBASE_Config.TT_NonCache = 1;
  696. WriteVIAConfig(&GARTBASE_Config,
  697. GATTBASE_OFFSET,
  698. sizeof(GARTBASE_Config));
  699. ViaGartEnable(ON);
  700. AgpContext->GlobalEnable = TRUE;
  701. }
  702. MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
  703. return(STATUS_SUCCESS);
  704. }
  705. NTSTATUS
  706. AgpUnMapMemory(
  707. IN PAGPVIA_EXTENSION AgpContext,
  708. IN PAGP_RANGE AgpRange,
  709. IN ULONG NumberOfPages,
  710. IN ULONG PageOffset
  711. )
  712. /*++
  713. Routine Description:
  714. Unmaps previously mapped memory in the GART.
  715. Arguments:
  716. AgpContext - Supplies the AGP context
  717. AgpRange - Supplies the AGP range that the memory should be mapped into
  718. NumberOfPages - Supplies the number of pages in the range to be freed.
  719. PageOffset - Supplies the offset into the range where the freeing should begin.
  720. Return Value:
  721. NTSTATUS
  722. --*/
  723. {
  724. ULONG i;
  725. PGART_PTE Pte;
  726. PGART_PTE LastChanged=NULL;
  727. PGART_PTE StartPte;
  728. ULONG NewState;
  729. PAGED_CODE();
  730. ASSERT(PageOffset + NumberOfPages <= AgpRange->NumberOfPages);
  731. StartPte = AgpRange->Context;
  732. Pte = &StartPte[PageOffset];
  733. if (AgpRange->Type == MmNonCached) {
  734. NewState = GART_ENTRY_RESERVED_UC;
  735. } else {
  736. NewState = GART_ENTRY_RESERVED_WC;
  737. }
  738. //
  739. // Flush TLB
  740. //
  741. AgpVIAFlushPageTLB(AgpContext);
  742. for (i=0; i<NumberOfPages; i++) {
  743. if (Pte[i].Hard.Valid) {
  744. Pte[i].Soft.State = NewState;
  745. LastChanged = &Pte[i];
  746. } else {
  747. //
  748. // This page is not mapped, just skip it.
  749. //
  750. AGPLOG(AGP_NOISE,
  751. ("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n",
  752. &Pte[i],
  753. Pte[i].AsUlong,
  754. i));
  755. }
  756. }
  757. //
  758. // We have invalidated all the PTEs. Read back the last one we wrote
  759. // in order to flush the write buffers.
  760. //
  761. if (LastChanged != NULL) {
  762. ULONG Temp;
  763. Temp = *(volatile ULONG *)(&LastChanged->AsUlong);
  764. }
  765. return(STATUS_SUCCESS);
  766. }
  767. PGART_PTE
  768. AgpVIAFindRangeInGart(
  769. IN PGART_PTE StartPte,
  770. IN PGART_PTE EndPte,
  771. IN ULONG Length,
  772. IN BOOLEAN SearchBackward,
  773. IN ULONG SearchState
  774. )
  775. /*++
  776. Routine Description:
  777. Finds a contiguous range in the GART. This routine can
  778. search either from the beginning of the GART forwards or
  779. the end of the GART backwards.
  780. Arguments:
  781. StartIndex - Supplies the first GART pte to search
  782. EndPte - Supplies the last GART to search (inclusive)
  783. Length - Supplies the number of contiguous free entries
  784. to search for.
  785. SearchBackward - TRUE indicates that the search should begin
  786. at EndPte and search backwards. FALSE indicates that the
  787. search should begin at StartPte and search forwards
  788. SearchState - Supplies the PTE state to look for.
  789. Return Value:
  790. Pointer to the first PTE in the GART if a suitable range
  791. is found.
  792. NULL if no suitable range exists.
  793. --*/
  794. {
  795. PGART_PTE Current;
  796. PGART_PTE Last;
  797. LONG Delta;
  798. ULONG Found;
  799. PGART_PTE Candidate;
  800. PAGED_CODE();
  801. ASSERT(EndPte >= StartPte);
  802. ASSERT(Length <= (ULONG)(EndPte - StartPte + 1));
  803. ASSERT(Length != 0);
  804. if (SearchBackward) {
  805. Current = EndPte;
  806. Last = StartPte-1;
  807. Delta = -1;
  808. } else {
  809. Current = StartPte;
  810. Last = EndPte+1;
  811. Delta = 1;
  812. }
  813. Found = 0;
  814. while (Current != Last) {
  815. if (Current->Soft.State == SearchState) {
  816. if (++Found == Length) {
  817. //
  818. // A suitable range was found, return it
  819. //
  820. if (SearchBackward) {
  821. return(Current);
  822. } else {
  823. return(Current - Length + 1);
  824. }
  825. }
  826. } else {
  827. Found = 0;
  828. }
  829. Current += Delta;
  830. }
  831. //
  832. // A suitable range was not found.
  833. //
  834. return(NULL);
  835. }
  836. VOID
  837. AgpVIAFlushPageTLB(
  838. IN PAGPVIA_EXTENSION AgpContext
  839. )
  840. /*++
  841. Routine Description:
  842. Flush the AGP TLB (16 entries)
  843. if hardware does not support FLUSH TLB, then read Aperture 32 times
  844. Arguments:
  845. AgpContext - Supplies the AGP context
  846. Return Value:
  847. None
  848. --*/
  849. {
  850. VIA_GART_TLB_CTRL GARTCTRL_Config;
  851. PAGED_CODE();
  852. if (AgpContext->Cap_FlushTLB) {
  853. ReadVIAConfig(&GARTCTRL_Config,
  854. GARTCTRL_OFFSET,
  855. sizeof(GARTCTRL_Config));
  856. //Flush TLB
  857. GARTCTRL_Config.FlushPageTLB = 1;
  858. WriteVIAConfig(&GARTCTRL_Config,
  859. GARTCTRL_OFFSET,
  860. sizeof(GARTCTRL_Config));
  861. //Stop Flush TLB
  862. GARTCTRL_Config.FlushPageTLB = 0;
  863. WriteVIAConfig(&GARTCTRL_Config,
  864. GARTCTRL_OFFSET,
  865. sizeof(GARTCTRL_Config));
  866. } else {
  867. AgpVIAFlushData(AgpContext);
  868. }
  869. }
  870. VOID
  871. AgpFindFreeRun(
  872. IN PVOID AgpContext,
  873. IN PAGP_RANGE AgpRange,
  874. IN ULONG NumberOfPages,
  875. IN ULONG OffsetInPages,
  876. OUT ULONG *FreePages,
  877. OUT ULONG *FreeOffset
  878. )
  879. /*++
  880. Routine Description:
  881. Finds the first contiguous run of free pages in the specified
  882. part of the reserved range.
  883. Arguments:
  884. AgpContext - Supplies the AGP context
  885. AgpRange - Supplies the AGP range
  886. NumberOfPages - Supplies the size of the region to be searched for free pages
  887. OffsetInPages - Supplies the start of the region to be searched for free pages
  888. FreePages - Returns the length of the first contiguous run of free pages
  889. FreeOffset - Returns the start of the first contiguous run of free pages
  890. Return Value:
  891. None. FreePages == 0 if there are no free pages in the specified range.
  892. --*/
  893. {
  894. PGART_PTE Pte;
  895. ULONG i;
  896. PAGED_CODE();
  897. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  898. //
  899. // Find the first free PTE
  900. //
  901. for (i=0; i<NumberOfPages; i++) {
  902. if (Pte[i].Hard.Valid == 0) {
  903. //
  904. // Found a free PTE, count the contiguous ones.
  905. //
  906. *FreeOffset = i + OffsetInPages;
  907. *FreePages = 0;
  908. while ((i<NumberOfPages) && (Pte[i].Hard.Valid == 0)) {
  909. *FreePages += 1;
  910. ++i;
  911. }
  912. return;
  913. }
  914. }
  915. //
  916. // No free PTEs in the specified range
  917. //
  918. *FreePages = 0;
  919. return;
  920. }
  921. VOID
  922. AgpGetMappedPages(
  923. IN PVOID AgpContext,
  924. IN PAGP_RANGE AgpRange,
  925. IN ULONG NumberOfPages,
  926. IN ULONG OffsetInPages,
  927. OUT PMDL Mdl
  928. )
  929. /*++
  930. Routine Description:
  931. Returns the list of physical pages mapped into the specified
  932. range in the GART.
  933. Arguments:
  934. AgpContext - Supplies the AGP context
  935. AgpRange - Supplies the AGP range
  936. NumberOfPages - Supplies the number of pages to be returned
  937. OffsetInPages - Supplies the start of the region
  938. Mdl - Returns the list of physical pages mapped in the specified range.
  939. Return Value:
  940. None
  941. --*/
  942. {
  943. PGART_PTE Pte;
  944. ULONG i;
  945. PULONG Pages;
  946. PAGED_CODE();
  947. ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
  948. Pages = (PULONG)(Mdl + 1);
  949. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  950. for (i=0; i<NumberOfPages; i++) {
  951. ASSERT(Pte[i].Hard.Valid == 1);
  952. Pages[i] = Pte[i].Hard.Page;
  953. }
  954. }
  955. VOID
  956. AgpVIAFlushData(
  957. IN PAGPVIA_EXTENSION AgpContext
  958. )
  959. /*++
  960. Routine Description:
  961. Flushes the chipset TB by reading 32 pages of aperture memory space.
  962. Arguments:
  963. AgpContext - Supplies the AGP context
  964. Return Value:
  965. NTSTATUS
  966. --*/
  967. {
  968. PVOID ApertureVirtAddr, TempVirtualAddr;
  969. ULONG ReadData;
  970. ULONG Index;
  971. PAGED_CODE();
  972. ApertureVirtAddr = MmMapIoSpace(AgpContext->ApertureStart,
  973. 32 * PAGE_SIZE,
  974. MmNonCached);
  975. ASSERT(ApertureVirtAddr != NULL);
  976. if (ApertureVirtAddr != NULL) {
  977. TempVirtualAddr = ApertureVirtAddr;
  978. for (Index = 0; Index < 32; Index++) {
  979. ReadData = *(PULONG)TempVirtualAddr;
  980. TempVirtualAddr = (PVOID)((PCCHAR)TempVirtualAddr + PAGE_SIZE);
  981. }
  982. MmUnmapIoSpace(ApertureVirtAddr, 32 * PAGE_SIZE);
  983. } else {
  984. AGPLOG(AGP_CRITICAL,("Agp440FlushPageTLB: Invalid address\n"));
  985. }
  986. }
  987. NTSTATUS
  988. AgpSpecialTarget(
  989. IN PAGPVIA_EXTENSION AgpContext,
  990. IN ULONGLONG DeviceFlags
  991. )
  992. /*++
  993. Routine Description:
  994. This routine makes "special" tweaks to the AGP chipset
  995. Arguments:
  996. AgpContext - Supplies the AGP context
  997. DeviceFlags - Flags indicating what tweaks to perform
  998. Return Value:
  999. STATUS_SUCCESS, or error
  1000. --*/
  1001. {
  1002. NTSTATUS Status;
  1003. //
  1004. // Should we change the AGP rate?
  1005. //
  1006. if (DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) {
  1007. Status = AgpVIASetRate(AgpContext,
  1008. (ULONG)((DeviceFlags & AGP_FLAG_SPECIAL_RESERVE)
  1009. >> AGP_FLAG_SET_RATE_SHIFT));
  1010. if (!NT_SUCCESS(Status)) {
  1011. return Status;
  1012. }
  1013. }
  1014. //
  1015. // Add more tweaks here...
  1016. //
  1017. AgpContext->SpecialTarget |= DeviceFlags;
  1018. return STATUS_SUCCESS;
  1019. }
  1020. NTSTATUS
  1021. AgpVIASetRate(
  1022. IN PAGPVIA_EXTENSION AgpContext,
  1023. IN ULONG AgpRate
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine sets the AGP rate
  1028. Arguments:
  1029. AgpContext - Supplies the AGP context
  1030. AgpRate - Rate to set
  1031. note: this routine assumes that AGP has already been enabled, and that
  1032. whatever rate we've been asked to set is supported by master
  1033. Return Value:
  1034. STATUS_SUCCESS, or error status
  1035. --*/
  1036. {
  1037. NTSTATUS Status;
  1038. ULONG TargetEnable;
  1039. ULONG MasterEnable;
  1040. PCI_AGP_CAPABILITY TargetCap;
  1041. PCI_AGP_CAPABILITY MasterCap;
  1042. BOOLEAN ReverseInit;
  1043. //
  1044. // Read capabilities
  1045. //
  1046. Status = AgpLibGetPciDeviceCapability(0, 0, &TargetCap);
  1047. if (!NT_SUCCESS(Status)) {
  1048. AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibGetPciDeviceCapability "
  1049. "failed %08lx\n", Status));
  1050. return Status;
  1051. }
  1052. Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
  1053. if (!NT_SUCCESS(Status)) {
  1054. AGPLOG(AGP_WARNING, ("AGPVIASetRate: AgpLibGetMasterCapability "
  1055. "failed %08lx\n", Status));
  1056. return Status;
  1057. }
  1058. //
  1059. // Verify the requested rate is supported by both master and target
  1060. //
  1061. if (!(AgpRate & TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate)) {
  1062. return STATUS_INVALID_PARAMETER;
  1063. }
  1064. //
  1065. // Disable AGP while the pull the rug out from underneath
  1066. //
  1067. TargetEnable = TargetCap.AGPCommand.AGPEnable;
  1068. TargetCap.AGPCommand.AGPEnable = 0;
  1069. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1070. if (!NT_SUCCESS(Status)) {
  1071. AGPLOG(AGP_WARNING,
  1072. ("AGPVIASetRate: AgpLibSetPciDeviceCapability %08lx for "
  1073. "Target failed %08lx\n",
  1074. &TargetCap,
  1075. Status));
  1076. return Status;
  1077. }
  1078. MasterEnable = MasterCap.AGPCommand.AGPEnable;
  1079. MasterCap.AGPCommand.AGPEnable = 0;
  1080. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1081. if (!NT_SUCCESS(Status)) {
  1082. AGPLOG(AGP_WARNING,
  1083. ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed "
  1084. "%08lx\n",
  1085. &MasterCap,
  1086. Status));
  1087. return Status;
  1088. }
  1089. //
  1090. // Fire up AGP with new rate
  1091. //
  1092. ReverseInit =
  1093. (AgpContext->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) ==
  1094. AGP_FLAG_REVERSE_INITIALIZATION;
  1095. if (ReverseInit) {
  1096. MasterCap.AGPCommand.Rate = AgpRate;
  1097. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1098. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1099. if (!NT_SUCCESS(Status)) {
  1100. AGPLOG(AGP_WARNING,
  1101. ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed "
  1102. "%08lx\n",
  1103. &MasterCap,
  1104. Status));
  1105. }
  1106. }
  1107. TargetCap.AGPCommand.Rate = AgpRate;
  1108. TargetCap.AGPCommand.AGPEnable = TargetEnable;
  1109. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1110. if (!NT_SUCCESS(Status)) {
  1111. AGPLOG(AGP_WARNING,
  1112. ("AGPVIASetRate: AgpLibSetPciDeviceCapability %08lx for "
  1113. "Target failed %08lx\n",
  1114. &TargetCap,
  1115. Status));
  1116. return Status;
  1117. }
  1118. if (!ReverseInit) {
  1119. MasterCap.AGPCommand.Rate = AgpRate;
  1120. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1121. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1122. if (!NT_SUCCESS(Status)) {
  1123. AGPLOG(AGP_WARNING,
  1124. ("AGPVIASetRate: AgpLibSetMasterCapability %08lx failed "
  1125. "%08lx\n",
  1126. &MasterCap,
  1127. Status));
  1128. }
  1129. }
  1130. return Status;
  1131. }