DMA transfer limit

My packet based DMA in my wdf driver is limited to 7K bytes and I don’t know why. I do an IOCTL call for my dma and create the dma with a request. I look at the scatter gather list and I have a single element as I expect. But no matter what size buffer I pass in it will never exceed 7K as far as the scatter gather element length is concerned. Why is this? Is there any way to change this? I printed out my WdfDmaEnablerGetMaximumLength( ); value and it is 0x14000. I tried calling WdfDmaTransactionSetMaximumLength (…, 10000) but that has no visible affect. If I am truly limited to 7K? I see that the Dpc can call my EvtProgramDma again via WdfDmaTransactionDmaCompleted( );. At this point can I just reprogram my device with the values in the scatter gather list(arfe they updated)? Does the Isr only queue another Dpc callback or do I need to worry about creating and deleting new dma transactions?

I answered a related question to one of your previous posts (sorry about the delay- while I’m in the Pacific zone, my working hours resemble the Eastern zone). But you raised some good questions, so…

>My packet based DMA in my wdf driver is limited to 7K bytes and I don’t know why. I do an IOCTL call for my dma and create the dma with a request. I look at the scatter gather list and I have a single element as I expect. But no matter what size buffer I pass in it will never exceed 7K as far as the scatter gather element length is concerned. Why is this? Is there any way to change this? I printed out my WdfDmaEnablerGetMaximumLength( ); value and it is 0x14000. I tried calling WdfDmaTransactionSetMaximumLength (…, 10000) but that has no visible affect. If I am truly limited to 7K?<<

I don’t think you are seeing what you think you are. Remember this is paged virtual memory, and that it has almost always been thrashed quite a bit with things paged in and out all over before you even got to log in.

I don’t know what machine type you’re on, I’ll assume an x86, which has 4KB pages. Your large buffer’s contiguous virtual address range is almost always scattered all over physical memory. If you look at the physical addresses in a transfer (and I’ve had occasion to do so), you usually see a bunch of 1 or 2-page transfers- you can even see a page later in a buffer that physically precedes one earlier in the buffer.

If you are using packet-based DMA, then I believe that what you are seeing is normal- it’s not the result of any software limits, but rather the inevitable hashing up of the physical address space.

I’m actually surprised you even saw as much as 7K- most typically I see a partial initial page, followed by several full-sized pages, and then perhaps a final partial page- each as a separate packet. But it’s been a while since I looked that deeply into it, and I never trust my memory entirely in such cases- multi-page consecutive chunks may be more common than I’m thinking at the moment. If so, someone out there may tell you what an idiot I am [justifiably so]…

If you want to explore this limit issue further, you can do this directly in your driver- use the WDM DDI (or the WdfCommonBufferxxx KMDF DDI) to create a common buffer or allocate contiguous physical memory with WDM. Create a WDFIOTARGET and open your own device with it. Then create a WDFREQUEST and use it send an IOCTL with that buffer’s address to that target [your driver]. You should get multiple packets only when the buffer size exceeds your maximums. If that isn’t the case, I’d certainly want to hear from you about it.

>I see that the Dpc can call my EvtProgramDma again via WdfDmaTransactionDmaCompleted( );. At this point can I just reprogram my device with the values in the scatter gather list(are they updated)?<<

Exactly so- each callback will have the next packet (or set of scatter-gather entries) you need to transfer. We tried to make this model as simple as possible [given the way DMA has to work in all of the varying scenarios]. Follow the recommended usages for these objects, and we handle all the bookkeeping on your behalf- you can concentrate on just programming the hardware. That’s the theory, anyway…

>Does the Isr only queue another Dpc callback or do I need to worry about creating and deleting new dma transactions?<<

You want to keep using the existing transaction object. Again- think of it as an object that does all the bookkeeping for one buffer transfer.

You do not need to delete and recreate the transaction object, either- it is better to just call WdfDmaTransactionRelease when WdfDmaTransactionComplete returns TRUE. You can then call WdfDmaTransactionInitializeWithRequest when the next IOCTL comes along. Handling the objects in this way reduces the amount of memory allocation and freeing you do in your driver, which reduces the number of potential failure points in your processing, and also reduces fragmentation of the kernel memory pool.

Thanks. Everything you said makes sense and now my DMA is working perfectly. I misunderstood how the map registers work. I figured that because they are contiguous the physical address my device would be given would be for the entire transfer and the translation was done behind the scenes for the entire DMA. Everything you explained has been consistent with that which i have seen. I will continue to experiment with DMA because my device claims to have chaining capability but the device is buggy and it may not be feasible. Thanks again for all the help. The WDF makes life alot simpler than the wdm.