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.

1241 lines
34 KiB

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