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. > > ScottReceived 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