Wrapper API for static bus_dma allocations

John Baldwin jhb at freebsd.org
Tue Mar 22 17:45:28 UTC 2016


On Friday, February 26, 2016 05:10:53 PM John Baldwin wrote:
> On Thursday, January 29, 2015 03:37:19 PM John Baldwin wrote:
> > The bus_dma API to allocate a chunk of static DMA'able memory (e.g. for 
> > descriptor rings) can be a bit obtuse to use in that it require a bit of 
> > boilerplate to create a tag, allocate memory for the tag, then load it to get 
> > the bus address.  Similarly, freeing it also requires several steps.  In 
> > addition, some of the steps are a bit subtle (e.g. the need to check for an 
> > error in the bus_dma callback instead of from bus_dmamap_load()) and not all 
> > drivers get those correct.
> > 
> > To try to make this simpler I've written a little wrapper API that tries to 
> > provide a single call to allocate a buffer and a single call to free a buffer.  
> > Each buffer is described by a structure defined by the API, and if the call to 
> > allocate a buffer succeeds, the structure contains both a pointer to the 
> > buffer in the kernel's address space as well as a bus address of the buffer.
> > 
> > In the interests of simplicity, this API does not allow the buffer to be quite 
> > as fully configured as the underlying bus_dma API, instead it aims to handle 
> > the most common cases that are used in most drivers.  As such, it assumes that 
> > the buffer must be one contiguous range of DMA address space, and the only
> > parameters that can be specified are the parent tag, the alignment of the 
> > buffer, the lowaddr parameter, the size of the buffer to allocate, and the 
> > flags parameter that is normally passed to bus_dmamem_alloc().  I believe that 
> > this should be sufficient to cover the vast majority of the drivers in our 
> > tree.

After some more thinking, I've altered this API to include an 'args' struct
similar to the one Konstantin used for make_dev_s() to specify constraints.
This would permit most constraints to be specified on an as-needed basis
without requiring all of them each time.  It does still assume 1 contiguous
region, but the majority of our drivers require that anyway.

I've forward ported this and converted a more typical driver (xl(4)) as a
demo of the new API.  You can find the full diff here:

https://reviews.freebsd.org/D5704

(I've not yet written manpage updates)

Here's the new code in xl(4) to allocate the TX and RX rings.  I think it
highlights the specific constraints (alignment, etc.) more clearly than the
previous version:

	​        /*
	​         * Now allocate a chunk of DMA-able memory for the DMA
	​         * descriptor lists.  All of our lists are allocated as a
	​         * contiguous block of memory.
	​         */
	​        bus_dma_mem_args_init(&args);
	​        args.dma_alignment = 8;
	​        args.dma_lowaddr = BUS_SPACE_MAXADDR_32BIT;
	​        error = bus_dma_mem_alloc(bus_get_dma_tag(dev), XL_RX_LIST_SZ, 0, &args,
	​            &sc->xl_ldata.xl_rx_ring);
	​        if (error) {
	​                device_printf(dev, "failed to allocate rx ring\n");
	​                goto fail;
	​        }
	​        sc->xl_ldata.xl_rx_list = sc->xl_ldata.xl_rx_ring.dma_vaddr;
	​
	​        error = bus_dma_mem_alloc(bus_get_dma_tag(dev), XL_TX_LIST_SZ, 0, &args,
	​            &sc->xl_ldata.xl_tx_ring);
	​        if (error) {
	​                device_printf(dev, "failed to allocate tx ring\n");
	​                goto fail;
	​        }
	​        sc->xl_ldata.xl_tx_list = sc->xl_ldata.xl_tx_ring.dma_vaddr;
​

-- 
John Baldwin


More information about the freebsd-arch mailing list