Re: bus_dma question

From: Julian Elischer <julian_at_elischer.org>
Date: Wed, 15 Dec 2004 14:59:10 -0800
Scott this is just what I was looking for.

This should be added to the busdma man page I think..


Scott Long wrote:

> Julian Elischer wrote:
>
>>
>> The bus_dma man page is good. but it there documentation of how to 
>> extract the physical page addresses from a map? In other words, if I 
>> defien a tag for a device and then create a map using 
>> bus_dmamap_create, and then load it using bus_dmamap_load, what is 
>> the recommended method of extracting the list of addresses to feed 
>> into a DMA scatter_gather list? Looking at various drivers I'm 
>> getting more and more confused.. There is  a lot of home-grown s/g list
>> generation code out there.. is there a "right" way to do this?
>>
>
> The function pointer that you provide to bus_dmamap_load() is called
> when the S/G map is ready (it might be deferred due to needing bounce
> pages, so you cannot assume that it will be called before 
> bus_dmamap_load() returns).  The S/G list and length is provided in
> the arguments to the callback function.  So:
>
> static void
> my_start(my_softc, my_data_ptr, my_data_len)
> {
>     /* Prepare resources for sending data to the hardware */
>     [...]
>
>     /*
>      * Hand off to busdma to generate the S/G list.
>      */
>     error = bus_dmamap_load(my_softc->dmat, my_softc->dmamap,
>         my_data_ptr, my_data_len, my_callback_func, my_softc, 0);
>     if (error == EINPROGRESS) {
>         /*
>          * The callback will be called later.  Don't queue up
>          * any more commands until it has so that we don't spin
>          * on busdma.
>          */
>         my_softc->flags |= FROZEN;
>     }
>
>     return;
> }
>
> static void
> my_callack_func(void *arg, bus_dma_segment_t *segs, int nseg, int error)
> {
>     my_softc_t *my_softc = arg;
>
>     if (error) {
>         /* Handle error */
>         [...]
>         return;
>
>     for (i = 0; i < nsegs; i++) {
>         my_sg[i].phys = segs[i].ds_addr;
>         mg_sg[i].len = segs[i].ds_len;
>     }
>
>     if (dma is from host memory to the hardware)
>     bus_dmamap_sync(my_dmat, my_dmamap, BUS_DMASYNC_PREWRITE);
>
>     if (dma is from the hardware to host memory)
>     bus_dmamap_sync(my_dmat, my_dmamap, BUS_DMASYNC_PREREAD);
>
>     /*
>      * Send S/G list to the hardware and tell the hardware to start
>      * the transaction.
>      */
>     [...]
>
>     return;
> }
>
> Note that you cannot pass an error value or anything else from the 
> callback function to the caller since you have no control over when
> the callback will actually be called.  Well, if you use the 
> BUS_DMA_NOWAIT flag for bus_dmamap_load(), you'll be guaranteed to get
> an error back instead of a deferral, but that should only be used with
> great care.
>
> Also, don't forget to call bus_dmamap_sync() with the POSTREAD and 
> POSTWRITE ops once the transaction is complete.  This is very important
> now that >4GB of memory is easy to aquire; devices like UHCI and ATA can
> still only do 32bit S/G lists, so bouncing is required on i386 and
> amd64.  You also need to do a bus_dmamap_unload() call to free whatever
> busdma resources were used for the transaction, so the sequence should
> be something like:
>
> static void
> my_intr(void *arg)
> {
>     /* Check and handle interrupt */
>     [...]
>
>     /* return busdma resources */
>     if (dma is from host memory to the hardware)
>     bus_dmamap_sync(my_dmat, my_dmamap, BUS_DMASYNC_POSTWRITE);
>
>     if (dma is from the hardware to host memory)
>     bus_dmamap_sync(my_dmat, my_dmamap, BUS_DMASYNC_POSTREAD);
>
>     bus_dmamap_unload(my_dmat, my_dmamap);
>
>     /* Process the data that was DMA'd */
>     [...]
>
>     return;
> }
>
> There will likely be changes to the busdma API for 6.0 that will
> simplify this a bit, make it faster, and make it resemble NetBSD a
> little more, but I'm still working on them.
>
> Scott
Received on Wed Dec 15 2004 - 21:59:11 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:24 UTC