Jason Harmening jason.harmening at gmail.com
Sun Jun 8 05:03:32 UTC 2008


I've written a FreeBSD driver for Conexant CX2388x-based PCI TV capture cards.  
Of course the driver uses busdma to be as machine-independent as possible.  
One problem I've encountered is that bus_dmamem_alloc is inadequate for my 
needs.  The CX2388x only understands 32-bit physical addreses, and the driver 
has two separate use cases for busdma:

1)  Data buffers: These buffers may be relatively large (a 640x480 RGB32 video 
frame is ~1.2M), and therefore it is desirable that these buffers not be 
physically contiguous.

2)  DMA program buffers:  The DMA engine on the CX2388x is controlled by 
special-purpose RISC instructions, usually stored in host memory, that 
provide information on, among other things, the physical layout of the data 
buffers, which enables handling of non-contiguous data buffers.  These 
programs are rarely more than a few pages in size, so for the sake of 
simplicity it is desirable that DMA program buffers be physically contiguous.

For case 1), I malloc(9) the buffers and then feed them to busdma, since on 
most machines bus_dmamem_alloc just calls contigmalloc.  Use of malloc(9) is 
suboptimal as it may result in bounce buffering for non-IOMMU machines with 
large amounts of RAM.

For case 2), I contigmalloc the DMA program buffers in the 32-bit physical 
address range and then feed them to busdma.  I don't use bus_dmamem_alloc 
here because it always allocates the maximum size specified in the 
bus_dma_tag_t.  Since the driver supports dynamic data buffer allocation and 
DMA program generation, DMA program sizes may vary significantly.  I 
therefore just create the bus_dma_tag_t with the maximum possible size for a 
DMA program buffer since I'd prefer not to have to re-create the tag every 
time the DMA program size changes.  But always allocating the maximum buffer 
size would be a huge waste of contiguous memory, so bus_dmamem_alloc is out 
of the question here too.   At the same time, use of contigmalloc is 
suboptimal as it may not be necessary to restrict the allocation to 32-bit 
physical addresses on IOMMU-equipped machines.  This is something that 
bus_dmamem_alloc could take care of, if only it supported a size parameter 
(as I believe the NetBSD version does).

So I have 3 questions:

1)  Would it be possible to provide a bus_dmamem_alloc overload that takes a 
size parameter?   We could call it bus_dmamem_alloc_size and have 
bus_dmamem_alloc just call bus_dmamem_alloc_size with dmat->maxsize to 
preserve source-level compatibility with existing drivers.

2) Are there currently any serious plans to have bus_dmamem_alloc perform 
multi-segment allocations on non-IOMMU machines?  It looks like NetBSD does 
this by reserving the physical segments and then stitching them together into 
a virtually contiguous range.  Is something like this feasible for FreeBSD?

3) Are there currently any serious plans to support IOMMUs on anything besides 
Sun machines?  The AMD AGP GART, PowerPC 970 DART, and Intel VT-d and AMD 
IOMMU all come to mind.

If any of these ideas sound feasible, I'd be more than willing to help 
research/implement/test them.


More information about the freebsd-hackers mailing list