Split up of scatter/gather lists

How is WDF splitting up scatter/gather lists.
I have created a common buffer that is large enough to hold the largest number of scatter/gather entries that can be sent to the driver.
The maximum transfer length of the dma enabler is set to the largest buffer that can be sent to the driver.
However, I have noticed, that even when sending smaller buffers, the scatter/gather lists are now and then split up in 2 or more parts (several calls to vkEvtDmaTransferSGList).
Below is the code used to setup the DMA (note: this code is placed in different places in the code; see ellipsis).
Is this split-up normal behaviour? Can I force to only generate 1 list?

Thanks /Kurt

WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig, WdfDmaProfileScatterGather64Duplex, pDevExt->maximumTransferLength);
status = WdfDmaEnablerCreate(pDevExt->device, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevExt->dmaEnabler);
pDevExt->commonBufferSize = sizeof(DMA_TRANSFER_ELEMENT) * DevExt->transferElements;
status = WdfCommonBufferCreate( pDevExt->dmaEnabler,
pDevExt->commonBufferSize,
WDF_NO_OBJECT_ATTRIBUTES,
&pDevExt->commonBuffer);

status = WdfDmaTransactionCreate( pDevExt->dmaEnabler,
&attributes,
&pDevExt->dmaTransaction);

status = WdfDmaTransactionInitialize( pDevExtension->dmaTransaction,
vkEvtDmaTransferSGList,
wdfDmaDirectionWriteToDevice,
pBuffer->mdl,
pBuffer->address,
pBuffer->size
);

status = WdfDmaTransactionExecute(pDevExtension->dmaTransaction, WDF_NO_CONTEXT);

Another question came to my mind:
should I use MmGetMdlByteCount() for the last parameter to WdfDmaTransactionInitialize() or can I use the user supplied size of the buffer? Can this make a difference on the number of times WdfDmaTransactionInitialize calls the EvtProgramDmaFunction?

MmGetMdlByteCount, but that is not likely to be your problem. If your IO is
originating from a user mode request you should be using
WdfDmaTransactionInitializeUsingRequest instead of having to bother with any
of this. Also I have no idea why your transactions are being split up into
two SGLs instead of one, other than the obvious reason that the original
request was too large for one transaction.

On Sat, Apr 19, 2008 at 10:57 AM, wrote:

> Another question came to my mind:
> should I use MmGetMdlByteCount() for the last parameter to
> WdfDmaTransactionInitialize() or can I use the user supplied size of the
> buffer? Can this make a difference on the number of times
> WdfDmaTransactionInitialize calls the EvtProgramDmaFunction?
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy

WdfDmaTransactionInitializeUsingRequest is not an option, because the IOCLT receives a pointer to a struct containing a.o. a pointer to a user allocated buffer. For the same buffer, sometimes EvtProgramDmaFunction is called only once, and some times more than once, with the common buffer size and transfer size being equal.
User application code skeleton:
p = Allocate buffer
struct s = { p, sizeof p, flags }
while (true)
{
deviceioctl(…, &s, sizeof(s));
}

The driver locks the user memory, retrieves the mdl, executes a DMA transaction and unlocks the buffer. The user supplied buffer is smaller than the maximum transfer size; the common buffer is large enough to store number_of_pages(maximum buffer size).
Even if the buffer wouldn’t be large enough, it still doesn’ t explain why a transaction sometimes only transmits only 1 page (e.g. for a total of 1000 pages, I often see the transfer being split up in 990 pages, 8 pages, 2 pages).
Any idea what the logic behind all this is?

Your use of the term pages is confusing. A single SGL is a collection of
SGEs with each SGE describing one contiguous run of physical memory -
described in bytes, not pages. The whole point of the SGL is to describe
multiple physical runs in one data structure. I thought your problem was
that you didn’t expect more than one SGL in one callback to your *EvtProgramDma
*routine per IO request but instead you sometimes (always?) are getting more
than one. If that is what you are still talking about (990 pages translates
to one SGL describing 990 pages of data in N SGEs) I still don’t have an
explanation. However, there is no guarantee that I see anywhere in the docs
indicating that you will not get multiple callbacks for one DMA transaction,
and in fact this certainly can happen if your device requires map registers
on the platform it is running on. You have to code for multiple callbacks.

On Sat, Apr 19, 2008 at 2:21 PM, wrote:

> WdfDmaTransactionInitializeUsingRequest is not an option, because the
> IOCLT receives a pointer to a struct containing a.o. a pointer to a user
> allocated buffer. For the same buffer, sometimes EvtProgramDmaFunction is
> called only once, and some times more than once, with the common buffer size
> and transfer size being equal.
> User application code skeleton:
> p = Allocate buffer
> struct s = { p, sizeof p, flags }
> while (true)
> {
> deviceioctl(…, &s, sizeof(s));
> }
>
> The driver locks the user memory, retrieves the mdl, executes a DMA
> transaction and unlocks the buffer. The user supplied buffer is smaller than
> the maximum transfer size; the common buffer is large enough to store
> number_of_pages(maximum buffer size).
> Even if the buffer wouldn’t be large enough, it still doesn’ t explain why
> a transaction sometimes only transmits only 1 page (e.g. for a total of 1000
> pages, I often see the transfer being split up in 990 pages, 8 pages, 2
> pages).
> Any idea what the logic behind all this is?
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy

You’re right Mark, my explanation was unclear. The driver splits up each SGE into pages (4K). So if the SGE indicates it’s 8K, it is split up in two ‘entries’ that are sent to the hardware (the hardware presumes that s/glist entries point to memory of 1 page or less).
The problem is indeed that EvtProgramDma is called more than once (where I expect it to be called only once). The device is a 64-bit PCIe device; the driver is running on XP 64-bit with 4 GB of RAM. So, I assume that map registers are not necessary (is there a way to check this?).
The driver is working with multiple callbacks, but one callback iso multiple could improve performance.
So, I am still curious about the inner workings of WdfDmaTransactionInitialize.