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.

1767 lines
54 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. //
  386. // Two level translation...
  387. //
  388. if (AgpContext->MMIO->Capabilities.TwoLevelAddrTransSupported == 1) {
  389. AgpLibFreeMappedPhysicalMemory(AgpContext->Gart,
  390. AgpContext->GartLength);
  391. //
  392. // Free the directory base allocation
  393. //
  394. if (AgpContext->Dir != NULL) {
  395. MmFreeContiguousMemory(AgpContext->Dir);
  396. AgpContext->Dir = NULL;
  397. }
  398. } else {
  399. MmFreeContiguousMemory(AgpContext->Gart);
  400. }
  401. AgpContext->Gart = NULL;
  402. AgpContext->GartLength = 0;
  403. }
  404. }
  405. NTSTATUS
  406. AgpReserveMemory(
  407. IN PAGPCPQ_EXTENSION AgpContext,
  408. IN OUT AGP_RANGE *Range
  409. )
  410. /*******************************************************************************
  411. *
  412. * Routine Functional Description:
  413. *
  414. * Reserves a range of memory in the GART.
  415. *
  416. * Arguments:
  417. *
  418. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  419. *
  420. * Range -- Supplies the AGP_RANGE structure. AGPLIB will have filled in
  421. * NumberOfPages and Type. This routine will fill in MemoryBase
  422. * and Context.
  423. *
  424. * Return Value:
  425. *
  426. * NTSTATUS
  427. *
  428. *******************************************************************************/
  429. {
  430. ULONG Index;
  431. ULONG NewState;
  432. NTSTATUS Status;
  433. PGART_PTE FoundRange;
  434. BOOLEAN Backwards;
  435. ASSERT((Range->Type == MmNonCached) || (Range->Type == MmWriteCombined));
  436. ASSERT(Range->NumberOfPages <= (AgpContext->ApertureLength / PAGE_SIZE));
  437. AGPLOG(AGP_NOISE, ("AgpCpq: AgpReserveMemory entered.\n"));
  438. //
  439. // If we have not allocated our GART yet, now is the time to do so
  440. //
  441. if (AgpContext->Gart == NULL) {
  442. ASSERT(AgpContext->GartLength == 0);
  443. Status = AgpCPQCreateGart(AgpContext, Range->NumberOfPages);
  444. if (!NT_SUCCESS(Status)) {
  445. AGPLOG(AGP_CRITICAL,
  446. ("AgpCPQCreateGart failed %08lx to create GART of size %lx\n",
  447. Status,
  448. AgpContext->ApertureLength/PAGE_SIZE));
  449. return(Status);
  450. }
  451. }
  452. ASSERT(AgpContext->GartLength != 0);
  453. //
  454. // Now that we have a GART, try and find enough contiguous entries
  455. // to satisfy the request. Requests for uncached memory will scan
  456. // from high addresses to low addresses. Requests for write-combined
  457. // memory will scan from low addresses to high addresses. We will
  458. // use a first-fit algorithm to try and keep the allocations
  459. // packed and contiguous.
  460. //
  461. Backwards = (Range->Type == MmNonCached) ? TRUE : FALSE;
  462. FoundRange = AgpCPQFindRangeInGart(&AgpContext->Gart[0],
  463. &AgpContext->Gart[(AgpContext->GartLength / sizeof(GART_PTE)) - 1],
  464. Range->NumberOfPages, Backwards, GART_ENTRY_FREE);
  465. if (FoundRange == NULL) {
  466. //
  467. // A big enough chunk was not found.
  468. //
  469. AGPLOG(AGP_CRITICAL,
  470. ("AgpReserveMemory - Could not find %d contiguous free pages of type %d in GART at %08lx\n",
  471. Range->NumberOfPages,
  472. Range->Type,
  473. AgpContext->Gart));
  474. //
  475. // This is where we could try and grow the GART
  476. //
  477. return(STATUS_INSUFFICIENT_RESOURCES);
  478. }
  479. AGPLOG(AGP_NOISE,
  480. ("AgpReserveMemory - reserved %d pages at GART PTE %08lx\n",
  481. Range->NumberOfPages,
  482. FoundRange));
  483. //
  484. // Set these pages to reserved
  485. //
  486. if (Range->Type == MmNonCached) {
  487. NewState = GART_ENTRY_RESERVED_UC;
  488. } else {
  489. NewState = GART_ENTRY_RESERVED_WC;
  490. }
  491. for (Index = 0; Index < Range->NumberOfPages; Index++) {
  492. ASSERT(FoundRange[Index].Soft.State == GART_ENTRY_FREE);
  493. FoundRange[Index].AsUlong = 0;
  494. FoundRange[Index].Soft.State = NewState;
  495. }
  496. //
  497. // Return the values.
  498. //
  499. Range->MemoryBase.QuadPart = AgpContext->ApertureStart.QuadPart +
  500. (FoundRange - &AgpContext->Gart[0]) * PAGE_SIZE;
  501. Range->Context = FoundRange;
  502. ASSERT(Range->MemoryBase.HighPart == 0);
  503. AGPLOG(AGP_NOISE,
  504. ("AgpReserveMemory - reserved memory handle %lx at PA %08lx\n",
  505. FoundRange,
  506. Range->MemoryBase.LowPart));
  507. return(STATUS_SUCCESS);
  508. }
  509. NTSTATUS
  510. AgpReleaseMemory(
  511. IN PAGPCPQ_EXTENSION AgpContext,
  512. IN PAGP_RANGE Range
  513. )
  514. /*******************************************************************************
  515. *
  516. * Routine Functional Description:
  517. *
  518. * Releases memory previously reserved with AgpReserveMemory.
  519. *
  520. * Arguments:
  521. *
  522. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  523. *
  524. * Range -- Supplies the range to be released.
  525. *
  526. * Return Value:
  527. *
  528. * NTSTATUS
  529. *
  530. *******************************************************************************/
  531. {
  532. PGART_PTE Pte, LastPteWritten;
  533. ULONG Start, ReadBack, PolledValue, Retry;
  534. AGPLOG(AGP_NOISE, ("AgpCpq: AgpReleaseMemory entered.\n"));
  535. //
  536. // Go through and free all the PTEs. None of these should still
  537. // be valid at this point, nor should they be mapped.
  538. //
  539. LastPteWritten = NULL;
  540. for (Pte = Range->Context;
  541. Pte < (PGART_PTE)Range->Context + Range->NumberOfPages;
  542. Pte++)
  543. {
  544. ASSERT(Pte->Hard.Page == 0);
  545. if (Range->Type == MmNonCached) {
  546. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_UC);
  547. } else {
  548. ASSERT(Pte->Soft.State == GART_ENTRY_RESERVED_WC);
  549. }
  550. Pte->Soft.State = GART_ENTRY_FREE;
  551. LastPteWritten = Pte;
  552. }
  553. //
  554. // Invalidate the GART Cache appropriately.
  555. //
  556. AgpCPQMaintainGARTCacheCoherency(AgpContext,
  557. Range->MemoryBase,
  558. Range->NumberOfPages,
  559. FALSE );
  560. //
  561. // Flush the posted write buffers
  562. //
  563. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  564. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  565. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  566. if (LastPteWritten) {
  567. ReadBack = *(volatile ULONG *)&LastPteWritten->AsUlong;
  568. }
  569. for (Retry = 1000; Retry; Retry--) {
  570. PolledValue =
  571. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  572. if (PolledValue == 0) {
  573. break;
  574. }
  575. }
  576. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  577. Range->MemoryBase.QuadPart = 0;
  578. return(STATUS_SUCCESS);
  579. }
  580. NTSTATUS
  581. AgpMapMemory(
  582. IN PAGPCPQ_EXTENSION AgpContext,
  583. IN PAGP_RANGE Range,
  584. IN PMDL Mdl,
  585. IN ULONG OffsetInPages,
  586. OUT PHYSICAL_ADDRESS *MemoryBase
  587. )
  588. /*******************************************************************************
  589. *
  590. * Routine Functional Description:
  591. *
  592. * Maps physical memory into the AGP aperture, somewhere in the specified
  593. * range.
  594. *
  595. * Arguments:
  596. *
  597. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  598. *
  599. * Range -- Supplies the AGP range into which the memory should be mapped.
  600. *
  601. * Mdl -- Supplies the MDL describing the physical pages to be mapped.
  602. *
  603. * OffsetInPages - Supplies the offset into the reserved range where the
  604. * mapping should begin.
  605. *
  606. * MemoryBase -- Returns the 'physical' address in the aperture where the
  607. * pages were mapped.
  608. *
  609. * Return Value:
  610. *
  611. * NTSTATUS
  612. *
  613. *******************************************************************************/
  614. {
  615. ULONG PageCount;
  616. PGART_PTE Pte;
  617. PGART_PTE StartPte;
  618. ULONG Index;
  619. ULONG TargetState;
  620. PULONG Page;
  621. BOOLEAN Backwards;
  622. GART_PTE NewPte;
  623. ULONG PolledValue, Retry;
  624. AGPLOG(AGP_NOISE, ("AgpCpq: AgpMapMemory entered.\n"));
  625. ASSERT(Mdl->Next == NULL);
  626. StartPte = Range->Context;
  627. PageCount = BYTES_TO_PAGES(Mdl->ByteCount);
  628. ASSERT(PageCount <= Range->NumberOfPages);
  629. ASSERT(OffsetInPages <= Range->NumberOfPages);
  630. ASSERT(PageCount + OffsetInPages <= Range->NumberOfPages);
  631. ASSERT(PageCount > 0);
  632. TargetState = (Range->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC :
  633. GART_ENTRY_RESERVED_WC;
  634. Pte = StartPte + OffsetInPages;
  635. //
  636. // We have found a suitable spot to map the pages. Now map them.
  637. //
  638. ASSERT(Pte >= StartPte);
  639. ASSERT(Pte + PageCount <= StartPte + Range->NumberOfPages);
  640. NewPte.AsUlong = 0;
  641. NewPte.Soft.State = (Range->Type == MmNonCached) ? GART_ENTRY_VALID_UC :
  642. GART_ENTRY_VALID_WC;
  643. Page = (PULONG)(Mdl + 1);
  644. for (Index = 0; Index < PageCount; Index++)
  645. {
  646. ASSERT(Pte[Index].Soft.State == TargetState);
  647. NewPte.Hard.Page = *Page++;
  648. Pte[Index].AsUlong = NewPte.AsUlong;
  649. ASSERT(Pte[Index].Hard.Valid == 1);
  650. ASSERT(Pte[Index].Hard.Linked == 0);
  651. }
  652. //
  653. // If Linking is supported, then link the entries by setting the link bit
  654. // in all entries, except the last entry, in the mapped set.
  655. //
  656. if (AgpContext->MMIO->Capabilities.LinkingSupported) {
  657. ASSERT(AgpContext->MMIO->FeatureControl.LinkingEnable);
  658. for (Index = 0; Index < PageCount-1; Index++) {
  659. ASSERT(Pte[Index].Hard.Page != 0);
  660. Pte[Index].Hard.Linked = 1;
  661. }
  662. }
  663. //
  664. // We have filled in all the PTEs. Now flush the write buffers.
  665. //
  666. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  667. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  668. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  669. NewPte.AsUlong = *(volatile ULONG *)&Pte[PageCount-1].AsUlong;
  670. for (Retry = 1000; Retry; Retry--) {
  671. PolledValue =
  672. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  673. if (PolledValue == 0) {
  674. break;
  675. }
  676. }
  677. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  678. //
  679. // Return where they are mapped
  680. //
  681. MemoryBase->QuadPart = Range->MemoryBase.QuadPart + (Pte - StartPte) * PAGE_SIZE;
  682. return(STATUS_SUCCESS);
  683. }
  684. NTSTATUS
  685. AgpUnMapMemory(
  686. IN PAGPCPQ_EXTENSION AgpContext,
  687. IN PAGP_RANGE AgpRange,
  688. IN ULONG NumberOfPages,
  689. IN ULONG OffsetInPages
  690. )
  691. /*******************************************************************************
  692. *
  693. * Routine Functional Description:
  694. *
  695. * UnMaps all or part of the memory that was previously mapped by AgpMapMemory.
  696. *
  697. * Arguments:
  698. *
  699. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  700. *
  701. * AgpRange -- Supplies the AGP range out of which memory should be un-mapped.
  702. *
  703. * NumberOfPages -- Supplies the number of pages in the range to be un-mapped.
  704. *
  705. * OffsetInPages -- Supplies the offset into the Reserved Range where the un-mapping
  706. * should begin.
  707. *
  708. * Return Value:
  709. *
  710. * NTSTATUS
  711. *
  712. *******************************************************************************/
  713. {
  714. ULONG Index, TargetState, ReadBack, PolledValue, Retry;
  715. PGART_PTE ReservedBasePte;
  716. PGART_PTE Pte;
  717. PGART_PTE LastChangedPte=NULL;
  718. PHYSICAL_ADDRESS pa;
  719. AGPLOG(AGP_NOISE, ("AgpCpq: AgpUnMapMemory entered.\n"));
  720. ASSERT(OffsetInPages + NumberOfPages <= AgpRange->NumberOfPages);
  721. ReservedBasePte = AgpRange->Context;
  722. Pte = &ReservedBasePte[OffsetInPages];
  723. TargetState = (AgpRange->Type == MmNonCached) ? GART_ENTRY_RESERVED_UC : GART_ENTRY_RESERVED_WC;
  724. //
  725. // UnMap each entry by putting each Mapped Entry back into the 'Reserved State'
  726. //
  727. for (Index=0; Index < NumberOfPages; Index++) {
  728. if (Pte[Index].Hard.Valid) {
  729. ASSERT(Pte[Index].Hard.Page != 0);
  730. Pte[Index].Hard.Page = 0;
  731. Pte[Index].Soft.State = TargetState;
  732. LastChangedPte = &Pte[Index];
  733. } else {
  734. //
  735. // We are being asked to un-map a page that is not mapped.
  736. //
  737. ASSERT(Pte[Index].Hard.Page == 0);
  738. ASSERT(Pte[Index].Soft.State == TargetState);
  739. AGPLOG(AGP_NOISE,
  740. ("AgpUnMapMemory - PTE %08lx (%08lx) at offset %d not mapped\n",
  741. &Pte[Index],
  742. Pte[Index].AsUlong,
  743. Index));
  744. }
  745. }
  746. //
  747. // Maintain link bit coherency within this reserved range.
  748. //
  749. if (OffsetInPages != 0) {
  750. ASSERT(OffsetInPages >= 1);
  751. if (ReservedBasePte[OffsetInPages-1].Hard.Linked == 1) {
  752. ASSERT(ReservedBasePte[OffsetInPages-1].Hard.Valid == 1);
  753. ReservedBasePte[OffsetInPages-1].Hard.Linked = 0;
  754. }
  755. }
  756. //
  757. // Invalidate the Cache appropriately.
  758. //
  759. pa.HighPart = 0;
  760. pa.LowPart = AgpRange->MemoryBase.LowPart + OffsetInPages*PAGE_SIZE;
  761. AgpCPQMaintainGARTCacheCoherency(AgpContext, pa, NumberOfPages, FALSE);
  762. //
  763. // Flush the posted write buffers
  764. //
  765. if (LastChangedPte != NULL)
  766. {
  767. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  768. AgpContext->MMIO->PostedWriteBufferControl.Flush = 1;
  769. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  770. ReadBack = *((volatile ULONG *)&(LastChangedPte[0].AsUlong));
  771. for (Retry = 2000; Retry; Retry--) {
  772. PolledValue =
  773. AgpContext->MMIO->PostedWriteBufferControl.Flush;
  774. if (PolledValue == 0) {
  775. break;
  776. }
  777. }
  778. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  779. }
  780. return(STATUS_SUCCESS);
  781. }
  782. NTSTATUS
  783. AgpCPQCreateGart(
  784. IN PAGPCPQ_EXTENSION AgpContext,
  785. IN ULONG MinimumPages
  786. )
  787. /*******************************************************************************
  788. *
  789. * Routine Functional Description:
  790. *
  791. * Allocates and initializes an empty GART. The current implementation
  792. * attempts to allocate the entire GART on the first reserve.
  793. *
  794. * Arguments:
  795. *
  796. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  797. *
  798. * MinimumPages -- Supplies the minimum size (in pages) of the GART to be
  799. * created.
  800. *
  801. * Return Value:
  802. *
  803. * NTSTATUS
  804. *
  805. *******************************************************************************/
  806. {
  807. PGART_PTE Gart;
  808. ULONG* Dir;
  809. PHYSICAL_ADDRESS LowestAcceptable;
  810. PHYSICAL_ADDRESS BoundaryMultiple;
  811. PHYSICAL_ADDRESS HighestAcceptable;
  812. PHYSICAL_ADDRESS GartPhysical, DirPhysical, GartPointer, GartPagePhysical;
  813. ULONG Index;
  814. ULONG GartLength = BYTES_TO_PAGES(AgpContext->ApertureLength) * sizeof(GART_PTE);;
  815. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQCreateGart entered.\n"));
  816. //
  817. // If the chipset requires two-level address translation, then allocate a not-necessarily-
  818. // contiguous GART, and create a Directory. Otherwise, allocate a contiguous GART.
  819. //
  820. if (AgpContext->MMIO->Capabilities.TwoLevelAddrTransSupported == 1){
  821. //
  822. // The chipset uses 2-level GART address translation.
  823. // Allocate the (not-necessarily-contiguous) GART.
  824. //
  825. Gart = AgpLibAllocateMappedPhysicalMemory(AgpContext, GartLength);
  826. if (Gart == NULL)
  827. {
  828. AGPLOG(AGP_CRITICAL,
  829. ("AgpCPQCreateGart - MmAllocateNonCachedMemory, for %lx bytes, failed\n",
  830. PAGE_SIZE));
  831. return(STATUS_INSUFFICIENT_RESOURCES);
  832. }
  833. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  834. //
  835. // Now allocate a GART Directory. The directory needs to be
  836. // below the 4GB boundary.
  837. //
  838. HighestAcceptable.QuadPart = 0xffffffff;
  839. LowestAcceptable.QuadPart = 0;
  840. BoundaryMultiple.QuadPart = 0;
  841. Dir = MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE,
  842. LowestAcceptable,
  843. HighestAcceptable,
  844. BoundaryMultiple,
  845. MmNonCached);
  846. if (Dir == NULL)
  847. {
  848. AGPLOG(AGP_CRITICAL,
  849. ("AgpCPQCreateGart - MmAllocateContiguousMemory %lx failed\n",
  850. PAGE_SIZE));
  851. return(STATUS_INSUFFICIENT_RESOURCES);
  852. }
  853. ASSERT(((ULONG_PTR)Dir & (PAGE_SIZE-1)) == 0);
  854. DirPhysical = MmGetPhysicalAddress(Dir);
  855. //
  856. // Walk the Directory, and assign to each Directory entry the value
  857. // of the physical address of the corresponding GART page.
  858. //
  859. ASSERT(GartLength/PAGE_SIZE <= PAGE_SIZE/sizeof(ULONG));
  860. for (Index=0; Index<(GartLength/PAGE_SIZE); Index++)
  861. {
  862. ULONG HighPart;
  863. ULONG Temp;
  864. GartPagePhysical = MmGetPhysicalAddress( &(Gart[Index*PAGE_SIZE/sizeof(GART_PTE)]));
  865. //
  866. // Format of a directory entry is
  867. // 31 12 11 10 9 8 7 2 1 0 <- bits
  868. // ------------------------------------------------------
  869. // | [31:12] | [32] | [33] | [34] | [35] | | L | V | <- Data
  870. // ------------------------------------------------------
  871. //
  872. // Where:-
  873. // 31-12 are bits 31 thru 12 of the physical address, ie
  874. // the page number if the page is below 4GB.
  875. // 32, 33, 34 and 35 are the respective bits of the physical
  876. // address if the address is above 4GB.
  877. // L Link.
  878. // V Valid.
  879. //
  880. ASSERT((GartPagePhysical.HighPart & ~0xf) == 0);
  881. HighPart = GartPagePhysical.HighPart & 0xf;
  882. Temp = (HighPart & 1) << 11;// bit 32 -> bit 11
  883. Temp |= (HighPart & 2) << 9 ;// bit 33 -> bit 10
  884. Temp |= (HighPart & 4) << 7 ;// bit 34 -> bit 9
  885. Temp |= (HighPart & 8) << 5 ;// bit 35 -> bit 8
  886. Dir[Index] = GartPagePhysical.LowPart | Temp;
  887. }
  888. } else {
  889. //
  890. // The chipset uses single level address translation.
  891. // Allocate the contiguous GART.
  892. //
  893. //
  894. // Try and get a chunk of contiguous memory big enough to map the
  895. // entire aperture.
  896. //
  897. HighestAcceptable.QuadPart = 0xFFFFFFFF;
  898. LowestAcceptable.QuadPart = 0;
  899. BoundaryMultiple.QuadPart = 0;
  900. Gart = MmAllocateContiguousMemorySpecifyCache(GartLength,
  901. LowestAcceptable,
  902. HighestAcceptable,
  903. BoundaryMultiple,
  904. MmNonCached);
  905. if (Gart == NULL)
  906. {
  907. AGPLOG(AGP_CRITICAL,
  908. ("AgpCPQCreateGart - MmAllocateContiguousMemory %lx failed\n",
  909. GartLength));
  910. return(STATUS_INSUFFICIENT_RESOURCES);
  911. }
  912. //
  913. // We successfully allocated a contiguous chunk of memory.
  914. // It should be page aligned already.
  915. //
  916. ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE-1)) == 0);
  917. //
  918. // Get the physical address.
  919. //
  920. GartPhysical = MmGetPhysicalAddress(Gart);
  921. AGPLOG(AGP_NOISE,
  922. ("AgpCPQCreateGart - GART of length %lx created at VA %08lx, PA %08lx\n",
  923. GartLength,
  924. Gart,
  925. GartPhysical.LowPart));
  926. ASSERT(GartPhysical.HighPart == 0);
  927. ASSERT((GartPhysical.LowPart & (PAGE_SIZE-1)) == 0);
  928. }
  929. //
  930. // Initialize all the GART PTEs to free
  931. //
  932. for (Index=0; Index<GartLength/sizeof(GART_PTE); Index++)
  933. {
  934. Gart[Index].Soft.State = GART_ENTRY_FREE;
  935. }
  936. //
  937. // Update our extension to reflect the current state.
  938. //
  939. AgpContext->Gart = Gart;
  940. AgpContext->GartLength = GartLength;
  941. if (AgpContext->MMIO->Capabilities.TwoLevelAddrTransSupported == 1) {
  942. AgpContext->Dir = Dir;
  943. GartPointer=DirPhysical;
  944. } else {
  945. AgpContext->Dir = NULL;
  946. GartPointer=GartPhysical;
  947. }
  948. //
  949. // Stash GartPointer for resuming from s3 or s4
  950. //
  951. AgpContext->GartPointer = GartPointer.LowPart;
  952. //
  953. // Tell the chipset where the GART base is.
  954. //
  955. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  956. AgpContext->MMIO->GartBase.Page = (GartPointer.LowPart >> PAGE_SHIFT);
  957. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  958. return(STATUS_SUCCESS);
  959. }
  960. PGART_PTE
  961. AgpCPQFindRangeInGart(
  962. IN PGART_PTE StartPte,
  963. IN PGART_PTE EndPte,
  964. IN ULONG Length,
  965. IN BOOLEAN SearchBackward,
  966. IN ULONG SearchState
  967. )
  968. /*++
  969. Routine Description:
  970. Finds a contiguous range in the GART. This routine can
  971. search either from the beginning of the GART forwards or
  972. the end of the GART backwards.
  973. Arguments:
  974. StartIndex - Supplies the first GART pte to search
  975. EndPte - Supplies the last GART to search (inclusive)
  976. Length - Supplies the number of contiguous free entries
  977. to search for.
  978. SearchBackward - TRUE indicates that the search should begin
  979. at EndPte and search backwards. FALSE indicates that the
  980. search should begin at StartPte and search forwards
  981. SearchState - Supplies the PTE state to look for.
  982. Return Value:
  983. Pointer to the first PTE in the GART if a suitable range
  984. is found.
  985. NULL if no suitable range exists.
  986. --*/
  987. {
  988. PGART_PTE Current;
  989. PGART_PTE Last;
  990. LONG Delta;
  991. ULONG Found;
  992. PGART_PTE Candidate;
  993. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQFindRangeInGart entered.\n"));
  994. ASSERT(EndPte >= StartPte);
  995. ASSERT(Length <= (ULONG)(EndPte - StartPte + 1));
  996. ASSERT(Length != 0);
  997. if (SearchBackward) {
  998. Current = EndPte;
  999. Last = StartPte-1;
  1000. Delta = -1;
  1001. } else {
  1002. Current = StartPte;
  1003. Last = EndPte+1;
  1004. Delta = 1;
  1005. }
  1006. Found = 0;
  1007. while (Current != Last) {
  1008. if (Current->Soft.State == SearchState) {
  1009. if (++Found == Length) {
  1010. //
  1011. // A suitable range was found, return it
  1012. //
  1013. if (SearchBackward) {
  1014. return(Current);
  1015. } else {
  1016. return(Current - Length + 1);
  1017. }
  1018. }
  1019. } else {
  1020. Found = 0;
  1021. }
  1022. Current += Delta;
  1023. }
  1024. //
  1025. // A suitable range was not found.
  1026. //
  1027. return(NULL);
  1028. }
  1029. VOID
  1030. AgpCPQMaintainGARTCacheCoherency(
  1031. IN PAGPCPQ_EXTENSION AgpContext,
  1032. IN PHYSICAL_ADDRESS MemoryBase,
  1033. IN ULONG NumberOfEntries,
  1034. IN BOOLEAN InvalidateAll
  1035. )
  1036. /*******************************************************************************
  1037. *
  1038. * Routine Functional Description:
  1039. *
  1040. * Invalidates the entire GART [&DIR] Cache, or individual Entries in the GART
  1041. * cache, depending on which would provide better overall performance.
  1042. *
  1043. * Arguments:
  1044. *
  1045. * AgpContext -- Supplies the AGP Context, i.e. the AGP Extension.
  1046. *
  1047. * MemoryBase -- Supplies the 'physical' address, in the AGP aperture,
  1048. * corresponding to the first GART Entry to flush
  1049. * from the GART Entry Cache.
  1050. *
  1051. * NumberOfEntries -- Supplies the number of Cached Entries which need to be
  1052. * invalidated.
  1053. *
  1054. * InvalidateAll -- Supplies a flag that, if TRUE, indicates that this routine
  1055. * should invalidate the entire GART [&DIR] cache, rather than the individual
  1056. * Cached Entries. If FALSE, then this routine decides how best to do it.
  1057. *
  1058. * Return Value:
  1059. *
  1060. * None
  1061. *
  1062. *******************************************************************************/
  1063. {
  1064. ULONG PolledValue, AperturePage, Index, Retry;
  1065. GART_CACHE_ENTRY_CONTROL CacheEntryControlValue;
  1066. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQMaintainGARTCacheCoherency entered.\n"));
  1067. if (InvalidateAll || (NumberOfEntries > MAX_CACHED_ENTRIES_TO_INVALIDATE)) {
  1068. //
  1069. // Invalidate the entire GART [&DIR] Cache
  1070. //
  1071. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  1072. AgpContext->MMIO->CacheControl.GartAndDirCacheInvalidate = 1;
  1073. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  1074. for (Retry = 2000; Retry; Retry--) {
  1075. PolledValue =
  1076. AgpContext->MMIO->CacheControl.GartAndDirCacheInvalidate;
  1077. if (PolledValue == 0) {
  1078. break;
  1079. }
  1080. }
  1081. ASSERT(PolledValue == 0); // This bit should get reset by the chipset.
  1082. } else {
  1083. //
  1084. // Invalidate the individual cached GART enties
  1085. //
  1086. AperturePage = MemoryBase.LowPart >> PAGE_SHIFT;
  1087. for (Index=0; Index<NumberOfEntries; Index++, AperturePage++) {
  1088. CacheEntryControlValue.AsBits.GartEntryInvalidate = 1;
  1089. CacheEntryControlValue.AsBits.GartEntryOffset = AperturePage;
  1090. if (AgpContext->IsHPSA) DnbSetShadowBit(0);
  1091. AgpContext->MMIO->CacheEntryControl.AsDword =
  1092. CacheEntryControlValue.AsDword;
  1093. if (AgpContext->IsHPSA) DnbSetShadowBit(1);
  1094. for (Retry = 1000; Retry; Retry--) {
  1095. PolledValue =
  1096. AgpContext->MMIO->CacheEntryControl.AsBits.GartEntryInvalidate;
  1097. if (PolledValue == 0) {
  1098. break;
  1099. }
  1100. }
  1101. ASSERT(PolledValue == 0);
  1102. }
  1103. }
  1104. return;
  1105. }
  1106. PIO_RESOURCE_LIST
  1107. AgpCPQGetApSizeRequirements(
  1108. ULONG MaxSize,
  1109. ULONG Count
  1110. )
  1111. /*******************************************************************************
  1112. *
  1113. * Routine Functional Description:
  1114. *
  1115. * Creates and fills in an IO_RESOURCE_LIST structure, which describes
  1116. * the possible aperture sizes supported by the chipset.
  1117. *
  1118. * Arguments:
  1119. *
  1120. * MaxSize -- The Maximum possible size, in Bytes, for the aperture
  1121. *
  1122. * Count -- The number of different aperture sizes. This routine assumes
  1123. * that the aperture size is a multiple of two
  1124. * times the smallest aperture size. For example, 256MB, 128MB, 64MB
  1125. * 32MB. MaxSize would be 256M, and count would be 4.
  1126. *
  1127. * Return Value:
  1128. *
  1129. * Pointer to the newly created IO_RESOURCE_LIST.
  1130. *
  1131. *******************************************************************************/
  1132. {
  1133. PVOID RequirementsPointer;
  1134. PIO_RESOURCE_LIST Requirements;
  1135. ULONG Length, Index;
  1136. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQGetApSizeRequirements entered.\n"));
  1137. RequirementsPointer = ExAllocatePoolWithTag(PagedPool, sizeof(IO_RESOURCE_LIST) +
  1138. (Count-1)*sizeof(IO_RESOURCE_DESCRIPTOR), 'RpgA');
  1139. if (RequirementsPointer == NULL) {
  1140. AGPLOG(AGP_NOISE,
  1141. ("AgpAgpCPQGetApSizeRequirements - Failed to Allocate memory for a Resource Descriptor.\n"));
  1142. return(NULL);
  1143. } else {
  1144. Requirements = (PIO_RESOURCE_LIST)RequirementsPointer;
  1145. }
  1146. //
  1147. // Compaq supports several different aperture sizes, all must be
  1148. // naturally aligned. Start with the largest aperture and
  1149. // work downwards so that we get the biggest possible aperture.
  1150. //
  1151. Requirements->Version = Requirements->Revision = 1;
  1152. Requirements->Count = Count;
  1153. Length = MaxSize;
  1154. for (Index=0; Index < Count; Index++)
  1155. {
  1156. Requirements->Descriptors[Index].Option = IO_RESOURCE_ALTERNATIVE;
  1157. Requirements->Descriptors[Index].Type = CmResourceTypeMemory;
  1158. Requirements->Descriptors[Index].ShareDisposition = CmResourceShareDeviceExclusive;
  1159. Requirements->Descriptors[Index].Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_PREFETCHABLE;
  1160. Requirements->Descriptors[Index].u.Memory.Length = Length;
  1161. Requirements->Descriptors[Index].u.Memory.Alignment = Length;
  1162. Requirements->Descriptors[Index].u.Memory.MinimumAddress.QuadPart = 0;
  1163. Requirements->Descriptors[Index].u.Memory.MaximumAddress.QuadPart = (ULONG)-1;
  1164. Length = Length/2;
  1165. }
  1166. return(Requirements);
  1167. }
  1168. NTSTATUS
  1169. AgpCPQSetApSizeInChipset
  1170. (
  1171. IN UCHAR NewSetApSize,
  1172. IN UCHAR NewSetAgpValid
  1173. )
  1174. /*******************************************************************************
  1175. *
  1176. * Routine Functional Description:
  1177. *
  1178. * Modifes the Device Address Space (Aperture) Size register in the chipset's
  1179. * PCI-PCI bridge.
  1180. *
  1181. * Arguments:
  1182. *
  1183. * NewSetApSize -- The value to set in bits 3:1 of the DAS_SIZE register.
  1184. * NewSetAgpValid -- Value to set in bit 0 of the DAS_SIZE register.
  1185. *
  1186. * Return Value:
  1187. *
  1188. * NT Status value.
  1189. *
  1190. *******************************************************************************/
  1191. {
  1192. NTSTATUS Status = STATUS_SUCCESS;
  1193. UCHAR ApSizeRegisterOffset;
  1194. BUS_SLOT_ID CpqP2PBusSlotID;
  1195. AGP_AP_SIZE_REG ApSizeRegister;
  1196. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQSetApSizeInChipset entered.\n"));
  1197. ApSizeRegisterOffset = OFFSET_AP_SIZE;
  1198. CpqP2PBusSlotID.BusId = AGP_CPQ_BUS_ID;
  1199. CpqP2PBusSlotID.SlotId = AGP_CPQ_PCIPCI_SLOT_ID;
  1200. ApSizeRegister.AsBits.ApSize = NewSetApSize;
  1201. ApSizeRegister.AsBits.AgpValid = NewSetAgpValid;
  1202. Status = ApGetSetBusData(&CpqP2PBusSlotID, FALSE, &ApSizeRegister.AsByte,
  1203. ApSizeRegisterOffset, sizeof(UCHAR));
  1204. return(Status);
  1205. }
  1206. NTSTATUS
  1207. AgpCPQSetApBaseInChipset
  1208. (
  1209. IN PHYSICAL_ADDRESS NewBase
  1210. )
  1211. {
  1212. ULONG ApBase;
  1213. AGPLOG(AGP_NOISE, ("AgpCpq: AgpCPQSetApBaseInChipset entered.\n"));
  1214. //
  1215. // Write the value of the aperture base in BAR0.
  1216. //
  1217. ApBase = NewBase.LowPart & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1218. WriteCPQConfig(&ApBase, OFFSET_BAR0, sizeof(ApBase));
  1219. #if DBG
  1220. //
  1221. // Read back what we wrote, make sure it worked
  1222. //
  1223. {
  1224. ULONG DbgBase;
  1225. ReadCPQConfig(&DbgBase, OFFSET_BAR0, sizeof(ApBase));
  1226. ASSERT((DbgBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK) == ApBase);
  1227. }
  1228. #endif
  1229. return(STATUS_SUCCESS);
  1230. }
  1231. VOID
  1232. AgpFindFreeRun(
  1233. IN PVOID AgpContext,
  1234. IN PAGP_RANGE AgpRange,
  1235. IN ULONG NumberOfPages,
  1236. IN ULONG OffsetInPages,
  1237. OUT ULONG *FreePages,
  1238. OUT ULONG *FreeOffset
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Finds the first contiguous run of free pages in the specified
  1243. part of the reserved range.
  1244. Arguments:
  1245. AgpContext - Supplies the AGP context
  1246. AgpRange - Supplies the AGP range
  1247. NumberOfPages - Supplies the size of the region to be searched for free pages
  1248. OffsetInPages - Supplies the start of the region to be searched for free pages
  1249. FreePages - Returns the length of the first contiguous run of free pages
  1250. FreeOffset - Returns the start of the first contiguous run of free pages
  1251. Return Value:
  1252. None. FreePages == 0 if there are no free pages in the specified range.
  1253. --*/
  1254. {
  1255. PGART_PTE Pte;
  1256. ULONG i;
  1257. AGPLOG(AGP_NOISE, ("AgpCpq: AgpFindFreeRun entered.\n"));
  1258. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  1259. //
  1260. // Find the first free PTE
  1261. //
  1262. for (i=0; i<NumberOfPages; i++) {
  1263. if (Pte[i].Hard.Valid == 0) {
  1264. //
  1265. // Found a free PTE, count the contiguous ones.
  1266. //
  1267. *FreeOffset = i + OffsetInPages;
  1268. *FreePages = 0;
  1269. while ((i<NumberOfPages) && (Pte[i].Hard.Valid == 0)) {
  1270. *FreePages += 1;
  1271. ++i;
  1272. }
  1273. return;
  1274. }
  1275. }
  1276. //
  1277. // No free PTEs in the specified range
  1278. //
  1279. *FreePages = 0;
  1280. return;
  1281. }
  1282. VOID
  1283. AgpGetMappedPages(
  1284. IN PVOID AgpContext,
  1285. IN PAGP_RANGE AgpRange,
  1286. IN ULONG NumberOfPages,
  1287. IN ULONG OffsetInPages,
  1288. OUT PMDL Mdl
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. Returns the list of physical pages mapped into the specified
  1293. range in the GART.
  1294. Arguments:
  1295. AgpContext - Supplies the AGP context
  1296. AgpRange - Supplies the AGP range
  1297. NumberOfPages - Supplies the number of pages to be returned
  1298. OffsetInPages - Supplies the start of the region
  1299. Mdl - Returns the list of physical pages mapped in the specified range.
  1300. Return Value:
  1301. None
  1302. --*/
  1303. {
  1304. PGART_PTE Pte;
  1305. ULONG i;
  1306. PULONG Pages;
  1307. AGPLOG(AGP_NOISE, ("AgpCpq: AgpGetMappedPages entered.\n"));
  1308. ASSERT(NumberOfPages * PAGE_SIZE == Mdl->ByteCount);
  1309. Pages = (PULONG)(Mdl + 1);
  1310. Pte = (PGART_PTE)(AgpRange->Context) + OffsetInPages;
  1311. for (i=0; i<NumberOfPages; i++) {
  1312. ASSERT(Pte[i].Hard.Valid == 1);
  1313. Pages[i] = Pte[i].Hard.Page;
  1314. }
  1315. return;
  1316. }
  1317. NTSTATUS
  1318. AgpSpecialTarget(
  1319. IN PAGPCPQ_EXTENSION AgpContext,
  1320. IN ULONGLONG DeviceFlags
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. This routine makes "special" tweaks to the AGP chipset
  1325. Arguments:
  1326. AgpContext - Supplies the AGP context
  1327. DeviceFlags - Flags indicating what tweaks to perform
  1328. Return Value:
  1329. STATUS_SUCCESS, or error
  1330. --*/
  1331. {
  1332. NTSTATUS Status;
  1333. //
  1334. // Should we change the AGP rate?
  1335. //
  1336. if (DeviceFlags & AGP_FLAG_SPECIAL_RESERVE) {
  1337. Status = AgpCPQSetRate(AgpContext,
  1338. (ULONG)((DeviceFlags & AGP_FLAG_SPECIAL_RESERVE)
  1339. >> AGP_FLAG_SET_RATE_SHIFT));
  1340. if (!NT_SUCCESS(Status)) {
  1341. return Status;
  1342. }
  1343. }
  1344. //
  1345. // Add more tweaks here...
  1346. //
  1347. AgpContext->SpecialTarget |=DeviceFlags;
  1348. return STATUS_SUCCESS;
  1349. }
  1350. NTSTATUS
  1351. AgpCPQSetRate(
  1352. IN PAGPCPQ_EXTENSION AgpContext,
  1353. IN ULONG AgpRate
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. This routine sets the AGP rate
  1358. Arguments:
  1359. AgpContext - Supplies the AGP context
  1360. AgpRate - Rate to set
  1361. note: this routine assumes that AGP has already been enabled, and that
  1362. whatever rate we've been asked to set is supported by master
  1363. Return Value:
  1364. STATUS_SUCCESS, or error status
  1365. --*/
  1366. {
  1367. NTSTATUS Status;
  1368. ULONG TargetEnable;
  1369. ULONG MasterEnable;
  1370. PCI_AGP_CAPABILITY TargetCap;
  1371. PCI_AGP_CAPABILITY MasterCap;
  1372. BOOLEAN ReverseInit;
  1373. //
  1374. // Read capabilities
  1375. //
  1376. Status = AgpLibGetPciDeviceCapability(0, 0, &TargetCap);
  1377. if (!NT_SUCCESS(Status)) {
  1378. AGPLOG(AGP_WARNING, ("AgpCpqSetRate: AgpLibGetPciDeviceCapability "
  1379. "failed %08lx\n", Status));
  1380. return Status;
  1381. }
  1382. Status = AgpLibGetMasterCapability(AgpContext, &MasterCap);
  1383. if (!NT_SUCCESS(Status)) {
  1384. AGPLOG(AGP_WARNING, ("AgpCpqSetRate: AgpLibGetMasterCapability "
  1385. "failed %08lx\n", Status));
  1386. return Status;
  1387. }
  1388. //
  1389. // Verify the requested rate is supported by both master and target
  1390. //
  1391. if (!(AgpRate & TargetCap.AGPStatus.Rate & MasterCap.AGPStatus.Rate)) {
  1392. return STATUS_INVALID_PARAMETER;
  1393. }
  1394. //
  1395. // Disable AGP while the pull the rug out from underneath
  1396. //
  1397. TargetEnable = TargetCap.AGPCommand.AGPEnable;
  1398. TargetCap.AGPCommand.AGPEnable = 0;
  1399. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1400. if (!NT_SUCCESS(Status)) {
  1401. AGPLOG(AGP_WARNING,
  1402. ("AgpCpqSetRate: AgpLibSetPciDeviceCapability %08lx for "
  1403. "Target failed %08lx\n",
  1404. &TargetCap,
  1405. Status));
  1406. return Status;
  1407. }
  1408. MasterEnable = MasterCap.AGPCommand.AGPEnable;
  1409. MasterCap.AGPCommand.AGPEnable = 0;
  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. return Status;
  1418. }
  1419. //
  1420. // Fire up AGP with new rate
  1421. //
  1422. ReverseInit =
  1423. (AgpContext->SpecialTarget & AGP_FLAG_REVERSE_INITIALIZATION) ==
  1424. AGP_FLAG_REVERSE_INITIALIZATION;
  1425. if (ReverseInit) {
  1426. MasterCap.AGPCommand.Rate = AgpRate;
  1427. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1428. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1429. if (!NT_SUCCESS(Status)) {
  1430. AGPLOG(AGP_WARNING,
  1431. ("AgpCpqSetRate: AgpLibSetMasterCapability %08lx failed "
  1432. "%08lx\n",
  1433. &MasterCap,
  1434. Status));
  1435. }
  1436. }
  1437. TargetCap.AGPCommand.Rate = AgpRate;
  1438. TargetCap.AGPCommand.AGPEnable = TargetEnable;
  1439. Status = AgpLibSetPciDeviceCapability(0, 0, &TargetCap);
  1440. if (!NT_SUCCESS(Status)) {
  1441. AGPLOG(AGP_WARNING,
  1442. ("AgpCpqSetRate: AgpLibSetPciDeviceCapability %08lx for "
  1443. "Target failed %08lx\n",
  1444. &TargetCap,
  1445. Status));
  1446. return Status;
  1447. }
  1448. if (!ReverseInit) {
  1449. MasterCap.AGPCommand.Rate = AgpRate;
  1450. MasterCap.AGPCommand.AGPEnable = MasterEnable;
  1451. Status = AgpLibSetMasterCapability(AgpContext, &MasterCap);
  1452. if (!NT_SUCCESS(Status)) {
  1453. AGPLOG(AGP_WARNING,
  1454. ("AgpCpqSetRate: AgpLibSetMasterCapability %08lx failed "
  1455. "%08lx\n",
  1456. &MasterCap,
  1457. Status));
  1458. }
  1459. }
  1460. return Status;
  1461. }