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.

1303 lines
32 KiB

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