How to detect if memory is contiguous

I have a device that can perform SG DMA. The device transfers images to the
user application. A typical image might be 640 pixels wide by 480 lines
long. This device will transfer each line (640 bytes) as a DMA operation.
Each entry in the SG list must be 640 bytes (or more) in size. If it is
more then the extra amount must be equal for each line. This restriction is
relaxed if the memory is contiguous (which it is when the memory comes from
a video card). When the user calls the driver they will pass either a
system memory address or a video card memory address.

For system memory, to meet the requirements of the device, the user can over
allocate and then align the memory that is passed to the driver so that each
line is on a 1K boundary (wasting 384 bytes per line). For video card
memory, this over allocation isn’t desired since there may not be enough
video memory to do this.

I can instruct the user on how to pass the memory to the driver but how can
I detect that if the memory is not properly aligned then it is contiguous.
I suppose I could look at the MDL describing the memory but this is supposed
to be an opaque structure. Or I can create the SG list and verify that each
line fits completely within the PHYSICAL_ADDRESS returned by
GetScatterGatherList or MapTransfer. However, this means that I need to
detect this during or after building the SG list and then fail the IRP in
the AdapterControl function (and don’t actually perform the DMA operation).
This seems like it might work (although it is somewhat inefficient since I
have to create the SG list, test it and if it fails, free the list, free the
map registers and then fail the IRP).

Is there any other way to detect if memory is contiguous or some other
solution to this problem?

  • Steve -

> For system memory, to meet the requirements of the device, the user
can over

allocate and then align the memory that is passed to the driver so
that each
line is on a 1K boundary (wasting 384 bytes per line).

For what?
Why not allow unaligned lines? Or the line must not cross the page
boundary, to avoid it being splitted to 2 different physical pages?

If second - then, after MapTransfer, check the lines which are broken
this way, and allocate the common buffer chunks for them with double
buffering - for them only, not for all lines.

Also - DMA to video memory is problematic if you have non-overlay
non-fullscreen DirectDraw surface. For such a surface, pitch != width.
Pitch is screen pitch, while width is 640.

Max

> > For system memory, to meet the requirements of the device, the user

can over
> allocate and then align the memory that is passed to the driver so
that each
> line is on a 1K boundary (wasting 384 bytes per line).

For what?
Why not allow unaligned lines? Or the line must not cross the page
boundary, to avoid it being splitted to 2 different physical pages?

The main issue is that each descriptor is an address only. The descriptor
length is global to all descriptors. I could have computed the GCD such
that all descriptors would be the same length but this could degenerate to a
very small number which would make for very inefficient DMA.

If second - then, after MapTransfer, check the lines which are broken
this way, and allocate the common buffer chunks for them with double
buffering - for them only, not for all lines.

I don’t believe this will work because of the descriptor length restriction.
Since the device is a special purpose device and we have a layer of software
that our users must uses to access the hardware, having the alignment
restriction isn’t too bad since we can hide it from the user. For another
device we did double buffering and the performance impact is a little too
high. The primary reason I want to detect the alignment/contiguousness is
to catch bugs in our code or cases where our users code has bugs that cause
our code’s data to become corrupted which results in an invalid request to
the driver.

Also - DMA to video memory is problematic if you have non-overlay
non-fullscreen DirectDraw surface. For such a surface, pitch != width.
Pitch is screen pitch, while width is 640.

It is true that pitch might not be equal to width but I believe that the
physical memory is a contiguous block (at least in all the cases I’ve seen)
so crossing a page boundary isn’t an issue. However, the driver doesn’t
know where the memory came from so the contiguous test would be applied even
when the memory comes from a DirectDraw surface.

  • Steve -

> > If second - then, after MapTransfer, check the lines which are
broken

> this way, and allocate the common buffer chunks for them with
double
> buffering - for them only, not for all lines.

I don’t believe this will work because of the descriptor length
restriction.

Why not? The “replacement” chunks can be allocated of this constant
descriptor length.

Max