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.

639 lines
24 KiB

  1. Video DMA Interface.
  2. This note outlines a proposed interface between the display driver,
  3. miniport and the video port. The objective is to provide an interface
  4. for the display driver that optimizes DMA throughput for devices that
  5. support scattergather while maintaining system throughput. The design
  6. also optimizes locking, performing the DMA and unlocking into one
  7. IOCTL if desired, a significant performance win. The idea is to provide
  8. a handle available to the display driver that represents locked memory
  9. and for that handle to be returned from each DMA IOCTL request. The
  10. miniport fields some of theses IOCTLs and calls into the video port for
  11. support.
  12. This interface supports only PCI busmaster devices.
  13. ///////////////////////////////////////////////////////////////////
  14. Video port to miniport interface.
  15. ///////////////////////////////////////////////////////////////////
  16. The miniport must provide 2 things at DriverEntry time:
  17. A) Set Master in VIDEO_PORT_CONFIG_INFO to TRUE.
  18. B) Provide a callback HwStartDma() of type PVIDEO_HW_START_DMA
  19. in the VIDEO_HW_INITIALIZATION_DATA.
  20. Then the following interfaces can be used:
  21. The NT video port support now exports to the miniport the following
  22. function:
  23. 1) BOOLEAN
  24. VideoPortLockPages(
  25. IN PVOID HwDeviceExtension,
  26. IN OUT PVIDEO_REQUEST_PACKET pVrp
  27. IN OUT PEVENT pMappedUserEvent,
  28. IN PEVENT pDisplayEvent,
  29. IN DMA_FLAGS DmaFlags
  30. );
  31. This routine can be called by the miniport to do busmaster DMA for
  32. DMA devices. It returns TRUE if successful and FALSE if not successful.
  33. It can only be called in the context of an IOCTL. It cannot be called
  34. from an ISR or DPC.
  35. Its arguments are:
  36. 1) A pointer to a DEVICE_EXTENSION.
  37. 2) A pointer to a VIDEO_REQUEST_PACKET, whose OutputBuffer it may
  38. modify. The InputBuffer must be the virtual address of the memory
  39. to be locked. The InputBufferSize must be the size of that memory.
  40. The output buffer will receive a PDMA from which may be extracted
  41. a pointer to a scattergather list of physical pages which comprise
  42. the locked down virtual address (via GET_VIDEO_SCATTERGATHER). From
  43. this pointer, one can extract the physical address of any virtual
  44. address (see GET_VIDEO_PHYSICAL_ADDRESS).
  45. 3) A pointer to a mapped user event, which may be set by the miniport.
  46. This is either a valid event returned from EngMapEvent or NULL. This
  47. should be received from the display driver. It will be passed into
  48. HwStartDma every time the resulting handle from VideoPortLockPages()
  49. is passed into the Video Port for a DMA operation. All events can only
  50. be set in the miniport, not waited on.
  51. 4) A pointer to an event received from the display driver, intended
  52. to be used by the display driver to wait on DMA completion. May be
  53. NULL. Again, may only be set in miniport.
  54. This pointer to an event will also be passed into HwStartDma every
  55. time the resulting handle is passed into the Video Port for a DMA
  56. operation.
  57. 4) An enum of type DMA_FLAGS defined in video.h. The values can be:
  58. a) VideoPortUnlockAfterDma
  59. This value should be used for a "one shot" dma action, where
  60. the memory is locked and a dma handle passed to HwStartDma(),
  61. then the memory is unlocked after the miniport signals via
  62. setting pDmaCompletionEvent.
  63. b) VideoPortKeepPagesLocked
  64. This value should only be used for dedicated graphics units.
  65. It does not guarantee that the virtual memory passed in will
  66. remain locked after a dma has completed, only that the system
  67. will try to keep it locked.
  68. c) VideoPortDmaInitOnly
  69. A typical initialization value. If used, the InputBuffer must
  70. contain a pointer to virtual memory. The HwStartDma will not
  71. be called in this case (see below). The memory will remained
  72. locked if possible.
  73. 2) PDMA
  74. VideoPortDoDma(
  75. IN PVOID HwDeviceExtension,
  76. IN PDMA pDma,
  77. IN DMA_FLAGS DmaFlags
  78. );
  79. Routine Description:
  80. This function is called by the miniport when a it has a valid DMA
  81. handle to cause HwStartDma to be called. It can be called outside
  82. the context of an IOCTL, but not from an ISR. It must execute at
  83. irql <= DISPATCH_LEVEL.
  84. Arguments:
  85. HwDeviceExtension - Pointer to miniport HWDeviceExtension.
  86. pDma - Non - NULL DMA handle returned by this routine or
  87. VideoPortLockPages() in OutputBuffer.
  88. DmaFlags - Flags specifying desired action.
  89. Return Value:
  90. Non NULL pDma if the corresponding memory is still locked, NULL
  91. otherwise.
  92. 3) PVOID
  93. VideoPortGetCommonBuffer(
  94. IN PVOID HwDeviceExtension,
  95. IN ULONG DesiredLength,
  96. IN ULONG Alignment,
  97. OUT PVOID * pVirtualAddress,
  98. OUT PPHYSICAL_ADDRESS pLogicalAddress,
  99. OUT PULONG pActualLength,
  100. IN BOOLEAN CacheEnabled
  101. );
  102. Routine Description:
  103. Provides physical address visible to both device and system. Memory seen as contiguous
  104. by device. This routine can only be reliably called at driver load time. Memory allocated
  105. must be less than 256K.
  106. Arguments:
  107. HwDeviceExtension - device extension available to miniport.
  108. DesiredLength - size of desired memory (should be minimal).
  109. Alignment - Desired liagnment of buffer, currently unused.
  110. pVirtualAddress - unused.
  111. pLogicalAddress - [out] parameter which will hold physical address of
  112. of the buffer upon function return.
  113. pActualLength - Actual length of buffer.
  114. CacheEnabled - Specifies whether the allocated memory can be cached.
  115. Return Value:
  116. Virtual address of the common buffer.
  117. 4) PDMA
  118. VideoPortGetMdl(
  119. PVOID HwDeviceExtension,
  120. PDMA pDma
  121. );
  122. Routine Description:
  123. Returns a PMDL representing the page table of the locked buffer.
  124. Arguments:
  125. HwDeviceExtension - device extension available to miniport.
  126. pDma - Dma handle received from either VideoPortLockPages()
  127. or VideoPortDoDma().
  128. Return Value:
  129. A PMDL reprsenting the locked buffer.
  130. 5) BOOLEAN
  131. VideoPortSignalDmaComplete(
  132. IN PVOID HwDeviceExtension,
  133. IN PVOID pDmaHandle
  134. )
  135. /*++
  136. Routine Description:
  137. Arguments:
  138. HwDeviceExtension - a pointer to the miniport HW_DEVICE_EXTENSION.
  139. pDmaHandle - the handle returned in the output buffer of the
  140. VIDEO_REQUEST_PACKET after VideoPortLockPages() returns.
  141. Return Value:
  142. TRUE if the DPC was scheduled, FALSE otherwise.
  143. --*/
  144. 6) PVOID
  145. VideoPortGetDmaContext(
  146. IN PVOID HwDeviceExtension,
  147. IN PDMA pDma
  148. );
  149. /*++
  150. Routine Description:
  151. Arguments:
  152. HwDeviceExtension - a pointer to the miniport HW_DEVICE_EXTENSION.
  153. pDma - the handle returned in the output buffer of the
  154. VIDEO_REQUEST_PACKET after VideoPortLockPages() returns.
  155. Return Value:
  156. The Context previously associated with this PDMA.
  157. --*/
  158. 7) VOID
  159. VideoPortSetDmaContext(
  160. IN PVOID HwDeviceExtension,
  161. OUT PDMA pDma,
  162. IN PVOID InstanceContext
  163. );
  164. /*++
  165. Routine Description:
  166. Arguments:
  167. HwDeviceExtension - a pointer to the miniport HW_DEVICE_EXTENSION.
  168. pDma - the handle returned in the output buffer of the
  169. VIDEO_REQUEST_PACKET after VideoPortLockPages() returns.
  170. InstanceContext - any PVOID supplied by user.
  171. Return Value:
  172. NONE.
  173. --*/
  174. 8) ULONG
  175. VideoPortGetBytesUsed(
  176. IN PVOID HwDeviceExtension,
  177. IN PDMA pDma
  178. );
  179. /*++
  180. Routine Description:
  181. Arguments:
  182. HwDeviceExtension - a pointer to the miniport HW_DEVICE_EXTENSION.
  183. pDma - the handle returned in the output buffer of the
  184. VIDEO_REQUEST_PACKET after VideoPortLockPages() returns.
  185. Return Value:
  186. The number of bytes used in the buffer associated with this PDMA
  187. --*/
  188. 9) VOID
  189. VideoPortSetBytesUsed(
  190. IN PVOID HwDeviceExtension,
  191. IN OUT PDMA pDma,
  192. IN ULONG BytesUsed
  193. );
  194. /*++
  195. Routine Description:
  196. Arguments:
  197. HwDeviceExtension - a pointer to the miniport HW_DEVICE_EXTENSION.
  198. pDma - the handle returned in the output buffer of the
  199. VIDEO_REQUEST_PACKET after VideoPortLockPages() returns.
  200. BytesUsed - The number of bytes written to the buffer.
  201. Return Value:
  202. NONE.
  203. --*/
  204. ///////////////////////////////////////////////////////////////////
  205. Display driver to miniport interface (IOCTL interface).
  206. ///////////////////////////////////////////////////////////////////
  207. 1) Miniport IOCTL routine.
  208. The design attemps to optimize DMA transfer from a fixed piece of virtual
  209. memory. These IOCTLs are to be defined by the miniport and the following
  210. descriptions of the IOCTLs are only suggestions.
  211. IOCTL_VIDEO_DMA_INIT - set by DispDrvr
  212. Causes VideoPortLockPages() to be called by the miniport where the DMA_FLAGS is
  213. set to VideoPortDmaInitOnly. This should only be done in graphics dedicated
  214. contexts, where disk and network IO is secondary to video IO. Driver writers
  215. must be aware that system performance (e.g. WinBench) can be damaged by leaving
  216. memory locked.
  217. IOCTL_VIDEO_DMA_TRANSFER_KEEP_LOCKED - set by DispDrvr
  218. The miniport may set up this IOCTL such that VideoPortDoDma() is called with the
  219. VideoPortKeepPagesLocked DMA_FLAGS argument. This scenario is oriented to graphics
  220. dedicated applications. It optimizes throughput so that the HwStartDma() routine
  221. in the miniport is called. In this way, DMA operations are optimized such that
  222. memory resources to other parts of the system are constrained.
  223. The scatter gather list available to HwStartDma() is valid:
  224. a) before the routine HwStartDma() returns.
  225. b) if HwStartDma() returns asynchronously, the list may be valid
  226. if the system memory manager is not stressed. If the PEVENT
  227. which is the fourth argument to HwStartDma() is set when the DMA is
  228. done, it will remain valid until then. If the PEVENT is not set,
  229. the list may become invalid at random times. This PEVENT must
  230. be set by :
  231. VideoPortSetEvent(HwDeviceExtension, PEVENT);
  232. c) if HwStartDma returns synchronously and the system memory
  233. manager is not stressed, the list will remain valid. if HwStartDma()
  234. return synchronously and the memory manager is stressed, the list
  235. will become invalid after HwStartDma returns.
  236. IOCTL_VIDEO_DMA_TRANSFER_ONCE - set by DispDrvr
  237. The miniport may set up this IOCTL so that VideoPortLockPages() is called with
  238. the VideoPortUnlockAfterDma DMA_FLAGS. This allows the buffer to be locked down,
  239. the HwStartDma miniport routine to be called back and the memory to be unlocked
  240. after the dma transfer has completed. This IOCTL is tuned for systems in which
  241. disk and network IO is very important and memory may be at a premium.
  242. The same remarks apply to the scatter gather list as for
  243. IOCTL_VIDEO_TRANSFER_KEEP_LOCKED.
  244. IOCTL_VIDEO_DMA_UNLOCK_PAGES - set by DispDrvr
  245. The miniport should simply call VideoPortUnlockPages() with the appropriate
  246. PDMA.
  247. Locking memory
  248. The video port must lock down the memory in order to perform dma. The
  249. amount of memory locked down is restricted by three things:
  250. 1) Maximal number of physical page breaks supported by the driver.
  251. This is strictly a function of the dma hardware.
  252. 2) The number of map registers the system has available at
  253. initialization. This is usually not bounded for busmaster devices,
  254. except by that indicated by HalGetAdapter().
  255. 3) System performance contraints. In order to provide reasonable
  256. throughput for other parts of the system, the amount of memory the
  257. video port allows to be locked down is currently set as follows:
  258. a) small systems (12-16 meg) 256k
  259. b) medium systems (16-31 meg) 512k
  260. c) large systems (>32 meg) 1M
  261. These default values can be overridden by setting MaxDmaSize value under the
  262. Devicexxx key in the CurrentControlSet in the registry. Again, drivers which
  263. leave more than these amounts of memory locked down can severely impact system
  264. performance.
  265. Examples:
  266. from a miniport StartIo routine (note that the display driver formatting
  267. is unique to the display driver):
  268. case IOCTL_VIDEO_DMA_INIT:
  269. {
  270. //
  271. // This IOCTL should only be used for buffers that may remained locked
  272. // down for more than one dma transfer.
  273. //
  274. //
  275. // Map display driver representation into video port. Display
  276. // driver input buffer is of form
  277. //
  278. // typedef struct _DMA_CONTROL
  279. // {
  280. // void * pBitmap; // Pointer to memory
  281. // // to be locked.
  282. // ULONG ulSize; // size of memory to
  283. // // be locked.
  284. // PVOID pDma; // Dma handle [OUT].
  285. // PVOID * pPhysAddr; // Location to put
  286. // // Physaddr.
  287. // PEVENT pDisplayEvent // PEVENT.
  288. // PEVENT pMappedUserEvent// Mapped User Mode EVENT
  289. // // handle.
  290. // } DMA_CONTROL, *PDMA_CONTROL;
  291. //
  292. //
  293. //
  294. //
  295. PDMA_CONTROL pDmaCtrl = (PDMA_CONTROL) RequestPacket->InputBuffer;
  296. PUCHAR ptmp = pDmaCrtl->bitmap;
  297. ULONG size = pDmaCrtl->size;
  298. VideoDebugPrint(( 0,"\t InputBuffer:%x\n", ptmp));
  299. VideoDebugPrint(( 0,"\t InputBufferLength:%x\n", size));
  300. //
  301. // Save the location to put physaddr.
  302. //
  303. busAddress = (PULONG)(pDmaCtrl->pPhysAddr);
  304. RequestPacket->InputBuffer = ptmp;
  305. RequestPacket->InputBufferLength = size;
  306. if (RequestPacket->OutputBufferLength <
  307. (RequestPacket->StatusBlock->Information =
  308. sizeof(ULONG) )) {
  309. VideoDebugPrint((0, "IOCTL_VIDEO_DMA_INIT error1\n"));
  310. status = ERROR_INSUFFICIENT_BUFFER;
  311. break;
  312. }
  313. if (!VideoPortLockPages(HwDeviceExtension,
  314. RequestPacket,
  315. pMappedUserEvent,
  316. pDisplayEvent,
  317. VideoPortDmaInitOnly))
  318. {
  319. RequestPacket->StatusBlock->Information = 0;
  320. VideoDebugPrint((0, "IOCTL_VIDEO_DMA_INIT error2\n"));
  321. status = ERROR_INSUFFICIENT_BUFFER;
  322. }
  323. else
  324. {
  325. //
  326. // Have to extract Physical address from scatterlist via DMA context in
  327. // OutputBuffer and put it back into OutputBuffer.
  328. //
  329. PVOID * ppDmaHandle = (PVOID *)(RequestPacket->OutputBuffer);
  330. PVRB_SG pSG = GET_VIDEO_SCATTERGATHER((PULONG)ppDmaHandle);
  331. ULONG physaddr;
  332. pDmaCrtl->DmaHandle = *ppDmaHandle;
  333. hwDeviceExtension->IoBufferSize = size;
  334. hwDeviceExtension->IoBuffer = ptmp;
  335. GET_VIDEO_PHYSICAL_ADDRESS(pSG, ptmp, ptmp, &size, physaddr);
  336. *busAddress = physaddr;
  337. status = NO_ERROR;
  338. }
  339. break;
  340. }
  341. case IOCTL_VIDEO_DMA_TRANSFER:
  342. //
  343. // This IOCTL is optimized so that the display driver can get a buffer locked,
  344. // dmaed and unlocked in one IOCTL.
  345. //
  346. {
  347. PDSP_DMA_ARGS pDSPDmaArgs = (PDSP_DMA_ARGS)RequestPacket->InputBuffer;
  348. PDSP_DMA pDSPDma = pDSPDmaArgs->pDmaControl;
  349. PUCHAR ptmp = pDSPDma ->bitmap;
  350. ULONG size = pDSPDma ->size;
  351. if (RequestPacket->InputBufferLength < sizeof(DSP_DMA_ARGS)) {
  352. VideoDebugPrint(( 2,"\n Insufficient Buffer" ));
  353. status = ERROR_INSUFFICIENT_BUFFER;
  354. break;
  355. }
  356. RequestPacket->InputBuffer = ptmp;
  357. RequestPacket->InputBufferLength = size;
  358. ASSERT(pDSPDma);
  359. if (RequestPacket->OutputBufferLength <
  360. (RequestPacket->StatusBlock->Information =
  361. sizeof(ULONG) )) {
  362. VideoDebugPrint((0, "IOCTL_VIDEO_DMA_INIT error1\n"));
  363. status = ERROR_INSUFFICIENT_BUFFER;
  364. break;
  365. }
  366. hwDeviceExtension->pDSPDmaArgs = pDSPDmaArgs;
  367. if (!VideoPortLockPages(HwDeviceExtension,
  368. RequestPacket,
  369. pDSPDma->pMappedUserEvent,
  370. pDSPDma->pDisplayEvent,
  371. VideoPortUnlockAfterDma))
  372. {
  373. RequestPacket->StatusBlock->Information = 0;
  374. VideoDebugPrint((0, "IOCTL_VIDEO_DMA_TRANSFER error\n"));
  375. status = ERROR_INSUFFICIENT_BUFFER;
  376. }
  377. else
  378. status = NO_ERROR;
  379. break;
  380. }
  381. case IOCTL_VIDEO_DMA_UNLOCK:
  382. {
  383. //
  384. // Private cleanup code. The memory has already been unlocked.
  385. // The InputBuffer contains the Dma Handle.
  386. //
  387. PDMA pDma = *(PDMA*) (RequestPacket->InputBuffer);
  388. VideoPortUnlockPages(HwDeviceExtension, pDma);
  389. break;
  390. }
  391. 2) Display driver code.
  392. DISPDBG((1, "Target, DmaControl.pBitmap:%x, DmaControl.ulSize:%x\n", DmaControl.pBitmap, DmaControl.ulSize));
  393. //
  394. // Ask the miniport to lock the pages needed for this DMA, do the dma and unlock them.
  395. //
  396. DSPDmaArgs.pDma = (PVOID)DmaHandle;
  397. DSPDmaArgs.DmaBase = ptrgBase;
  398. DSPDmaArgs.WidthTrg = widthTrg;
  399. DSPDmaArgs.WidthSrc = widthSrc;
  400. DSPDmaArgs.width__ = width * DSPSRCPIXELBYTES;
  401. DSPDmaArgs.Height = height;
  402. DSPDmaArgs.Offset = ulOffset;
  403. DSPDmaArgs.pPhysAddr = pPCIAddress;
  404. DSPDmaArgs.bitdepth = DSPSRCPIXELBITS;
  405. DSPDmaArgs.HS = TRUE;
  406. DSPDmaArgs.pDmaControl = &DmaControl;
  407. if (EngDeviceIoControl(ppdev->hDriver,
  408. IOCTL_VIDEO_DMA_TRANSFER,
  409. &DSPDmaArgs,
  410. sizeof(DSPDmaArgs),
  411. &(DSPDmaArgs.pDma),
  412. sizeof(DSPDmaArgs.pDma),
  413. &returnedDataLength))
  414. {
  415. DISPDBG((0, "DSP.DLL!MSDMA - EngDeviceIoControl IOCTL_VIDEO_DMA_TRANSFER Error!!!\n"));
  416. DISPDBG((0, "DSP.DLL!vBitbltHSDMA - Exit\n"));
  417. return;
  418. }
  419. The requirements for these interfaces include:
  420. 1) In the PVIDEO_HW_INITIALIZATION_DATA, the following fields need to be filled:
  421. PVIDEO_HW_START_DMA HwStartDma - a pointer to a function which can be
  422. called when page locking is complete. This function returns
  423. Dma_Async_Return if it returns before the transfer is complete or
  424. Dma_Sync_Return if it returns after the transfer is complete.
  425. These return values are typedefed in video.h. This function takes
  426. as arguments:
  427. a) pHwDeviceExtension - a pointer to a miniport device
  428. extension.
  429. b) a dma handle returned from a IOCTL_VIDEO_DMA_INIT or
  430. IOCTL_VIDEO_DMA_TRANSFER call.
  431. c) a PEVENT which is the user Event mapped into kernel mode.
  432. (NULL if pMappedUserEvent is NULL).
  433. d) pDisplayEvent - a PEVENT, intended to be created and
  434. waited on by the DisplayDriver and set by the miniport.
  435. e) another PEVENT which must be set if the routine returns
  436. Dma_Async_Return when the DMA completes. Failure to set
  437. this PEVENT may invalidate the scatter gather lists at
  438. any time. It must be set by:
  439. VideoPortSetEvent(HwDeviceExtension, pVPEvent);
  440. Also, HwDeviceExtension should make a copy of the elements of the
  441. irp it intends to use or pass on, as the irp will be completed when
  442. HwStartDma returns, and hence it's fields will be invalidated.
  443. 2) In the PORT_CONFIG_INFO, the following fields need to be
  444. filled:
  445. ULONG DmaChannel - a value indicating if the device supports
  446. DMA.
  447. ULONG DmaPort - a value indicating if the device supports
  448. microchannel DMA.
  449. ULONG NumberOfPhysicalBreaks - a value indicating the
  450. maximal number of physical breaks the device supports.
  451. DMA_WIDTH DmaWidth - a value indicating the width of the dma
  452. device.
  453. DMA_SPEED DmaSpeed - a value indicating the specified transfer
  454. speed.
  455. BOOLEAN DemandMode - a BOOLEAN indicating that the device can
  456. be programmed for demand mode rather than single cycle operations.
  457. BOOLEAN bMapBuffers- a BOOLEAN indicating if an adapter
  458. requires that the data buffers be mapped into virtual address space.
  459. BOOLEAN NeedPhysicalAddresses - a BOOLEAN indicating that the
  460. driver will need to translate virtual to physical addresses.
  461. BOOLEAN ScatterGather - a BOOLEAN indicating that the
  462. driver will support scatter gather.
  463. BOOLEAN Master - a BOOLEAN indicating that the adapter
  464. is a bus master. Again, currently required to be TRUE.
  465. ULONG MaximumScatterGatherChunkSize - the largest contiguous
  466. piece of memory the dma controller can handle. This value is zero
  467. if and only if the size is unbounded.