Technical Document #3

Technical Document #3        [Product Version: 11.1.0 and above]
Preallocating contiguous DMA buffers on Windows

The WinDriver DMA APIs do not limit the size of allocated DMA buffers. However, the success of the DMA allocation is dependent on the amount of available system resources at the time of the allocation. Therefore, the earlier you try to allocate the buffer, the better your chances of succeeding.
Beginning with version 11.1.0 of WinDriver for Windows, you can configure your device INF file to preallocate at boot time a contiguous host-to-device DMA buffer and/or a device-to-host DMA buffer, thus increasing the odds that the allocation(s) will succeed. Beginning with version 11.4.0 of WinDriver for Windows, you can, alternatively, configure the device INF file to preallocate up to two bidirectional DMA buffers at boot time.

NOTE
You may currently preallocate a maximum of either two unidirectional buffers — one host-to-device buffer and/or one device-to-host buffer — or two bidirectional buffers.

To preallocate contiguous DMA buffers on Windows, follow these steps:

  1. Add the required configuration under the [UpdateRegistryDevice] registry key in your device INF file, as shown below.
    NOTE
    • The examples are for configuring preallocation of two DMA buffers (either unidirectional or bidirectional), but you may, of-course, select to preallocate just one buffer (or none at all).
    • The wizard-generated and relevant sample WinDriver device INF files already contain the unidirectional buffers configuration lines, so you only need to remove the comment indicator (';') at the start of each line. For bidirectional buffers, you should also edit the title comments and DMA direction flag (see below).

    • To preallocate unidirectional buffers, add these lines:
      ; Host-to-device DMA buffer:
      HKR,, "DmaToDeviceBytes",0x00010001,0x100000   ; Buffer size, in bytes
      HKR,, "DmaToDeviceOptions",0x00010001,0x41     ; DMA flags (0x40=DMA_TO_DEVICE
                                                     ; + 0x1=DMA_KERNEL_BUFFER_ALLOC)
                      
      ; Device-to-host DMA buffer:
      HKR,, "DmaFromDeviceBytes",0x00010001,0x100000 ; Buffer size, in bytes
      HKR,, "DmaFromDeviceOptions",0x00010001,0x21   ; DMA flags (0x20=DMA_FROM_DEVICE
                                                     ; + 0x1=DMA_KERNEL_BUFFER_ALLOC)
    • To preallocate bidirectional buffers, add these lines:
      ; Bidirectional DMA buffer:
      HKR,, "DmaToDeviceBytes",0x00010001,0x100000   ; Buffer size, in bytes
      HKR,, "DmaToDeviceOptions",0x00010001,0x61     ; DMA flags (0x60=DMA_TO_FROM_DEVICE
                                                     ; + 0x1=DMA_KERNEL_BUFFER_ALLOC)
                      
      ; Second Bidirectional DMA buffer:
      HKR,, "DmaFromDeviceBytes",0x00010001,0x100000 ; Buffer size, in bytes
      HKR,, "DmaFromDeviceOptions",0x00010001,0x61   ; DMA flags (0x60=DMA_TO_FROM_DEVICE
                                                     ; + 0x1=DMA_KERNEL_BUFFER_ALLOC)
      NOTE
      The INF-file configuration for bidirectional buffers uses the same registry keys as for unidirectional buffers (DmaToDeviceXXX and DmaFromDeviceXXX), but the DMA-options key value (DmaToDeviceOptions / DmaFromDeviceOptions) should contain the DMA_TO_FROM_DEVICE flag (0x60) instead of the unidirectional DMA_TO_DEVICE (0x40) or DMA_FROM_DEVICE (0x20) flag, as shown above.

  2. Edit the buffer sizes and add flags to the options masks in the INF file, as needed.
    Note, however, that the direction flags and the DMA_KERNEL_BUFFER_ALLOC flag must be set as shown in Step 1.
    NOTE
    The supported WinDriver DMA flags are documented in the WinDriver PCI User's Manual. To locate the relevant flag values to set in the INF file, look for the flag definitions in the <WinDriver directory>\include\windrvr.h file; (look for the enum that contains the DMA_KERNEL_BUFFER_ALLOC flag).

  3. In your code, the first call or the first two calls (if you configured the INF file to preallocate two DMA buffers) to the contiguous-DMA-lock function — WDC_DMAContigBufLock() or the low-level WD_DMALock() function — should set parameter values that match the buffer configurations in the INF file:

    • For a device-to-host buffer or the first allocation of a bidirectional buffer, the DMA-options mask parameter (dwOptions / pDma->dwOptions) should contain the same DMA flags set in the DmaFromDeviceOptions registry key value, and the buffer-size parameter (dwDMABufSize / pDma->dwBytes) should be set to the value of the DmaFromDeviceBytes registry key value.

    • For a host-to-device buffer or the second allocation of a bidirectional buffer, the DMA-options mask parameter (dwOptions / pDma->dwOptions) should contain the same flags set in the DmaToDeviceOptions registry key value, and the buffer-size parameter (dwDMABufSize / pDma->dwBytes) should be set to the value of the DmaToDeviceBytes registry key value.
    NOTE
    • In calls to WDC_DMAContigBufLock(), the DMA configuration information is provided via dedicated function parameters — dwDMABufSize and dwOptions.
      In calls to WD_DMALock(), the information is provided within the fields of the WD_DMA struct pointed to by the pDma parameter — pDma->dwBytes and pDma->dwOptions.

    • When using WDC_DMAContigBufLock(), the DMA_KERNEL_BUFFER_ALLOC flag is automatically set by the function, so you do not need to set it explicitly in the DMA-options mask parameter (as you do when using the low-level WD_DMALock() function), even though it is set in the INF-file configuration.

    • If the buffer preallocation fails due to insufficient resources, you may need to increase the size of the non-paged pool (from which the memory is allocated), as explained in Technical Document #58.