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.

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