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.

1189 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. intrface.c
  5. Abstract:
  6. Routines for implementing the AGP_BUS_INTERFACE_STANDARD interface
  7. Author:
  8. John Vert (jvert) 10/26/1997
  9. Revision History:
  10. Elliot Shmukler (elliots) 3/24/1999 - Added support for "favored" memory
  11. ranges for AGP physical memory allocation,
  12. fixed some bugs.
  13. --*/
  14. #define INITGUID 1
  15. #include "agplib.h"
  16. VOID
  17. AgpLibFlushDcacheMdl(
  18. PMDL Mdl
  19. );
  20. VOID
  21. ApFlushDcache(
  22. IN PKDPC Dpc,
  23. IN PKEVENT Event,
  24. IN PMDL Mdl,
  25. IN PVOID SystemArgument2
  26. );
  27. PMDL
  28. AgpCombineMdlList(IN PMDL MdlList);
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, AgpInterfaceReference)
  31. #pragma alloc_text(PAGE, AgpInterfaceDereference)
  32. #pragma alloc_text(PAGE, AgpInterfaceReserveMemory)
  33. #pragma alloc_text(PAGE, AgpInterfaceReleaseMemory)
  34. #pragma alloc_text(PAGE, AgpInterfaceSetRate)
  35. #pragma alloc_text(PAGE, AgpInterfaceCommitMemory)
  36. #pragma alloc_text(PAGE, AgpInterfaceFreeMemory)
  37. #pragma alloc_text(PAGE, AgpLibFlushDcacheMdl)
  38. #pragma alloc_text(PAGE, AgpLibAllocatePhysicalMemory)
  39. #pragma alloc_text(PAGE, AgpLibAllocateMappedPhysicalMemory)
  40. #pragma alloc_text(PAGE, AgpCombineMdlList)
  41. #endif
  42. VOID
  43. AgpInterfaceReference(
  44. IN PMASTER_EXTENSION Extension
  45. )
  46. /*++
  47. Routine Description:
  48. References an interface. Currently a NOP.
  49. Arguments:
  50. Extension - Supplies the device extension
  51. Return Value:
  52. None
  53. --*/
  54. {
  55. PAGED_CODE();
  56. InterlockedIncrement(&Extension->InterfaceCount);
  57. }
  58. VOID
  59. AgpInterfaceDereference(
  60. IN PMASTER_EXTENSION Extension
  61. )
  62. /*++
  63. Routine Description:
  64. Dereferences an interface. Currently a NOP.
  65. Arguments:
  66. Extension - Supplies the device extension
  67. Return Value:
  68. None
  69. --*/
  70. {
  71. PAGED_CODE();
  72. InterlockedDecrement(&Extension->InterfaceCount);
  73. }
  74. NTSTATUS
  75. AgpInterfaceReserveMemory(
  76. IN PMASTER_EXTENSION Extension,
  77. IN ULONG NumberOfPages,
  78. IN MEMORY_CACHING_TYPE MemoryType,
  79. OUT PVOID *MapHandle,
  80. OUT OPTIONAL PHYSICAL_ADDRESS *PhysicalAddress
  81. )
  82. /*++
  83. Routine Description:
  84. Reserves memory in the specified aperture
  85. Arguments:
  86. Extension - Supplies the device extension where physical address space should be reserved.
  87. NumberOfPages - Supplies the number of pages to reserve.
  88. MemoryType - Supplies the memory caching type.
  89. MapHandle - Returns the mapping handle to be used on subsequent calls.
  90. PhysicalAddress - If present, returns the physical address in the aperture of the reserved
  91. space
  92. Return Value:
  93. NTSTATUS
  94. --*/
  95. {
  96. PVOID AgpContext;
  97. NTSTATUS Status;
  98. PHYSICAL_ADDRESS MemoryBase;
  99. PAGP_RANGE Range;
  100. PAGED_CODE();
  101. AgpContext = GET_AGP_CONTEXT_FROM_MASTER(Extension);
  102. Range = ExAllocatePoolWithTag(PagedPool,
  103. sizeof(AGP_RANGE),
  104. 'RpgA');
  105. if (Range == NULL) {
  106. return(STATUS_INSUFFICIENT_RESOURCES);
  107. }
  108. Range->CommittedPages = 0;
  109. Range->NumberOfPages = NumberOfPages;
  110. Range->Type = MemoryType;
  111. LOCK_MASTER(Extension);
  112. Status = AgpReserveMemory(AgpContext,
  113. Range);
  114. UNLOCK_MASTER(Extension);
  115. if (!NT_SUCCESS(Status)) {
  116. AGPLOG(AGP_CRITICAL,
  117. ("AgpInterfaceReserveMemory - reservation of %x pages of type %d failed %08lx\n",
  118. NumberOfPages,
  119. MemoryType,
  120. Status));
  121. } else {
  122. AGPLOG(AGP_NOISE,
  123. ("AgpInterfaceReserveMemory - reserved %x pages of type %d at %I64X\n",
  124. NumberOfPages,
  125. MemoryType,
  126. Range->MemoryBase.QuadPart));
  127. }
  128. *MapHandle = Range;
  129. if (ARGUMENT_PRESENT(PhysicalAddress)) {
  130. *PhysicalAddress = Range->MemoryBase;
  131. }
  132. return(Status);
  133. }
  134. NTSTATUS
  135. AgpInterfaceReleaseMemory(
  136. IN PMASTER_EXTENSION Extension,
  137. IN PVOID MapHandle
  138. )
  139. /*++
  140. Routine Description:
  141. Releases memory in the specified aperture that was previously reserved by
  142. AgpInterfaceReserveMemory
  143. Arguments:
  144. Extension - Supplies the device extension where physical address space should be reserved.
  145. MapHandle - Supplies the mapping handle returned from AgpInterfaceReserveMemory
  146. Return Value:
  147. NTSTATUS
  148. --*/
  149. {
  150. PAGP_RANGE Range;
  151. PVOID AgpContext;
  152. NTSTATUS Status;
  153. PHYSICAL_ADDRESS MemoryBase;
  154. PAGED_CODE();
  155. AgpContext = GET_AGP_CONTEXT_FROM_MASTER(Extension);
  156. Range = (PAGP_RANGE)MapHandle;
  157. LOCK_MASTER(Extension);
  158. //
  159. // Make sure the range is empty
  160. //
  161. ASSERT(Range->CommittedPages == 0);
  162. if (Range->CommittedPages != 0) {
  163. AGPLOG(AGP_CRITICAL,
  164. ("AgpInterfaceReleaseMemory - Invalid attempt to release non-empty range %08lx\n",
  165. Range));
  166. UNLOCK_MASTER(Extension);
  167. return(STATUS_INVALID_PARAMETER);
  168. }
  169. AGPLOG(AGP_NOISE,
  170. ("AgpInterfaceReleaseMemory - releasing range %08lx, %lx pages at %08lx\n",
  171. Range,
  172. Range->NumberOfPages,
  173. Range->MemoryBase.QuadPart));
  174. Status = AgpReleaseMemory(AgpContext,
  175. Range);
  176. if (!NT_SUCCESS(Status)) {
  177. AGPLOG(AGP_CRITICAL,
  178. ("AgpInterfaceReleaseMemory - release failed %08lx\n",
  179. Status));
  180. }
  181. UNLOCK_MASTER(Extension);
  182. ExFreePool(Range);
  183. return(Status);
  184. }
  185. NTSTATUS
  186. AgpInterfaceCommitMemory(
  187. IN PMASTER_EXTENSION Extension,
  188. IN PVOID MapHandle,
  189. IN ULONG NumberOfPages,
  190. IN ULONG OffsetInPages,
  191. IN OUT PMDL Mdl OPTIONAL,
  192. OUT PHYSICAL_ADDRESS *MemoryBase
  193. )
  194. /*++
  195. Routine Description:
  196. Commits memory into the specified aperture that was previously reserved by
  197. AgpInterfaceReserveMemory
  198. Arguments:
  199. Extension - Supplies the device extension where physical address space should
  200. be committed.
  201. MapHandle - Supplies the mapping handle returned from AgpInterfaceReserveMemory
  202. NumberOfPages - Supplies the number of pages to be committed.
  203. OffsetInPages - Supplies the offset, in pages, into the aperture reserved by
  204. AgpInterfaceReserveMemory
  205. Mdl - Returns the MDL describing the pages of memory committed.
  206. MemoryBase - Returns the physical memory address of the committed memory.
  207. Return Value:
  208. NTSTATUS
  209. --*/
  210. {
  211. PAGP_RANGE Range = (PAGP_RANGE)MapHandle;
  212. PMDL NewMdl;
  213. PVOID AgpContext;
  214. NTSTATUS Status=STATUS_SUCCESS;
  215. ULONG RunLength, RunOffset;
  216. ULONG CurrentLength, CurrentOffset;
  217. PMDL FirstMdl=NULL;
  218. PAGED_CODE();
  219. AgpContext = GET_AGP_CONTEXT_FROM_MASTER(Extension);
  220. ASSERT(NumberOfPages <= Range->NumberOfPages);
  221. ASSERT(NumberOfPages > 0);
  222. ASSERT((Mdl == NULL) || (Mdl->ByteCount == PAGE_SIZE * NumberOfPages));
  223. CurrentLength = NumberOfPages;
  224. CurrentOffset = OffsetInPages;
  225. LOCK_MASTER(Extension);
  226. do {
  227. //
  228. // Save ourselves the trouble...
  229. //
  230. if (!(CurrentLength > 0)) {
  231. break;
  232. }
  233. //
  234. // Find the first free run in the supplied range.
  235. //
  236. AgpFindFreeRun(AgpContext,
  237. Range,
  238. CurrentLength,
  239. CurrentOffset,
  240. &RunLength,
  241. &RunOffset);
  242. if (RunLength > 0) {
  243. ASSERT(RunLength <= CurrentLength);
  244. ASSERT(RunOffset >= CurrentOffset);
  245. ASSERT(RunOffset < CurrentOffset + CurrentLength);
  246. ASSERT(RunOffset + RunLength <= CurrentOffset + CurrentLength);
  247. //
  248. // Compute the next offset and length
  249. //
  250. CurrentLength -= (RunOffset - CurrentOffset) + RunLength;
  251. CurrentOffset = RunOffset + RunLength;
  252. //
  253. // Get an MDL from memory management big enough to map the
  254. // requested range.
  255. //
  256. NewMdl = AgpLibAllocatePhysicalMemory(AgpContext, RunLength * PAGE_SIZE);
  257. //
  258. // This can fail in two ways, either no memory is available at all (NewMdl == NULL)
  259. // or some pages were available, but not enough. (NewMdl->ByteCount < Length)
  260. //
  261. if (NewMdl == NULL) {
  262. AGPLOG(AGP_CRITICAL,
  263. ("AgpInterfaceReserveMemory - Couldn't allocate pages for %lx bytes\n",
  264. RunLength));
  265. Status = STATUS_INSUFFICIENT_RESOURCES;
  266. break;
  267. } else if (BYTES_TO_PAGES(NewMdl->ByteCount) < RunLength) {
  268. AGPLOG(AGP_CRITICAL,
  269. ("AgpInterfaceCommitMemory - Only allocated enough pages for %lx of %lx bytes\n",
  270. NewMdl->ByteCount,
  271. RunLength));
  272. Status = STATUS_INSUFFICIENT_RESOURCES;
  273. MmFreePagesFromMdl(NewMdl);
  274. break;
  275. }
  276. //
  277. // Now that we have our MDL, we can map this into the specified
  278. // range.
  279. //
  280. if (AgpFlushPages != NULL) {
  281. if (!NT_SUCCESS((AgpFlushPages)(AgpContext, NewMdl))) {
  282. Status = STATUS_INSUFFICIENT_RESOURCES;
  283. MmFreePagesFromMdl(NewMdl);
  284. break;
  285. }
  286. } else {
  287. AgpLibFlushDcacheMdl(NewMdl);
  288. }
  289. Status = AgpMapMemory(AgpContext,
  290. Range,
  291. NewMdl,
  292. RunOffset,
  293. MemoryBase);
  294. if (!NT_SUCCESS(Status)) {
  295. AGPLOG(AGP_CRITICAL,
  296. ("AgpInterfaceCommitMemory - AgpMapMemory for Mdl %08lx in range %08lx failed %08lx\n",
  297. NewMdl,
  298. Range,
  299. Status));
  300. MmFreePagesFromMdl(NewMdl);
  301. break;
  302. }
  303. Range->CommittedPages += RunLength;
  304. //
  305. // Add this MDL to our list of allocated MDLs for cleanup
  306. // If we need to cleanup, we will also need to know the page offset
  307. // so that we can unmap the memory. Stash that value in the ByteOffset
  308. // field of the MDL (ByteOffset is always 0 for our MDLs)
  309. //
  310. NewMdl->ByteOffset = RunOffset;
  311. NewMdl->Next = FirstMdl;
  312. FirstMdl = NewMdl;
  313. }
  314. } while (RunLength > 0);
  315. //
  316. // Cleanup the MDLs. If the allocation failed, we need to
  317. // unmap them and free the pages and the MDL itself. If the
  318. // operation completed successfully, we just need to free the
  319. // MDL.
  320. //
  321. while (FirstMdl) {
  322. NewMdl = FirstMdl;
  323. FirstMdl = NewMdl->Next;
  324. if (!NT_SUCCESS(Status)) {
  325. //
  326. // Unmap the memory that was mapped. The ByteOffset field
  327. // of the MDL is overloaded here to store the offset in pages
  328. // into the range.
  329. //
  330. AgpUnMapMemory(AgpContext,
  331. Range,
  332. NewMdl->ByteCount / PAGE_SIZE,
  333. NewMdl->ByteOffset);
  334. NewMdl->ByteOffset = 0;
  335. Range->CommittedPages -= NewMdl->ByteCount / PAGE_SIZE;
  336. MmFreePagesFromMdl(NewMdl);
  337. }
  338. ExFreePool(NewMdl);
  339. }
  340. if (NT_SUCCESS(Status)) {
  341. if (Mdl) {
  342. //
  343. // Get the MDL that describes the entire mapped range.
  344. //
  345. AgpGetMappedPages(AgpContext,
  346. Range,
  347. NumberOfPages,
  348. OffsetInPages,
  349. Mdl);
  350. }
  351. MemoryBase->QuadPart = Range->MemoryBase.QuadPart + OffsetInPages * PAGE_SIZE;
  352. }
  353. UNLOCK_MASTER(Extension);
  354. return(Status);
  355. }
  356. NTSTATUS
  357. AgpInterfaceFreeMemory(
  358. IN PMASTER_EXTENSION Extension,
  359. IN PVOID MapHandle,
  360. IN ULONG NumberOfPages,
  361. IN ULONG OffsetInPages
  362. )
  363. /*++
  364. Routine Description:
  365. Frees memory previously committed by AgpInterfaceCommitMemory
  366. Arguments:
  367. Extension - Supplies the device extension where physical address space should
  368. be freed.
  369. MapHandle - Supplies the mapping handle returned from AgpInterfaceReserveMemory
  370. NumberOfPages - Supplies the number of pages to be freed.
  371. OffsetInPages - Supplies the start of the range to be freed.
  372. Return Value:
  373. NTSTATUS
  374. --*/
  375. {
  376. PAGP_RANGE Range = (PAGP_RANGE)MapHandle;
  377. PVOID AgpContext;
  378. NTSTATUS Status;
  379. PMDL FreeMdl;
  380. PAGED_CODE();
  381. AgpContext = GET_AGP_CONTEXT_FROM_MASTER(Extension);
  382. ASSERT(OffsetInPages < Range->NumberOfPages);
  383. ASSERT(OffsetInPages + NumberOfPages <= Range->NumberOfPages);
  384. //
  385. // Make sure the supplied address is within the reserved range
  386. //
  387. if ((OffsetInPages >= Range->NumberOfPages) ||
  388. (OffsetInPages + NumberOfPages > Range->NumberOfPages)) {
  389. AGPLOG(AGP_WARNING,
  390. ("AgpInterfaceFreeMemory - Invalid free of %x pages at offset %x from range %I64X (%x pages)\n",
  391. NumberOfPages,
  392. OffsetInPages,
  393. Range->MemoryBase.QuadPart,
  394. Range->NumberOfPages));
  395. return(STATUS_INVALID_PARAMETER);
  396. }
  397. //
  398. // Allocate an MDL big enough to contain the pages to be unmapped.
  399. //
  400. FreeMdl = MmCreateMdl(NULL, 0, NumberOfPages * PAGE_SIZE);
  401. if (FreeMdl == NULL) {
  402. //
  403. // This is kind of a sticky situation. We can't allocate the memory
  404. // that we need to free up some memory! I guess we could have a small
  405. // MDL on our stack and free things that way.
  406. //
  407. // John Vert (jvert) 11/11/1997
  408. // implement this
  409. //
  410. // ISSUE-2000/09/06-enelson I've tried several AGP video cards, and
  411. // not one of them uses AgpInterfaceCommit/FreeMemory, hence I'm
  412. // loathe to change this at this point...
  413. //
  414. ASSERT(FreeMdl != NULL);
  415. return(STATUS_INSUFFICIENT_RESOURCES);
  416. }
  417. LOCK_MASTER(Extension);
  418. //
  419. // Get the MDL that describes the entire mapped range
  420. //
  421. AgpGetMappedPages(AgpContext,
  422. Range,
  423. NumberOfPages,
  424. OffsetInPages,
  425. FreeMdl);
  426. //
  427. // Unmap the memory
  428. //
  429. Status = AgpUnMapMemory(AgpContext,
  430. Range,
  431. NumberOfPages,
  432. OffsetInPages);
  433. UNLOCK_MASTER(Extension);
  434. if (!NT_SUCCESS(Status)) {
  435. AGPLOG(AGP_CRITICAL,
  436. ("AgpInterfaceFreeMemory - UnMapMemory for %x pages at %I64X failed %08lx\n",
  437. NumberOfPages,
  438. Range->MemoryBase.QuadPart + OffsetInPages * PAGE_SIZE,
  439. Status));
  440. } else {
  441. //
  442. // Free the pages
  443. //
  444. MmFreePagesFromMdl(FreeMdl);
  445. ASSERT(Range->CommittedPages >= NumberOfPages);
  446. Range->CommittedPages -= NumberOfPages;
  447. }
  448. //
  449. // Free the MDL we allocated.
  450. //
  451. ExFreePool(FreeMdl);
  452. return(Status);
  453. }
  454. NTSTATUS
  455. AgpInterfaceGetMappedPages(
  456. IN PMASTER_EXTENSION Extension,
  457. IN PVOID MapHandle,
  458. IN ULONG NumberOfPages,
  459. IN ULONG OffsetInPages,
  460. OUT PMDL Mdl
  461. )
  462. /*++
  463. Routine Description:
  464. Returns the list of physical pages mapped backing the specified range.
  465. Arguments:
  466. Extension - Supplies the device extension where physical address space should
  467. be freed.
  468. MapHandle - Supplies the mapping handle returned from AgpInterfaceReserveMemory
  469. NumberOfPages - Supplies the number of pages to be returned
  470. OffsetInPages - Supplies the start of the rangion
  471. Return Value:
  472. NTSTATUS
  473. --*/
  474. {
  475. PAGP_RANGE Range = (PAGP_RANGE)MapHandle;
  476. PVOID AgpContext;
  477. NTSTATUS Status;
  478. PAGED_CODE();
  479. AgpContext = GET_AGP_CONTEXT_FROM_MASTER(Extension);
  480. ASSERT(NumberOfPages <= Range->NumberOfPages);
  481. ASSERT(NumberOfPages > 0);
  482. ASSERT(OffsetInPages < Range->NumberOfPages);
  483. ASSERT(OffsetInPages + NumberOfPages <= Range->NumberOfPages);
  484. ASSERT(Mdl->ByteCount == PAGE_SIZE * NumberOfPages);
  485. //
  486. // Make sure the supplied address is within the reserved range
  487. //
  488. if ((OffsetInPages >= Range->NumberOfPages) ||
  489. (OffsetInPages + NumberOfPages > Range->NumberOfPages)) {
  490. AGPLOG(AGP_WARNING,
  491. ("AgpInterfaceGetMappedPages - Invalid 'get' of %x pages at offset %x from range %I64X (%x pages)\n",
  492. NumberOfPages,
  493. OffsetInPages,
  494. Range->MemoryBase.QuadPart,
  495. Range->NumberOfPages));
  496. return(STATUS_INVALID_PARAMETER);
  497. }
  498. //
  499. // Get the MDL that describes the entire mapped range
  500. //
  501. LOCK_MASTER(Extension);
  502. AgpGetMappedPages(AgpContext,
  503. Range,
  504. NumberOfPages,
  505. OffsetInPages,
  506. Mdl);
  507. UNLOCK_MASTER(Extension);
  508. return(STATUS_SUCCESS);
  509. }
  510. PMDL
  511. AgpLibAllocatePhysicalMemory(IN PVOID AgpContext, IN ULONG TotalBytes)
  512. /*++
  513. Routine Description:
  514. Allocates a set of physical memory pages for use by the AGP driver.
  515. This routine uses MmAllocatePagesForMdl to attempt to allocate
  516. as many of the pages as possible within favored AGP memory
  517. ranges (if any).
  518. Arguments:
  519. AgpContext - The AgpContext
  520. TotalBytes - The total amount of bytes to allocate.
  521. Return Value:
  522. An MDL that describes the allocated physical pages or NULL
  523. if this function is unsuccessful.
  524. NOTE: Just like MmAllocatePagesForMdl, this function can return
  525. an MDL that describes an allocation smaller than TotalBytes in size.
  526. --*/
  527. {
  528. PHYSICAL_ADDRESS ZeroAddress, MaxAddress;
  529. PMDL MdlList = NULL, NewMdl = NULL;
  530. PTARGET_EXTENSION Extension;
  531. ULONG i, PagesNeeded;
  532. PAGED_CODE();
  533. AGPLOG(AGP_NOISE, ("AGPLIB: Attempting to allocate memory = %u pages.\n",
  534. BYTES_TO_PAGES(TotalBytes)));
  535. // Initialize some stuff
  536. ZeroAddress.QuadPart = 0;
  537. MAX_MEM(MaxAddress.QuadPart);
  538. AGPLOG(AGP_NOISE, ("AGPLIB: Max memory set to %I64x.\n", MaxAddress.QuadPart));
  539. GET_TARGET_EXTENSION(Extension, AgpContext);
  540. // How many pages do we need?
  541. PagesNeeded = BYTES_TO_PAGES(TotalBytes);
  542. //
  543. // Loop through each favored range, attempting to allocate
  544. // as much as possible from that range within the bounds
  545. // of what we actually need.
  546. //
  547. for (i = 0; i < Extension->FavoredMemory.NumRanges; i++) {
  548. AGPLOG(AGP_NOISE,
  549. ("AGPLIB: Trying to allocate %u pages from range %I64x - %I64x.\n",
  550. PagesNeeded,
  551. Extension->FavoredMemory.Ranges[i].Lower,
  552. Extension->FavoredMemory.Ranges[i].Upper));
  553. NewMdl = MmAllocatePagesForMdl(Extension->FavoredMemory.Ranges[i].Lower,
  554. Extension->FavoredMemory.Ranges[i].Upper,
  555. ZeroAddress,
  556. PagesNeeded << PAGE_SHIFT);
  557. if (NewMdl) {
  558. AGPLOG(AGP_NOISE, ("AGPLIB: %u pages allocated in range.\n",
  559. NewMdl->ByteCount >> PAGE_SHIFT));
  560. PagesNeeded -= (NewMdl->ByteCount >> PAGE_SHIFT);
  561. //
  562. // Build a list of the MDls used
  563. // for each range-based allocation
  564. //
  565. NewMdl->Next = MdlList;
  566. MdlList = NewMdl;
  567. // Stop allocating if we are finished.
  568. if (PagesNeeded == 0) break;
  569. } else {
  570. AGPLOG(AGP_NOISE, ("AGPLIB: NO pages allocated in range.\n"));
  571. }
  572. }
  573. //
  574. // Attempt to allocate from ALL of physical memory
  575. // if we could not complete our allocation with only
  576. // the favored memory ranges.
  577. //
  578. if (PagesNeeded > 0) {
  579. AGPLOG(AGP_NOISE, ("AGPLIB: Global Memory allocation for %u pages.\n",
  580. PagesNeeded));
  581. NewMdl = MmAllocatePagesForMdl(ZeroAddress,
  582. MaxAddress,
  583. ZeroAddress,
  584. PagesNeeded << PAGE_SHIFT);
  585. if (NewMdl) {
  586. AGPLOG(AGP_NOISE, ("AGPLIB: Good Global Memory Alloc for %u pages.\n",
  587. NewMdl->ByteCount >> PAGE_SHIFT));
  588. //
  589. // Add this MDL to the list as well
  590. //
  591. NewMdl->Next = MdlList;
  592. MdlList = NewMdl;
  593. } else {
  594. AGPLOG(AGP_NOISE, ("AGPLIB: Failed Global Memory Alloc.\n"));
  595. }
  596. }
  597. // We now have a list of Mdls in MdlList that give us the best
  598. // possible memory allocation taking favored ranges into account.
  599. // What we now need to do is combine this Mdl list into one mdl.
  600. NewMdl = AgpCombineMdlList(MdlList);
  601. if (!NewMdl && MdlList) {
  602. AGPLOG(AGP_WARNING, ("AGPLIB: Could not combine MDL List!\n"));
  603. // This is bad. The mdl list could not be combined probably
  604. // because a large enough mdl could not be allocated for
  605. // the combination.
  606. // This is not the end of the world however, since the mdl list
  607. // is not modified until its combination has succeeded so we
  608. // still have a valid list. But we need it in one Mdl, so
  609. // we just fall back to the simplest allocation strategy
  610. // we have available:
  611. // 1. Destroy the list and all of its allocations.
  612. while(MdlList)
  613. {
  614. MmFreePagesFromMdl(MdlList);
  615. NewMdl = MdlList->Next;
  616. ExFreePool(MdlList);
  617. MdlList = NewMdl;
  618. }
  619. // 2. Allocate a single Mdl with our pages without regard
  620. // for favored memory ranges.
  621. NewMdl = MmAllocatePagesForMdl(ZeroAddress,
  622. MaxAddress,
  623. ZeroAddress,
  624. TotalBytes);
  625. }
  626. return NewMdl;
  627. }
  628. PMDL
  629. AgpCombineMdlList(IN PMDL MdlList)
  630. /*++
  631. Routine Description:
  632. Combines a list of MDLs that describe some set of physical memory
  633. pages into a single MDL that describes the same set of pages.
  634. The MDLs in the list should be of the type produced by
  635. MmAllocatePagesForMdl (i.e. MDLs that are useful for nothing more
  636. than as an array of PFNs)
  637. This function is used by AgpLibAllocatePhysicalMemory in order
  638. to combine its multiple range-based allocations into 1 MDL.
  639. Arguments:
  640. MdlList - A list of MDLs to be combines
  641. Return Value:
  642. A single MDL that describes the same set of physical pages as
  643. the MDLs in MdlList or NULL if this function is unsuccessful.
  644. NOTE: This function will deallocate the Mdls in MdlList if it
  645. is successful. If it is unsuccessful, however, it will leave
  646. the MdlList intact.
  647. --*/
  648. {
  649. PMDL NewMdl = NULL, Mdl, MdlTemp;
  650. ULONG Pages = 0;
  651. PPFN_NUMBER NewPageArray, PageArray;
  652. ULONG i; // for debugging only
  653. PAGED_CODE();
  654. if ((MdlList == NULL) || (MdlList->Next == NULL)) {
  655. // List of 0 or 1 elements, no need for this
  656. // function to do anything.
  657. return MdlList;
  658. }
  659. // Calculate the number of pages spanned by this MdlList.
  660. for(Mdl = MdlList; Mdl; Mdl = Mdl->Next)
  661. Pages += BYTES_TO_PAGES(Mdl->ByteCount);
  662. // Allocate a new Mdl of the proper size.
  663. NewMdl = MmCreateMdl(NULL, NULL, Pages << PAGE_SHIFT);
  664. if (!NewMdl) {
  665. // Chances are that the system will bugcheck before
  666. // this actually happens ... but whatever.
  667. return NULL;
  668. }
  669. // Run through the mdl list, combining the mdls found
  670. // into a new mdl.
  671. //
  672. // First, get a pointer to the PFN array of the new Mdl
  673. //
  674. NewPageArray = MmGetMdlPfnArray(NewMdl);
  675. for(Mdl = MdlList; Mdl; Mdl = Mdl->Next)
  676. {
  677. // Get a pointer to the physical page number array in this Mdl.
  678. PageArray = MmGetMdlPfnArray(Mdl);
  679. Pages = Mdl->ByteCount >> PAGE_SHIFT;
  680. // Copy this array into a proper slot in the array area of the new Mdl.
  681. RtlCopyMemory((PVOID)NewPageArray,
  682. (PVOID)PageArray,
  683. sizeof(PFN_NUMBER) * Pages);
  684. // Adjust new array slot pointer appropriately for the next copy
  685. NewPageArray += Pages;
  686. }
  687. // The list has been combined, now we need to destroy the Mdls
  688. // in the list.
  689. Mdl = MdlList;
  690. while(Mdl)
  691. {
  692. MdlTemp = Mdl->Next;
  693. ExFreePool(Mdl);
  694. Mdl = MdlTemp;
  695. }
  696. // All done. Return the new combined Mdl.
  697. return NewMdl;
  698. }
  699. PVOID
  700. AgpLibAllocateMappedPhysicalMemory(IN PVOID AgpContext, IN ULONG TotalBytes)
  701. /*++
  702. Routine Description:
  703. Same as AgpLibAllocatePhysicalMemory, except this function will
  704. also map the allocated memory to a virtual address.
  705. Arguments:
  706. Same as AgpLibAllocatePhysicalMemory.
  707. Return Value:
  708. A virtual address of the allocated memory or NULL if unsuccessful.
  709. --*/
  710. {
  711. PMDL Mdl;
  712. PVOID Ret;
  713. PAGED_CODE();
  714. AGPLOG(AGP_NOISE,
  715. ("AGPLIB: Attempting to allocate mapped memory = %u.\n", TotalBytes));
  716. //
  717. // Call the real memory allocator.
  718. //
  719. Mdl = AgpLibAllocatePhysicalMemory(AgpContext, TotalBytes);
  720. // Two possible failures
  721. // 1. MDL is NULL. No memory could be allocated.
  722. if (Mdl == NULL) {
  723. AGPLOG(AGP_WARNING, ("AGPMAP: Could not allocate anything.\n"));
  724. return NULL;
  725. }
  726. // 2. MDL has some pages allocated but not enough.
  727. if (Mdl->ByteCount < TotalBytes) {
  728. AGPLOG(AGP_WARNING, ("AGPMAP: Could not allocate enough.\n"));
  729. MmFreePagesFromMdl(Mdl);
  730. ExFreePool(Mdl);
  731. return NULL;
  732. }
  733. // Ok. Our allocation succeeded. Map it to a virtual address.
  734. // Step 1: Map the locked Pages. (will return NULL if failed)
  735. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  736. Ret = MmMapLockedPagesSpecifyCache (Mdl,
  737. KernelMode,
  738. MmNonCached,
  739. NULL,
  740. FALSE,
  741. HighPagePriority);
  742. // Don't need the Mdl anymore, whether we succeeded or failed.
  743. ExFreePool(Mdl);
  744. if (Ret == NULL) {
  745. AGPLOG(AGP_WARNING, ("AGPMAP: Could not map.\n"));
  746. }
  747. return Ret;
  748. }
  749. #if defined (_X86_)
  750. #define FLUSH_DCACHE(Mdl) __asm{ wbinvd }
  751. #else
  752. #define FLUSH_DCACHE(Mdl) \
  753. AGPLOG(AGP_CRITICAL, \
  754. ("AgpLibFlushDcacheMdl - NEED TO IMPLEMENT DCACHE FLUSH FOR THIS ARCHITECTURE!!\n"))
  755. #endif
  756. VOID
  757. AgpLibFlushDcacheMdl(
  758. PMDL Mdl
  759. )
  760. /*++
  761. Routine Description:
  762. Flushes the specified MDL from the D-caches of all processors
  763. in the system.
  764. Current algorithm is to set the current thread's affinity to each
  765. processor in turn and flush the dcache. This could be made a lot
  766. more efficient if this turns out to be a hot codepath
  767. Arguments:
  768. Mdl - Supplies the MDL to be flushed.
  769. Return Value:
  770. None.
  771. --*/
  772. {
  773. NTSTATUS Status;
  774. KAFFINITY Processors;
  775. UCHAR Number;
  776. KEVENT Event;
  777. KDPC Dpc;
  778. PAGED_CODE();
  779. Processors = KeQueryActiveProcessors();
  780. //
  781. // Quick out for the UP case.
  782. //
  783. if (Processors == 1) {
  784. FLUSH_DCACHE(Mdl);
  785. return;
  786. }
  787. //
  788. // We will invoke a DPC on each processor. That DPC will flush the cache,
  789. // set the event and return.
  790. //
  791. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  792. Number = 0;
  793. while (Processors) {
  794. if (Processors & 1) {
  795. //
  796. // Initialize the DPC and set it to run on the specified
  797. // processor.
  798. //
  799. KeInitializeDpc(&Dpc,ApFlushDcache, &Event);
  800. KeSetTargetProcessorDpc(&Dpc, Number);
  801. //
  802. // Queue the DPC and wait for it to finish its work.
  803. //
  804. KeClearEvent(&Event);
  805. KeInsertQueueDpc(&Dpc, Mdl, NULL);
  806. KeWaitForSingleObject(&Event,
  807. Executive,
  808. KernelMode,
  809. FALSE,
  810. NULL);
  811. }
  812. Processors = Processors >> 1;
  813. ++Number;
  814. }
  815. }
  816. VOID
  817. ApFlushDcache(
  818. IN PKDPC Dpc,
  819. IN PKEVENT Event,
  820. IN PMDL Mdl,
  821. IN PVOID SystemArgument2
  822. )
  823. /*++
  824. Routine Description:
  825. DPC which executes on each processor in turn to flush the
  826. specified MDL out of the dcache on each.
  827. Arguments:
  828. Dpc - supplies the DPC object
  829. Event - Supplies the event to signal when the DPC is complete
  830. Mdl - Supplies the MDL to be flushed from the dcache
  831. Return Value:
  832. None
  833. --*/
  834. {
  835. FLUSH_DCACHE(Mdl);
  836. KeSetEvent(Event, 0, FALSE);
  837. }
  838. NTSTATUS
  839. AgpInterfaceSetRate(
  840. IN PMASTER_EXTENSION Extension,
  841. IN ULONG AgpRate
  842. )
  843. /*++
  844. Routine Description:
  845. This routine sets the AGP rate
  846. Arguments:
  847. Extension - Supplies the device extension
  848. AgpRate - Rate to set
  849. Return Value:
  850. STATUS_SUCCESS, or error status
  851. --*/
  852. {
  853. ULONGLONG DeviceFlags = 0;
  854. PAGED_CODE();
  855. switch (AgpRate) {
  856. case PCI_AGP_RATE_1X:
  857. DeviceFlags = AGP_FLAG_SET_RATE_1X;
  858. break;
  859. case PCI_AGP_RATE_2X:
  860. DeviceFlags = AGP_FLAG_SET_RATE_2X;
  861. break;
  862. case PCI_AGP_RATE_4X:
  863. DeviceFlags = AGP_FLAG_SET_RATE_4X;
  864. break;
  865. case 8:
  866. DeviceFlags = AGP_FLAG_SET_RATE_8X;
  867. break;
  868. }
  869. if (DeviceFlags != 0) {
  870. return AgpSpecialTarget(GET_AGP_CONTEXT_FROM_MASTER(Extension),
  871. DeviceFlags);
  872. }
  873. return STATUS_INVALID_PARAMETER;
  874. }