Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1742 lines
51 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. gart.c
  5. Abstract:
  6. This module contains the routines for setting and querying the AGP
  7. aperture, and for Reserving, Releasing, Mapping, and Unmapping.
  8. TODO:
  9. 1. Optimize for dual memory controllers (Done on 3/24/99 by elliots)
  10. 2. Claim MMIO resources for the chipset
  11. 3. Make sure the driver is generic for all RCC based systems (not just SP700).
  12. Author:
  13. John Vert (jvert) 10/30/1997
  14. Revision History:
  15. 12/15/97 John Theisen Modified to support Compaq Chipsets
  16. 10/09/98 John Theisen Modified to enable Shadowing in the SP700
  17. prior to MMIO writes.
  18. 01/15/99 John Theisen Modified to disable the aperture, by
  19. shrinking it to size = 0.
  20. 3/24/99 Elliot Shmukler Added support for "favored" memory
  21. ranges for AGP physical memory allocation,
  22. fixed some bugs. These changes optimizine
  23. the driver for dual memory controllers.
  24. 3/16/00 Peter Johnston Add support for ServerWorks HE chipset.
  25. --*/
  26. #include "AGPCPQ.H"
  27. //
  28. // Local routine prototypes
  29. //
  30. NTSTATUS
  31. AgpCPQCreateGart(
  32. IN PAGPCPQ_EXTENSION AgpContext,
  33. IN ULONG MinimumPages
  34. );
  35. NTSTATUS
  36. AgpCPQSetRate(
  37. IN PVOID AgpContext,
  38. IN ULONG AgpRate
  39. );
  40. PGART_PTE
  41. AgpCPQFindRangeInGart(
  42. IN PGART_PTE StartPte,
  43. IN PGART_PTE EndPte,
  44. IN ULONG Length,
  45. IN BOOLEAN SearchBackward,
  46. IN ULONG SearchState
  47. );
  48. VOID
  49. AgpCPQMaintainGARTCacheCoherency (
  50. IN PAGPCPQ_EXTENSION AgpContext,
  51. IN PHYSICAL_ADDRESS MemoryBase,
  52. IN ULONG NumberOfEntries,
  53. IN BOOLEAN InvalidateAll
  54. );
  55. PIO_RESOURCE_LIST
  56. AgpCPQGetApSizeRequirements(
  57. ULONG MaxSize,
  58. ULONG Count
  59. );
  60. NTSTATUS
  61. AgpCPQSetApSizeInChipset
  62. (
  63. IN UCHAR NewSetApSize,
  64. IN UCHAR NewSetAgpValid
  65. );
  66. NTSTATUS
  67. AgpCPQSetApBaseInChipset
  68. (
  69. IN PHYSICAL_ADDRESS NewBase
  70. );
  71. //
  72. // IMPLEMENTATION
  73. //
  74. NTSTATUS
  75. AgpQueryAperture(
  76. IN PAGPCPQ_EXTENSION AgpContext,
  77. OUT PHYSICAL_ADDRESS *CurrentBase,
  78. OUT ULONG *CurrentSizeInPages,
  79. OUT OPTIONAL PIO_RESOURCE_LIST *pApertureRequirements
  80. )
  81. /*******************************************************************************
  82. *
  83. * Routine Functional Description:
  84. *
  85. * Returns the current base and size of the GART aperture. Optionally returns
  86. * the possible GART settings.
  87. *
  88. * Arguments:
  89. *
  90. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  91. *
  92. * CurrentBase -- Returns the current physical address of the aperture.
  93. *
  94. * CurrentSizeInPages -- Returns the current size of the aperture, in pages.
  95. *
  96. * pApertureRequirements -- If present, returns the possible aperture
  97. * settings.
  98. *
  99. * Return Value:
  100. *
  101. * NTSTATUS
  102. *
  103. *******************************************************************************/
  104. {
  105. ULONG BAR0, CodedApSize;
  106. AGPLOG(AGP_NOISE, ("AgpCpq: AgpQueryAperture entered.\n"));
  107. //
  108. // Get the current base physical address of the AGP Aperture.
  109. //
  110. ReadCPQConfig(&BAR0, OFFSET_BAR0, sizeof(BAR0));
  111. CurrentBase->QuadPart = BAR0 & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  112. //
  113. // Get the (current) size of the aperture. This is done by writing all ones
  114. // to BAR0, and then reading back the value. The Read/Write attributes
  115. // of bits 31:25 in BAR0 will indicate the size.
  116. //
  117. CodedApSize = ALL_ONES;
  118. WriteCPQConfig(&CodedApSize, OFFSET_BAR0, sizeof(ULONG));
  119. ReadCPQConfig(&CodedApSize, OFFSET_BAR0, sizeof(CodedApSize));
  120. WriteCPQConfig(&BAR0, OFFSET_BAR0, sizeof(ULONG));
  121. CodedApSize &= MASK_LOW_TWENTYFIVE;
  122. switch(CodedApSize) {
  123. case BAR0_CODED_AP_SIZE_0MB:
  124. *CurrentSizeInPages = 0;
  125. break;
  126. case BAR0_CODED_AP_SIZE_32MB:
  127. *CurrentSizeInPages = (32 * 1024*1024) / PAGE_SIZE;
  128. break;
  129. case BAR0_CODED_AP_SIZE_64MB:
  130. *CurrentSizeInPages = (64 * 1024*1024) / PAGE_SIZE;
  131. break;
  132. case BAR0_CODED_AP_SIZE_128MB:
  133. *CurrentSizeInPages = (128* 1024*1024) / PAGE_SIZE;
  134. break;
  135. case BAR0_CODED_AP_SIZE_256MB:
  136. *CurrentSizeInPages = (256* 1024*1024) / PAGE_SIZE;
  137. break;
  138. case BAR0_CODED_AP_SIZE_512MB:
  139. *CurrentSizeInPages = (512* 1024*1024) / PAGE_SIZE;
  140. break;
  141. case BAR0_CODED_AP_SIZE_1GB:
  142. *CurrentSizeInPages = (1024*1024*1024) / PAGE_SIZE;
  143. break;
  144. case BAR0_CODED_AP_SIZE_2GB:
  145. *CurrentSizeInPages = (BYTES_2G) / PAGE_SIZE;
  146. break;
  147. default:
  148. AGPLOG(AGP_CRITICAL,
  149. ("AGPCPQ - AgpQueryAperture - Unexpected HW aperture size: %x.\n",
  150. *CurrentSizeInPages * PAGE_SIZE));
  151. ASSERT(FALSE);
  152. AgpContext->ApertureStart.QuadPart = 0;
  153. AgpContext->ApertureLength = 0;
  154. return(STATUS_UNSUCCESSFUL);
  155. }
  156. //
  157. // Remember the current aperture settings
  158. //
  159. AgpContext->ApertureStart.QuadPart = CurrentBase->QuadPart;
  160. AgpContext->ApertureLength = *CurrentSizeInPages * PAGE_SIZE;
  161. //
  162. // The pApertureRequirements will be returned in an
  163. // IO_RESOURCE_REQUIREMENTS_LIST structure
  164. // that describes the possible aperture sizes and bases that we support.
  165. // This will depend on which chipset we are running on, i.e. the
  166. // Device-VendorID in the PCI config header.
  167. //
  168. if (pApertureRequirements != NULL) {
  169. switch (AgpContext->DeviceVendorID) {
  170. case AGP_CNB20_LE_IDENTIFIER:
  171. *pApertureRequirements = AgpCPQGetApSizeRequirements(
  172. AP_MAX_SIZE_CNB20_LE, AP_SIZE_COUNT_CNB20_LE);
  173. break;
  174. case AGP_CNB20_HE_IDENTIFIER:
  175. *pApertureRequirements = AgpCPQGetApSizeRequirements(
  176. AP_MAX_SIZE_CNB20_HE, AP_SIZE_COUNT_CNB20_HE);
  177. break;
  178. case AGP_DRACO_IDENTIFIER:
  179. *pApertureRequirements = AgpCPQGetApSizeRequirements(
  180. AP_MAX_SIZE_DRACO, AP_SIZE_COUNT_DRACO);
  181. break;
  182. default:
  183. *pApertureRequirements = NULL;
  184. break;
  185. }
  186. }
  187. return(STATUS_SUCCESS);
  188. }
  189. NTSTATUS
  190. AgpSetAperture(
  191. IN PAGPCPQ_EXTENSION AgpContext,
  192. IN PHYSICAL_ADDRESS NewBase,
  193. IN ULONG NewSizeInPages
  194. )
  195. /*******************************************************************************
  196. *
  197. * Routine Functional Description:
  198. *
  199. * Sets the AGP aperture to the requested settings.
  200. *
  201. * Arguments:
  202. *
  203. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  204. *
  205. * NewBase -- Supplies the new physical memroy base for the AGP aperture.
  206. *
  207. * NewSizeInPages -- Supplies the new size for the AGP aperture.
  208. *
  209. * Return Value:
  210. *
  211. * NTSTATUS
  212. *
  213. *******************************************************************************/
  214. {
  215. NTSTATUS Status = STATUS_SUCCESS; // Assume successful completion.
  216. UCHAR SetApSize;
  217. ULONG ApBase;
  218. AGP_AP_SIZE_REG AgpApSizeRegister;
  219. BOOLEAN ChangingBase = TRUE;
  220. BOOLEAN ChangingSize = TRUE;
  221. AGPLOG(AGP_NOISE, ("AgpCpq: AgpSetAperture entered.\n"));
  222. //
  223. // If we are resuming from s3, or s4, we need to reprogram
  224. // the gart cache enable and base
  225. //
  226. if (AgpContext->Gart) {
  227. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  228. AgpContext->MMIO->GartBase.Page =
  229. (AgpContext->GartPointer >> PAGE_SHIFT);
  230. AgpContext->MMIO->FeatureControl.GARTCacheEnable = 1;
  231. //
  232. // If the chipset supports linking then enable linking.
  233. //
  234. if (AgpContext->MMIO->Capabilities.LinkingSupported==1) {
  235. AgpContext->MMIO->FeatureControl.LinkingEnable=1;
  236. }
  237. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  238. }
  239. //
  240. // Reprogram Special Target settings when the chip
  241. // is powered off, but ignore rate changes as those were already
  242. // applied during MasterInit
  243. //
  244. if (AgpContext->SpecialTarget & ~AGP_FLAG_SPECIAL_RESERVE) {
  245. AgpSpecialTarget(AgpContext,
  246. AgpContext->SpecialTarget &
  247. ~AGP_FLAG_SPECIAL_RESERVE);
  248. }
  249. //
  250. // Determine which parameter(s) we are being asked to change.
  251. //
  252. if (NewBase.QuadPart == AgpContext->ApertureStart.QuadPart)
  253. {
  254. ChangingBase = FALSE;
  255. }
  256. if (NewSizeInPages == AgpContext->ApertureLength / PAGE_SIZE)
  257. {
  258. ChangingSize = FALSE;
  259. }
  260. //
  261. // If the new settings match the current settings, leave everything alone.
  262. //
  263. if ( !ChangingBase && !ChangingSize )
  264. {
  265. return(STATUS_SUCCESS);
  266. }
  267. //
  268. // Make sure the supplied Base is aligned on the appropriate boundary for the size.
  269. //
  270. ASSERT(NewBase.HighPart == 0);
  271. ASSERT((NewBase.LowPart + (NewSizeInPages * PAGE_SIZE) - 1) <= ALL_ONES);
  272. ASSERT((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) == 0);
  273. if ((NewBase.QuadPart & ((NewSizeInPages * PAGE_SIZE) - 1)) != 0 )
  274. {
  275. AGPLOG(AGP_CRITICAL,
  276. ("AgpSetAperture - invalid base: %I64X for aperture of %lx pages\n",
  277. NewBase.QuadPart,
  278. NewSizeInPages));
  279. return(STATUS_INVALID_PARAMETER);
  280. }
  281. //
  282. // Change the size first, since doing so will modify the Read/Write attributes
  283. // of the appropriate bits in the Aperture Base register.
  284. //
  285. if (ChangingSize) {
  286. //
  287. // Draco only supports the default 256MB h/w Aperture Size, and can't change it, so fail.
  288. //
  289. if (AgpContext->DeviceVendorID == AGP_DRACO_IDENTIFIER)
  290. {
  291. ASSERT(NewSizeInPages != (256 * 1024*1024));
  292. AGPLOG(AGP_CRITICAL,
  293. ("AgpSetAperture - Chipset incapable of changing Aperture Size.\n"));
  294. return(STATUS_INVALID_PARAMETER);
  295. }
  296. //
  297. // RCC HE and LE chipset both support from 32M to 2G h/w Aperture Size.
  298. //
  299. ASSERT( (AgpContext->DeviceVendorID == AGP_CNB20_LE_IDENTIFIER) ||
  300. (AgpContext->DeviceVendorID == AGP_CNB20_HE_IDENTIFIER) );
  301. //
  302. // Determine the value to use to set the aperture size in the chipset's
  303. // Device Address Space Size register.
  304. //
  305. switch(NewSizeInPages) {
  306. case (32 * 1024*1024) / PAGE_SIZE:
  307. SetApSize = SET_AP_SIZE_32MB;
  308. break;
  309. case (64 * 1024*1024) / PAGE_SIZE:
  310. SetApSize = SET_AP_SIZE_64MB;
  311. break;
  312. case (128 * 1024*1024) / PAGE_SIZE:
  313. SetApSize = SET_AP_SIZE_128MB;
  314. break;
  315. case (256 * 1024*1024) / PAGE_SIZE:
  316. SetApSize = SET_AP_SIZE_256MB;
  317. break;
  318. case (512 * 1024*1024) / PAGE_SIZE:
  319. SetApSize = SET_AP_SIZE_512MB;
  320. break;
  321. case (1024 * 1024*1024) / PAGE_SIZE:
  322. SetApSize = SET_AP_SIZE_1GB;
  323. break;
  324. case (BYTES_2G) / PAGE_SIZE:
  325. SetApSize = SET_AP_SIZE_2GB;
  326. break;
  327. default:
  328. AGPLOG(AGP_CRITICAL,
  329. ("AgpSetAperture - Invalid size: %lx pages. Base: %I64X.\n",
  330. NewSizeInPages,
  331. NewBase.QuadPart));
  332. ASSERT(FALSE);
  333. return(STATUS_INVALID_PARAMETER);
  334. }
  335. //
  336. // Set the aperture size and set AgpValid bit. This must be done before setting the Aperture Base.
  337. //
  338. Status = AgpCPQSetApSizeInChipset(SetApSize, 1);
  339. if (!NT_SUCCESS(Status))
  340. {
  341. return(Status);
  342. }
  343. } // End if ChangingSize
  344. if (ChangingBase) {
  345. //
  346. // Set the aperture base.
  347. //
  348. Status = AgpCPQSetApBaseInChipset(NewBase);
  349. if (!NT_SUCCESS(Status))
  350. {
  351. return(Status);
  352. }
  353. } // End if ChangingBase
  354. //
  355. // Update our extension to reflect the new GART setting
  356. //
  357. AgpContext->ApertureStart = NewBase;
  358. AgpContext->ApertureLength = NewSizeInPages * PAGE_SIZE;
  359. return(STATUS_SUCCESS);
  360. }
  361. VOID
  362. AgpDisableAperture(
  363. IN PAGPCPQ_EXTENSION AgpContext
  364. )
  365. /*++
  366. Routine Description:
  367. Disables the GART aperture so that this resource is available
  368. for other devices
  369. Arguments:
  370. AgpContext - Supplies the AGP context
  371. Return Value:
  372. None - this routine must always succeed.
  373. --*/
  374. {
  375. AGPLOG(AGP_NOISE, ("AgpCpq: AgpDisableAperture entered.\n"));
  376. //
  377. // Set the ApSize and AgpValid to 0, which causes BAR0 to be set back
  378. // to zero and to be read only.
  379. //
  380. AgpCPQSetApSizeInChipset(0, 0);
  381. //
  382. // Nuke the Gart! (It's meaningless now...)
  383. //
  384. if (AgpContext->Gart != NULL) {
  385. MmFreeContiguousMemory(AgpContext->Gart);
  386. AgpContext->Gart = NULL;
  387. AgpContext->GartLength = 0;
  388. }
  389. }
  390. NTSTATUS
  391. AgpReserveMemory(
  392. IN PAGPCPQ_EXTENSION AgpContext,
  393. IN OUT AGP_RANGE *Range
  394. )
  395. /*******************************************************************************
  396. *
  397. * Routine Functional Description:
  398. *
  399. * Reserves a range of memory in the GART.
  400. *
  401. * Arguments:
  402. *
  403. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  404. *
  405. * Range -- Supplies the AGP_RANGE structure. AGPLIB will have filled in
  406. * NumberOfPages and Type. This routine will fill in MemoryBase
  407. * and Context.
  408. *
  409. * Return Value:
  410. *
  411. * NTSTATUS
  412. *
  413. *******************************************************************************/
  414. {
  415. ULONG Index;
  416. ULONG NewState;
  417. NTSTATUS Status;
  418. PGART_PTE FoundRange;
  419. BOOLEAN Backwards;
  420. ASSERT((Range->Type == MmNonCached) || (Range->Type == MmWriteCombined));
  421. ASSERT(Range->NumberOfPages <= (AgpContext->ApertureLength / PAGE_SIZE));
  422. AGPLOG(AGP_NOISE, ("AgpCpq: AgpReserveMemory entered.\n"));
  423. //
  424. // If we have not allocated our GART yet, now is the time to do so
  425. //
  426. if (AgpContext->Gart == NULL) {
  427. ASSERT(AgpContext->GartLength == 0);
  428. Status = AgpCPQCreateGart(AgpContext, Range->NumberOfPages);
  429. if (!NT_SUCCESS(Status)) {
  430. AGPLOG(AGP_CRITICAL,
  431. ("AgpCPQCreateGart failed %08lx to create GART of size %lx\n",
  432. Status,
  433. AgpContext->ApertureLength/PAGE_SIZE));
  434. return(Status);
  435. }
  436. }
  437. ASSERT(AgpContext->GartLength != 0);
  438. //
  439. // Now that we have a GART, try and find enough contiguous entries
  440. // to satisfy the request. Requests for uncached memory will scan
  441. // from high addresses to low addresses. Requests for write-combined
  442. // memory will scan from low addresses to high addresses. We will
  443. // use a first-fit algorithm to try and keep the allocations
  444. // packed and contiguous.
  445. //
  446. Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE;
  447. FoundRange = AgpCPQFindRangeInGart(&AgpContext->Gart[0],
  448. &AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
  449. Range->NumberOfPages, Backwards, GART_ENTRY_FREE);
  450. if (FoundRange == NULL) {
  451. //
  452. // A big enough chunk was not found.
  453. //
  454. AGPLOG(AGP_CRITICAL,
  455. ("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n",
  456. Range->NumberOfPages,
  457. Range->Type,
  458. AgpContext->Gart));
  459. //
  460. // This is where we could try and grow the GART
  461. //
  462. return(STATUS_INSUFFICIENT_RESOURCES);
  463. }
  464. AGPLOG(AGP_NOISE,
  465. ("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n",
  466. Range->NumberOfPages,
  467. FoundRange));
  468. //
  469. // Set these pages to reserved
  470. //
  471. if (Range->Type == MmNonCached) {
  472. NewState = GART_ENTRY_RESERVED_UC;
  473. } else {
  474. NewState = GART_ENTRY_RESERVED_WC;
  475. }
  476. for (Index = 0; Index < Range->NumberOfPages; Index++) {
  477. ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE);
  478. FoundRange[Index].AsUlong = 0;
  479. FoundRange[Index].Soft.State = NewState;
  480. }
  481. //
  482. // Return the values.
  483. //
  484. Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart +
  485. (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE;
  486. Range->Context = FoundRange;
  487. ASSERT(Range->MemoryBase.HighPart == 0);
  488. AGPLOG(AGP_NOISE,
  489. ("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
  490. FoundRange,
  491. Range->MemoryBase.LowPart));
  492. return(STATUS_SUCCESS);
  493. }
  494. NTSTATUS
  495. AgpReleaseMemory(
  496. IN PAGPCPQ_EXTENSION AgpContext,
  497. IN PAGP_RANGE Range
  498. )
  499. /*******************************************************************************
  500. *
  501. * Routine Functional Description:
  502. *
  503. * Releases memory previously reserved with AgpReserveMemory.
  504. *
  505. * Arguments:
  506. *
  507. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  508. *
  509. * Range -- Supplies the range to be released.
  510. *
  511. * Return Value:
  512. *
  513. * NTSTATUS
  514. *
  515. *******************************************************************************/
  516. {
  517. PGART_PTE Pte, LastPteWritten;
  518. ULONG Start, ReadBack, PolledValue, Retry;
  519. AGPLOG(AGP_NOISE, ("AgpCpq: AgpReleaseMemory entered.\n"));
  520. //
  521. // Go through and free all the PTEs. None of these should still
  522. // be valid at this point, nor should they be mapped.
  523. //
  524. for (Pte = Range->Context;
  525. Pte < (PGART_PTE)Range->Context + Range->NumberOfPages;
  526. Pte++)
  527. {
  528. ASSERT(Pte->Hard.Page == 0);
  529. if (Range->Type == MmNonCached) {
  530. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
  531. } else {
  532. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
  533. }
  534. Pte->Soft.State = GART_ENTRY_FREE;
  535. LastPteWritten = Pte;
  536. }
  537. //
  538. // Invalidate the GART Cache appropriately.
  539. //
  540. AgpCPQMaintainGARTCacheCoherency(AgpContext,
  541. Range->MemoryBase,
  542. Range->NumberOfPages,
  543. FALSE );
  544. //
  545. // Flush the posted write buffers
  546. //
  547. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  548. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  549. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  550. ReadBack = *(volatile ULONG *)&LastPteWritten->AsUlong;
  551. for (Retry = 1000; Retry; Retry--) {
  552. PolledValue =
  553. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  554. if (PolledValue == 0) {
  555. break;
  556. }
  557. }
  558. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  559. Range->MemoryBase.QuadPart = 0;
  560. return(STATUS_SUCCESS);
  561. }
  562. NTSTATUS
  563. AgpMapMemory(
  564. IN PAGPCPQ_EXTENSION AgpContext,
  565. IN PAGP_RANGE Range,
  566. IN PMDL Mdl,
  567. IN ULONG OffsetInPages,
  568. OUT PHYSICAL_ADDRESS *MemoryBase
  569. )
  570. /*******************************************************************************
  571. *
  572. * Routine Functional Description:
  573. *
  574. * Maps physical memory into the AGP aperture, somewhere in the specified
  575. * range.
  576. *
  577. * Arguments:
  578. *
  579. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  580. *
  581. * Range -- Supplies the AGP range into which the memory should be mapped.
  582. *
  583. * Mdl -- Supplies the MDL describing the physical pages to be mapped.
  584. *
  585. * OffsetInPages - Supplies the offset into the reserved range where the
  586. * mapping should begin.
  587. *
  588. * MemoryBase -- Returns the 'physical' address in the aperture where the
  589. * pages were mapped.
  590. *
  591. * Return Value:
  592. *
  593. * NTSTATUS
  594. *
  595. *******************************************************************************/
  596. {
  597. ULONG PageCount;
  598. PGART_PTE Pte;
  599. PGART_PTE StartPte;
  600. ULONG Index;
  601. ULONG TargetState;
  602. PULONG Page;
  603. BOOLEAN Backwards;
  604. GART_PTE NewPte;
  605. ULONG PolledValue, Retry;
  606. AGPLOG(AGP_NOISE, ("AgpCpq: AgpMapMemory entered.\n"));
  607. ASSERT(Mdl->Next == NULL);
  608. StartPte = Range->Context;
  609. PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
  610. ASSERT(PageCount <= Range->NumberOfPages);
  611. ASSERT(OffsetInPages <= Range->NumberOfPages);
  612. ASSERT(PageCount + OffsetInPages <= Range->NumberOfPages);
  613. ASSERT(PageCount > 0);
  614. TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC :
  615. GART_ENTRY_RESERVED_WC;
  616. Pte = StartPte + OffsetInPages;
  617. //
  618. // We have found a suitable spot to map the pages. Now map them.
  619. //
  620. ASSERT(Pte >= StartPte);
  621. ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages);
  622. NewPte.AsUlong = 0;
  623. NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC :
  624. GART_ENTRY_VALID_WC;
  625. Page = (PULONG)(Mdl + 1);
  626. for (Index = 0; Index < PageCount; Index++)
  627. {
  628. ASSERT(Pte[Index].Soft.State == TargetState);
  629. NewPte.Hard.Page = *Page++;
  630. Pte[Index].AsUlong = NewPte.AsUlong;
  631. ASSERT(Pte[Index].Hard.Valid == 1);
  632. ASSERT(Pte[Index].Hard.Linked == 0);
  633. }
  634. //
  635. // If Linking is supported, then link the entries by setting the link bit
  636. // in all entries, except the last entry, in the mapped set.
  637. //
  638. if (AgpContext->MMIO->Capabilities.LinkingSupported) {
  639. ASSERT(AgpContext->MMIO->FeatureControl.LinkingEnable);
  640. for (Index = 0; Index < PageCount-1; Index++) {
  641. ASSERT(Pte[Index].Hard.Page != 0);
  642. Pte[Index].Hard.Linked = 1;
  643. }
  644. }
  645. //
  646. // We have filled in all the PTEs. Now flush the write buffers.
  647. //
  648. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  649. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  650. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  651. NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
  652. for (Retry = 1000; Retry; Retry--) {
  653. PolledValue =
  654. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  655. if (PolledValue == 0) {
  656. break;
  657. }
  658. }
  659. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  660. //
  661. // Return where they are mapped
  662. //
  663. MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
  664. return(STATUS_SUCCESS);
  665. }
  666. NTSTATUS
  667. AgpUnMapMemory(
  668. IN PAGPCPQ_EXTENSION AgpContext,
  669. IN PAGP_RANGE AgpRange,
  670. IN ULONG NumberOfPages,
  671. IN ULONG OffsetInPages
  672. )
  673. /*******************************************************************************
  674. *
  675. * Routine Functional Description:
  676. *
  677. * UnMaps all or part of the memory that was previously mapped by AgpMapMemory.
  678. *
  679. * Arguments:
  680. *
  681. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  682. *
  683. * AgpRange -- Supplies the AGP range out of which memory should be un-mapped.
  684. *
  685. * NumberOfPages -- Supplies the number of pages in the range to be un-mapped.
  686. *
  687. * OffsetInPages -- Supplies the offset into the Reserved Range where the un-mapping
  688. * should begin.
  689. *
  690. * Return Value:
  691. *
  692. * NTSTATUS
  693. *
  694. *******************************************************************************/
  695. {
  696. ULONG Index, TargetState, ReadBack, PolledValue, Retry;
  697. PGART_PTE ReservedBasePte;
  698. PGART_PTE Pte;
  699. PGART_PTE LastChangedPte=NULL;
  700. PHYSICAL_ADDRESS pa;
  701. AGPLOG(AGP_NOISE, ("AgpCpq: AgpUnMapMemory entered.\n"));
  702. ASSERT(OffsetInPages + NumberOfPages <= AgpRange->NumberOfPages);
  703. ReservedBasePte = AgpRange->Context;
  704. Pte = &ReservedBasePte[OffsetInPages];
  705. TargetState = (AgpRange->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
  706. //
  707. // UnMap each entry by putting each Mapped Entry back into the 'Reserved State'
  708. //
  709. for (Index=0; Index < NumberOfPages; Index++) {
  710. if (Pte[Index].Hard.Valid) {
  711. ASSERT(Pte[Index].Hard.Page != 0);
  712. Pte[Index].Hard.Page = 0;
  713. Pte[Index].Soft.State = TargetState;
  714. LastChangedPte = &Pte[Index];
  715. } else {
  716. //
  717. // We are being asked to un-map a page that is not mapped.
  718. //
  719. ASSERT(Pte[Index].Hard.Page == 0);
  720. ASSERT(Pte[Index].Soft.State == TargetState);
  721. AGPLOG(AGP_NOISE,
  722. ("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n",
  723. &Pte[Index],
  724. Pte[Index].AsUlong,
  725. Index));
  726. }
  727. }
  728. //
  729. // Maintain link bit coherency within this reserved range.
  730. //
  731. if (OffsetInPages != 0) {
  732. ASSERT(OffsetInPages >= 1);
  733. if (ReservedBasePte[OffsetInPages-1].Hard.Linked == 1) {
  734. ASSERT(ReservedBasePte[OffsetInPages-1].Hard.Valid == 1);
  735. ReservedBasePte[OffsetInPages-1].Hard.Linked = 0;
  736. }
  737. }
  738. //
  739. // Invalidate the Cache appropriately.
  740. //
  741. pa.HighPart = 0;
  742. pa.LowPart = AgpRange->MemoryBase.LowPart + OffsetInPages*PAGE_SIZE;
  743. AgpCPQMaintainGARTCacheCoherency(AgpContext, pa, NumberOfPages, FALSE);
  744. //
  745. // Flush the posted write buffers
  746. //
  747. if (LastChangedPte != NULL)
  748. {
  749. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  750. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  751. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  752. ReadBack = *((volatile ULONG *)&(LastChangedPte[0].AsUlong));
  753. for (Retry = 2000; Retry; Retry--) {
  754. PolledValue =
  755. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  756. if (PolledValue == 0) {
  757. break;
  758. }
  759. }
  760. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  761. }
  762. return(STATUS_SUCCESS);
  763. }
  764. NTSTATUS
  765. AgpCPQCreateGart(
  766. IN PAGPCPQ_EXTENSION AgpContext,
  767. IN ULONG MinimumPages
  768. )
  769. /*******************************************************************************
  770. *
  771. * Routine Functional Description:
  772. *
  773. * Allocates and initializes an empty GART. The current implementation
  774. * attempts to allocate the entire GART on the first reserve.
  775. *
  776. * Arguments:
  777. *
  778. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  779. *
  780. * MinimumPages -- Supplies the minimum size (in pages) of the GART to be
  781. * created.
  782. *
  783. * Return Value:
  784. *
  785. * NTSTATUS
  786. *
  787. *******************************************************************************/
  788. {
  789. PGART_PTE Gart;
  790. ULONG* Dir;
  791. PHYSICAL_ADDRESS LowestAcceptable;
  792. PHYSICAL_ADDRESS BoundaryMultiple;
  793. PHYSICAL_ADDRESS HighestAcceptable;
  794. PHYSICAL_ADDRESS GartPhysical, DirPhysical, GartPointer, GartPagePhysical;
  795. ULONG Index;
  796. ULONG GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);;
  797. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQCreateGart entered.\n"));
  798. //
  799. // If the chipset requires two-level address translation, then allocate a not-necessarily-
  800. // contiguous GART, and create a Directory. Otherwise, allocate a contiguous GART.
  801. //
  802. if (AgpContext->MMIO->Capabilities.TwoLevelAddrTransSupported == 1){
  803. //
  804. // The chipset uses 2-level GART address translation.
  805. // Allocate the (not-necessarily-contiguous) GART.
  806. //
  807. Gart = AgpLibAllocateMappedPhysicalMemory(AgpContext, GartLength);
  808. if (Gart == NULL)
  809. {
  810. AGPLOG(AGP_CRITICAL,
  811. ("AgpCPQCreateGart - MmAllocateNonCachedMemory, for %lx bytes, failed\n",
  812. PAGE_SIZE));
  813. return(STATUS_INSUFFICIENT_RESOURCES);
  814. }
  815. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  816. //
  817. // Now allocate a GART Directory. The directory needs to be
  818. // below the 4GB boundary.
  819. //
  820. HighestAcceptable.QuadPart = 0xffffffff;
  821. LowestAcceptable.QuadPart = 0;
  822. BoundaryMultiple.QuadPart = 0;
  823. Dir = MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE,
  824. LowestAcceptable,
  825. HighestAcceptable,
  826. BoundaryMultiple,
  827. MmNonCached);
  828. if (Dir == NULL)
  829. {
  830. AGPLOG(AGP_CRITICAL,
  831. ("AgpCPQCreateGart - MmAllocateContiguousMemory %lx failed\n",
  832. PAGE_SIZE));
  833. return(STATUS_INSUFFICIENT_RESOURCES);
  834. }
  835. ASSERT(((ULONG_PTR)Dir & (PAGE_SIZE-1)) == 0);
  836. DirPhysical = MmGetPhysicalAddress(Dir);
  837. //
  838. // Walk the Directory, and assign to each Directory entry the value
  839. // of the physical address of the corresponding GART page.
  840. //
  841. ASSERT(GartLength/PAGE_SIZE <= PAGE_SIZE/sizeof(ULONG));
  842. for (Index=0; Index<(GartLength/PAGE_SIZE); Index++)
  843. {
  844. ULONG HighPart;
  845. ULONG Temp;
  846. GartPagePhysical = MmGetPhysicalAddress( &(Gart[Index*PAGE_SIZE/sizeof(GART_PTE)]));
  847. //
  848. // Format of a directory entry is
  849. // 31 12 11 10 9 8 7 2 1 0 <- bits
  850. // ------------------------------------------------------
  851. // | [31:12] | [32] | [33] | [34] | [35] | | L | V | <- Data
  852. // ------------------------------------------------------
  853. //
  854. // Where:-
  855. // 31-12 are bits 31 thru 12 of the physical address, ie
  856. // the page number if the page is below 4GB.
  857. // 32, 33, 34 and 35 are the respective bits of the physical
  858. // address if the address is above 4GB.
  859. // L Link.
  860. // V Valid.
  861. //
  862. ASSERT((GartPagePhysical.HighPart & ~0xf) == 0);
  863. HighPart = GartPagePhysical.HighPart & 0xf;
  864. Temp = (HighPart & 1) << 11;// bit 32 -> bit 11
  865. Temp |= (HighPart & 2) << 9 ;// bit 33 -> bit 10
  866. Temp |= (HighPart & 4) << 7 ;// bit 34 -> bit 9
  867. Temp |= (HighPart & 8) << 5 ;// bit 35 -> bit 8
  868. Dir[Index] = GartPagePhysical.LowPart | Temp;
  869. }
  870. } else {
  871. //
  872. // The chipset uses single level address translation.
  873. // Allocate the contiguous GART.
  874. //
  875. //
  876. // Try and get a chunk of contiguous memory big enough to map the
  877. // entire aperture.
  878. //
  879. HighestAcceptable.QuadPart = 0xFFFFFFFF;
  880. LowestAcceptable.QuadPart = 0;
  881. BoundaryMultiple.QuadPart = 0;
  882. Gart = MmAllocateContiguousMemorySpecifyCache(GartLength,
  883. LowestAcceptable,
  884. HighestAcceptable,
  885. BoundaryMultiple,
  886. MmNonCached);
  887. if (Gart == NULL)
  888. {
  889. AGPLOG(AGP_CRITICAL,
  890. ("AgpCPQCreateGart - MmAllocateContiguousMemory %lx failed\n",
  891. GartLength));
  892. return(STATUS_INSUFFICIENT_RESOURCES);
  893. }
  894. //
  895. // We successfully allocated a contiguous chunk of memory.
  896. // It should be page aligned already.
  897. //
  898. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  899. //
  900. // Get the physical address.
  901. //
  902. GartPhysical = MmGetPhysicalAddress(Gart);
  903. AGPLOG(AGP_NOISE,
  904. ("AgpCPQCreateGart - GART of length %lx created at VA %08lx, PA %08lx\n",
  905. GartLength,
  906. Gart,
  907. GartPhysical.LowPart));
  908. ASSERT(GartPhysical.HighPart == 0);
  909. ASSERT((GartPhysical.LowPart & (PAGE_SIZE-1)) == 0);
  910. }
  911. //
  912. // Initialize all the GART PTEs to free
  913. //
  914. for (Index=0; Index<GartLength/sizeof(GART_PTE); Index++)
  915. {
  916. Gart[Index].Soft.State = GART_ENTRY_FREE;
  917. }
  918. //
  919. // Update our extension to reflect the current state.
  920. //
  921. AgpContext->Gart = Gart;
  922. AgpContext->GartLength = GartLength;
  923. if (AgpContext->MMIO->Capabilities.TwoLevelAddrTransSupported == 1) {
  924. AgpContext->Dir = Dir;
  925. GartPointer=DirPhysical;
  926. } else {
  927. AgpContext->Dir = NULL;
  928. GartPointer=GartPhysical;
  929. }
  930. //
  931. // Stash GartPointer for resuming from s3 or s4
  932. //
  933. AgpContext->GartPointer = GartPointer.LowPart;
  934. //
  935. // Tell the chipset where the GART base is.
  936. //
  937. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  938. AgpContext->MMIO->GartBase.Page = (GartPointer.LowPart >> PAGE_SHIFT);
  939. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  940. return(STATUS_SUCCESS);
  941. }
  942. PGART_PTE
  943. AgpCPQFindRangeInGart(
  944. IN PGART_PTE StartPte,
  945. IN PGART_PTE EndPte,
  946. IN ULONG Length,
  947. IN BOOLEAN SearchBackward,
  948. IN ULONG SearchState
  949. )
  950. /*++
  951. Routine Description:
  952. Finds a contiguous range in the GART. This routine can
  953. search either from the beginning of the GART forwards or
  954. the end of the GART backwards.
  955. Arguments:
  956. StartIndex - Supplies the first GART pte to search
  957. EndPte - Supplies the last GART to search (inclusive)
  958. Length - Supplies the number of contiguous free entries
  959. to search for.
  960. SearchBackward - TRUE indicates that the search should begin
  961. at EndPte and search backwards. FALSE indicates that the
  962. search should begin at StartPte and search forwards
  963. SearchState - Supplies the PTE state to look for.
  964. Return Value:
  965. Pointer to the first PTE in the GART if a suitable range
  966. is found.
  967. NULL if no suitable range exists.
  968. --*/
  969. {
  970. PGART_PTE Current;
  971. PGART_PTE Last;
  972. LONG Delta;
  973. ULONG Found;
  974. PGART_PTE Candidate;
  975. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQFindRangeInGart entered.\n"));
  976. ASSERT(EndPte >= StartPte);
  977. ASSERT(Length <= (ULONG)(EndPte - StartPte + 1));
  978. ASSERT(Length != 0);
  979. if (SearchBackward) {
  980. Current = EndPte;
  981. Last = StartPte-1;
  982. Delta = -1;
  983. } else {
  984. Current = StartPte;
  985. Last = EndPte+1;
  986. Delta = 1;
  987. }
  988. Found = 0;
  989. while (Current != Last) {
  990. if (Current->Soft.State == SearchState) {
  991. if (++Found == Length) {
  992. //
  993. // A suitable range was found, return it
  994. //
  995. if (SearchBackward) {
  996. return(Current);
  997. } else {
  998. return(Current - Length + 1);
  999. }
  1000. }
  1001. } else {
  1002. Found = 0;
  1003. }
  1004. Current += Delta;
  1005. }
  1006. //
  1007. // A suitable range was not found.
  1008. //
  1009. return(NULL);
  1010. }
  1011. VOID
  1012. AgpCPQMaintainGARTCacheCoherency(
  1013. IN PAGPCPQ_EXTENSION AgpContext,
  1014. IN PHYSICAL_ADDRESS MemoryBase,
  1015. IN ULONG NumberOfEntries,
  1016. IN BOOLEAN InvalidateAll
  1017. )
  1018. /*******************************************************************************
  1019. *
  1020. * Routine Functional Description:
  1021. *
  1022. * Invalidates the entire GART [&DIR] Cache, or individual Entries in the GART
  1023. * cache, depending on which would provide better overall performance.
  1024. *
  1025. * Arguments:
  1026. *
  1027. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  1028. *
  1029. * MemoryBase -- Supplies the 'physical' address, in the AGP aperture,
  1030. * corresponding to the first GART Entry to flush
  1031. * from the GART Entry Cache.
  1032. *
  1033. * NumberOfEntries -- Supplies the number of Cached Entries which need to be
  1034. * invalidated.
  1035. *
  1036. * InvalidateAll -- Supplies a flag that, if TRUE, indicates that this routine
  1037. * should invalidate the entire GART [&DIR] cache, rather than the individual
  1038. * Cached Entries. If FALSE, then this routine decides how best to do it.
  1039. *
  1040. * Return Value:
  1041. *
  1042. * None
  1043. *
  1044. *******************************************************************************/
  1045. {
  1046. ULONG PolledValue, AperturePage, Index, Retry;
  1047. GART_CACHE_ENTRY_CONTROL CacheEntryControlValue;
  1048. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQMaintainGARTCacheCoherency entered.\n"));
  1049. if (InvalidateAll || (NumberOfEntries > MAX_CACHED_ENTRIES_TO_INVALIDATE)) {
  1050. //
  1051. // Invalidate the entire GART [&DIR] Cache
  1052. //
  1053. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  1054. AgpContext->MMIO->CacheControl.GartAndDirCacheInvalidate = 1;
  1055. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  1056. for (Retry = 2000; Retry; Retry--) {
  1057. PolledValue =
  1058. AgpContext->MMIO->CacheControl.GartAndDirCacheInvalidate;
  1059. if (PolledValue == 0) {
  1060. break;
  1061. }
  1062. }
  1063. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  1064. } else {
  1065. //
  1066. // Invalidate the individual cached GART enties
  1067. //
  1068. AperturePage = MemoryBase.LowPart >> PAGE_SHIFT;
  1069. for (Index=0; Index<NumberOfEntries; Index++, AperturePage++) {
  1070. CacheEntryControlValue.AsBits.GartEntryInvalidate = 1;
  1071. CacheEntryControlValue.AsBits.GartEntryOffset = AperturePage;
  1072. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  1073. AgpContext->MMIO->CacheEntryControl.AsDword =
  1074. CacheEntryControlValue.AsDword;
  1075. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  1076. for (Retry = 1000; Retry; Retry--) {
  1077. PolledValue =
  1078. AgpContext->MMIO->CacheEntryControl.AsBits.GartEntryInvalidate;
  1079. if (PolledValue == 0) {
  1080. break;
  1081. }
  1082. }
  1083. ASSERT(PolledValue == 0);
  1084. }
  1085. }
  1086. return;
  1087. }
  1088. PIO_RESOURCE_LIST
  1089. AgpCPQGetApSizeRequirements(
  1090. ULONG MaxSize,
  1091. ULONG Count
  1092. )
  1093. /*******************************************************************************
  1094. *
  1095. * Routine Functional Description:
  1096. *
  1097. * Creates and fills in an IO_RESOURCE_LIST structure, which describes
  1098. * the possible aperture sizes supported by the chipset.
  1099. *
  1100. * Arguments:
  1101. *
  1102. * MaxSize -- The Maximum possible size, in Bytes, for the aperture
  1103. *
  1104. * Count -- The number of different aperture sizes. This routine assumes
  1105. * that the aperture size is a multiple of two
  1106. * times the smallest aperture size. For example, 256MB, 128MB, 64MB
  1107. * 32MB. MaxSize would be 256M, and count would be 4.
  1108. *
  1109. * Return Value:
  1110. *
  1111. * Pointer to the newly created IO_RESOURCE_LIST.
  1112. *
  1113. *******************************************************************************/
  1114. {
  1115. PVOID RequirementsPointer;
  1116. PIO_RESOURCE_LIST Requirements;
  1117. ULONG Length, Index;
  1118. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQGetApSizeRequirements entered.\n"));
  1119. RequirementsPointer = ExAllocatePoolWithTag(PagedPool, sizeof(IO_RESOURCE_LIST) +
  1120. (Count-1)*sizeof(IO_RESOURCE_DESCRIPTOR), 'RpgA');
  1121. if (RequirementsPointer == NULL) {
  1122. AGPLOG(AGP_NOISE,
  1123. ("AgpAgpCPQGetApSizeRequirements - Failed to Allocate memory for a Resource Descriptor.\n"));
  1124. return(NULL);
  1125. } else {
  1126. Requirements = (PIO_RESOURCE_LIST)RequirementsPointer;
  1127. }
  1128. //
  1129. // Compaq supports several different aperture sizes, all must be
  1130. // naturally aligned. Start with the largest aperture and
  1131. // work downwards so that we get the biggest possible aperture.
  1132. //
  1133. Requirements->Version = Requirements->Revision = 1;
  1134. Requirements->Count = Count;
  1135. Length = MaxSize;
  1136. for (Index=0; Index < Count; Index++)
  1137. {
  1138. Requirements->Descriptors[Index].Option = IO_RESOURCE_ALTERNATIVE;
  1139. Requirements->Descriptors[Index].Type = CmResourceTypeMemory;
  1140. Requirements->Descriptors[Index].ShareDisposition = CmResourceShareDeviceExclusive;
  1141. Requirements->Descriptors[Index].Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_PREFETCHABLE;
  1142. Requirements->Descriptors[Index].u.Memory.Length = Length;
  1143. Requirements->Descriptors[Index].u.Memory.Alignment = Length;
  1144. Requirements->Descriptors[Index].u.Memory.MinimumAddress.QuadPart = 0;
  1145. Requirements->Descriptors[Index].u.Memory.MaximumAddress.QuadPart = (ULONG)-1;
  1146. Length = Length/2;
  1147. }
  1148. return(Requirements);
  1149. }
  1150. NTSTATUS
  1151. AgpCPQSetApSizeInChipset
  1152. (
  1153. IN UCHAR NewSetApSize,
  1154. IN UCHAR NewSetAgpValid
  1155. )
  1156. /*******************************************************************************
  1157. *
  1158. * Routine Functional Description:
  1159. *
  1160. * Modifes the Device Address Space (Aperture) Size register in the chipset's
  1161. * PCI-PCI bridge.
  1162. *
  1163. * Arguments:
  1164. *
  1165. * NewSetApSize -- The value to set in bits 3:1 of the DAS_SIZE register.
  1166. * NewSetAgpValid -- Value to set in bit 0 of the DAS_SIZE register.
  1167. *
  1168. * Return Value:
  1169. *
  1170. * NT Status value.
  1171. *
  1172. *******************************************************************************/
  1173. {
  1174. NTSTATUS Status = STATUS_SUCCESS;
  1175. UCHAR ApSizeRegisterOffset;
  1176. BUS_SLOT_ID CpqP2PBusSlotID;
  1177. AGP_AP_SIZE_REG ApSizeRegister;
  1178. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQSetApSizeInChipset entered.\n"));
  1179. ApSizeRegisterOffset = OFFSET_AP_SIZE;
  1180. CpqP2PBusSlotID.BusId = AGP_CPQ_BUS_ID;
  1181. CpqP2PBusSlotID.SlotId = AGP_CPQ_PCIPCI_SLOT_ID;
  1182. ApSizeRegister.AsBits.ApSize = NewSetApSize;
  1183. ApSizeRegister.AsBits.AgpValid = NewSetAgpValid;
  1184. Status = ApGetSetBusData(&CpqP2PBusSlotID, FALSE, &ApSizeRegister.AsByte,
  1185. ApSizeRegisterOffset, sizeof(UCHAR));
  1186. return(Status);
  1187. }
  1188. NTSTATUS
  1189. AgpCPQSetApBaseInChipset
  1190. (
  1191. IN PHYSICAL_ADDRESS NewBase
  1192. )
  1193. {
  1194. ULONG ApBase;
  1195. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQSetApBaseInChipset entered.\n"));
  1196. //
  1197. // Write the value of the aperture base in BAR0.
  1198. //
  1199. ApBase = NewBase.LowPart & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1200. WriteCPQConfig(&ApBase, OFFSET_BAR0, sizeof(ApBase));
  1201. #if DBG
  1202. //
  1203. // Read back what we wrote, make sure it worked
  1204. //
  1205. {
  1206. ULONG DbgBase;
  1207. ReadCPQConfig(&DbgBase, OFFSET_BAR0, sizeof(ApBase));
  1208. ASSERT((DbgBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK) == ApBase);
  1209. }
  1210. #endif
  1211. return(STATUS_SUCCESS);
  1212. }
  1213. VOID
  1214. AgpFindFreeRun(
  1215. IN PVOID AgpContext,
  1216. IN PAGP_RANGE AgpRange,
  1217. IN ULONG NumberOfPages,
  1218. IN ULONG OffsetInPages,
  1219. OUT ULONG *FreePages,
  1220. OUT ULONG *FreeOffset
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Finds the first contiguous run of free pages in the specified
  1225. part of the reserved range.
  1226. Arguments:
  1227. AgpContext - Supplies the AGP context
  1228. AgpRange - Supplies the AGP range
  1229. NumberOfPages - Supplies the size of the region to be searched for free pages
  1230. OffsetInPages - Supplies the start of the region to be searched for free pages
  1231. FreePages - Returns the length of the first contiguous run of free pages
  1232. FreeOffset - Returns the start of the first contiguous run of free pages
  1233. Return Value:
  1234. None. FreePages == 0 if there are no free pages in the specified range.
  1235. --*/
  1236. {
  1237. PGART_PTE Pte;
  1238. ULONG i;
  1239. AGPLOG(AGP_NOISE, ("AgpCpq: AgpFindFreeRun entered.\n"));
  1240. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  1241. //
  1242. // Find the first free PTE
  1243. //
  1244. for (i=0; i<NumberOfPages; i++) {
  1245. if (Pte[i].Hard.Valid == 0) {
  1246. //
  1247. // Found a free PTE, count the contiguous ones.
  1248. //
  1249. *FreeOffset = i + OffsetInPages;
  1250. *FreePages = 0;
  1251. while ((i<NumberOfPages) && (Pte[i].Hard.Valid == 0)) {
  1252. *FreePages += 1;
  1253. ++i;
  1254. }
  1255. return;
  1256. }
  1257. }
  1258. //
  1259. // No free PTEs in the specified range
  1260. //
  1261. *FreePages = 0;
  1262. return;
  1263. }
  1264. VOID
  1265. AgpGetMappedPages(
  1266. IN PVOID AgpContext,
  1267. IN PAGP_RANGE AgpRange,
  1268. IN ULONG NumberOfPages,
  1269. IN ULONG OffsetInPages,
  1270. OUT PMDL Mdl
  1271. )
  1272. /*++
  1273. Routine Description:
  1274. Returns the list of physical pages mapped into the specified
  1275. range in the GART.
  1276. Arguments:
  1277. AgpContext - Supplies the AGP context
  1278. AgpRange - Supplies the AGP range
  1279. NumberOfPages - Supplies the number of pages to be returned
  1280. OffsetInPages - Supplies the start of the region
  1281. Mdl - Returns the list of physical pages mapped in the specified range.
  1282. Return Value:
  1283. None
  1284. --*/
  1285. {
  1286. PGART_PTE Pte;
  1287. ULONG i;
  1288. PULONG Pages;
  1289. AGPLOG(AGP_NOISE, ("AgpCpq: AgpGetMappedPages entered.\n"));
  1290. ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
  1291. Pages = (PULONG)(Mdl + 1);
  1292. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  1293. for (i=0; i<NumberOfPages; i++) {
  1294. ASSERT(Pte[i].Hard.Valid == 1);
  1295. Pages[i] = Pte[i].Hard.Page;
  1296. }
  1297. return;
  1298. }
  1299. NTSTATUS
  1300. AgpSpecialTarget(
  1301. IN PAGPCPQ_EXTENSION AgpContext,
  1302. IN ULONGLONG DeviceFlags
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This routine makes "special" tweaks to the AGP chipset
  1307. Arguments:
  1308. AgpContext - Supplies the AGP context
  1309. DeviceFlags - Flags indicating what tweaks to perform
  1310. Return Value:
  1311. STATUS_SUCCESS, or error
  1312. --*/
  1313. {
  1314. NTSTATUS Status;
  1315. //
  1316. // Should we change the AGP rate?
  1317. //
  1318. if (DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) {
  1319. Status = AgpCPQSetRate(AgpContext,
  1320. (ULONG)((DeviceFlags & AGP_FLAG_SPECIAL_RESERVE)
  1321. >> AGP_FLAG_SET_RATE_SHIFT));
  1322. if (!NT_SUCCESS(Status)) {
  1323. return Status;
  1324. }
  1325. }
  1326. //
  1327. // Add more tweaks here...
  1328. //
  1329. AgpContext->SpecialTarget |=DeviceFlags;
  1330. return STATUS_SUCCESS;
  1331. }
  1332. NTSTATUS
  1333. AgpCPQSetRate(
  1334. IN PAGPCPQ_EXTENSION AgpContext,
  1335. IN ULONG AgpRate
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. This routine sets the AGP rate
  1340. Arguments:
  1341. AgpContext - Supplies the AGP context
  1342. AgpRate - Rate to set
  1343. note: this routine assumes that AGP has already been enabled, and that
  1344. whatever rate we've been asked to set is supported by master
  1345. Return Value:
  1346. STATUS_SUCCESS, or error status
  1347. --*/
  1348. {
  1349. NTSTATUS Status;
  1350. ULONG TargetEnable;
  1351. ULONG MasterEnable;
  1352. PCI_AGP_CAPABILITY TargetCap;
  1353. PCI_AGP_CAPABILITY MasterCap;
  1354. BOOLEAN ReverseInit;
  1355. //
  1356. // Read capabilities
  1357. //
  1358. Status = AgpLibGetPciDeviceCapability(0, 0, &TargetCap);
  1359. if (!NT_SUCCESS(Status)) {
  1360. AGPLOG(AGP_WARNING, ("AgpCpqSetRate: AgpLibGetPciDeviceCapability "
  1361. "failed %08lx\n", Status));
  1362. return Status;
  1363. }
  1364. Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
  1365. if (!NT_SUCCESS(Status)) {
  1366. AGPLOG(AGP_WARNING, ("AgpCpqSetRate: AgpLibGetMasterCapability "
  1367. "failed %08lx\n", Status));
  1368. return Status;
  1369. }
  1370. //
  1371. // Verify the requested rate is supported by both master and target
  1372. //
  1373. if (!(AgpRate & TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate)) {
  1374. return STATUS_INVALID_PARAMETER;
  1375. }
  1376. //
  1377. // Disable AGP while the pull the rug out from underneath
  1378. //
  1379. TargetEnable = TargetCap.AGPCommand.AGPEnable;
  1380. TargetCap.AGPCommand.AGPEnable = 0;
  1381. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1382. if (!NT_SUCCESS(Status)) {
  1383. AGPLOG(AGP_WARNING,
  1384. ("AgpCpqSetRate: AgpLibSetPciDeviceCapability %08lx for "
  1385. "Target failed %08lx\n",
  1386. &TargetCap,
  1387. Status));
  1388. return Status;
  1389. }
  1390. MasterEnable = MasterCap.AGPCommand.AGPEnable;
  1391. MasterCap.AGPCommand.AGPEnable = 0;
  1392. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1393. if (!NT_SUCCESS(Status)) {
  1394. AGPLOG(AGP_WARNING,
  1395. ("AgpCpqSetRate: AgpLibSetMasterCapability %08lx failed "
  1396. "%08lx\n",
  1397. &MasterCap,
  1398. Status));
  1399. return Status;
  1400. }
  1401. //
  1402. // Fire up AGP with new rate
  1403. //
  1404. ReverseInit =
  1405. (AgpContext->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) ==
  1406. AGP_FLAG_REVERSE_INITIALIZATION;
  1407. if (ReverseInit) {
  1408. MasterCap.AGPCommand.Rate = AgpRate;
  1409. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1410. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1411. if (!NT_SUCCESS(Status)) {
  1412. AGPLOG(AGP_WARNING,
  1413. ("AgpCpqSetRate: AgpLibSetMasterCapability %08lx failed "
  1414. "%08lx\n",
  1415. &MasterCap,
  1416. Status));
  1417. }
  1418. }
  1419. TargetCap.AGPCommand.Rate = AgpRate;
  1420. TargetCap.AGPCommand.AGPEnable = TargetEnable;
  1421. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1422. if (!NT_SUCCESS(Status)) {
  1423. AGPLOG(AGP_WARNING,
  1424. ("AgpCpqSetRate: AgpLibSetPciDeviceCapability %08lx for "
  1425. "Target failed %08lx\n",
  1426. &TargetCap,
  1427. Status));
  1428. return Status;
  1429. }
  1430. if (!ReverseInit) {
  1431. MasterCap.AGPCommand.Rate = AgpRate;
  1432. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1433. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1434. if (!NT_SUCCESS(Status)) {
  1435. AGPLOG(AGP_WARNING,
  1436. ("AgpCpqSetRate: AgpLibSetMasterCapability %08lx failed "
  1437. "%08lx\n",
  1438. &MasterCap,
  1439. Status));
  1440. }
  1441. }
  1442. return Status;
  1443. }