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.

1326 lines
33 KiB

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