tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Am I using bus_dma right?



>> 		while (fewer than n samples copied)
>> 			DMASYNC_POSTREAD for sample at offset o
> That should be PREREAD (to make sure the dma'd data is visible for
> the cpu)
>> 			read sample at offset o
> and teh POSTREAD should be here

>> 			if value is "impossible", break
> missig PREWRITE here
>> 			set sample at offset o to "impossible" value
>> 			DMASYNC_PREWRITE for sample at offset o
> and this should be POSTWRITE

> See the example in the -current man page:

This looks a lot like the example in the 8.0 manpage, which did not
help much because my use case does not match its very well:

>               An example of using bus_dmamap_sync(), involving
>               multiple read-write use of a single mapping might look
>               like this:

I'm not doing read/write DMA.  DMA never transfers from memory to the
device.  (Well, I suppose it does to a small extent, in that the device
reads buffer descriptors.  But the buffer descriptors are set up once
and never touched afterwards; the code snippet I posted is not writing
to them.)

The hardware is DMAing into the memory, and nothing else.  The driver
reads the memory and immediately writes it again, to be read by the
driver some later time, possibly being overwritten by DMA in between.
So an example that says "do write DMA" is not directly applicable.

The example makes it look as though read DMA (device->memory) needs to
be bracketed by PREREAD and POSTREAD and write DMA by PREWRITE and
POSTWRITE.  If that were what I'm doing, it would be straightforward.
Instead, I have DMA and the driver both writing memory, but only the
driver ever reading it.

Your placement for PREREAD and POSTREAD confuses me because it doesn't
match the example.  The example says

	/* invalidate soon-to-be-stale cache blocks */
	bus_dmamap_sync(..., BUS_DMASYNC_PREREAD);
	[ do read DMA ]
	/* copy from bounce */
	bus_dmamap_sync(..., BUS_DMASYNC_POSTREAD);
	/* read data now in driver-provided buffer */
	[ computation ]
	/* data to be written now in driver-provided buffer */
	/* flush write buffers and writeback, copy to bounce */
	bus_dmamap_sync(..., BUS_DMASYNC_PREWRITE);
	[ do write DMA ]
	/* probably a no-op, but provided for consistency */
	bus_dmamap_sync(..., BUS_DMASYNC_POSTWRITE);

but what your changes would have my driver doing is

[read-direction DMA might happen here]
PREREAD
driver reads data from driver-provided buffer
POSTREAD
[read-direction DMA might happen here]
PREWRITE
driver writes data to driver-provided buffer
POSTWRITE
[read-direction DMA might happen here]

The conceptual paradigm is

- at attach time: allocate, set up, and load the mapping

- at open time: tell hardware to start DMAing

- at read time (ie, repeatedly): driver reads buffer to see how much
   has been overwritten by DMA, copying the overwritten portion out and
   immediately resetting it to the pre-overwrite data, to be
   overwritten again later

- at close tiem: tell hardware to stop DMAing

The map is never unloaded; the driver is not detachable.  The system
has no use case for that, so I saw no point in putting time into it.

The code I quoted is the "at read time" part.  My guess based on the
manpage's example and what you've written is that I need

	while (fewer than n samples copied)
		POSTWRITE
		POSTREAD
		read sample from buffer
		if sample isn't "impossible"
			write "impossible" value to buffer
			PREWRITE
		PREREAD
		if sample is "impossible", break

because some aspects of "write", and relatively normal "read", are
happening outside that code segment.  But this is different enough from
what you said (and possibly not well-paired - should the PREWRITE be
outside the if?) that now I'm possibly even less sure of myself.  I
could just try different permutations in the hope of finding something
that works, but that strikes me as one of the worst possible ways to do
it; I would prefer to understand the paradigm enough to get it right.

I am not concerned about the race between pushing the driver-written
value to the buffer and DMA overwriting it; provided the driver's write
gets pushed reasonably promptly, this will happen only in error
conditions like userland ignoring the device for too long - it takes
the hardware multiple seconds to wrap around the ring buffer.

> I always have to look up the direction, but READ is when CPU reads
> data provided by the device.

Yes: READ corresponds to read() and WRITE to write().  One of the
things that confuses me is that I have no write-direction DMA going on
at all; all the DMA is in the read direction.  But there is a driver
write to the buffer that is, to put it loosely, half of a write DMA
operation (the "host writes the buffer" half).

/~\ The ASCII				  Mouse
\ / Ribbon Campaign
 X  Against HTML		mouse%rodents-montreal.org@localhost
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Home | Main Index | Thread Index | Old Index