Subject: DMA segs and scatter/gather
To: None <tech-kern@netbsd.org>
From: Bruce J.A. Nourish <bjan+tech-kern@bjan.net>
List: tech-kern
Date: 08/21/2003 17:43:26
Hey everyone,

Still working on if_ath.c. I have a question that I've not been able to 
answer by looking at similar code.

According to NetBSD's bus_dma(9), the max number of DMA segments (nseg) 
requested in a call to bus_dmamem_alloc is usually the same as the max 
number of scatter/gather descriptors the device can support. However,
other drivers that use scatter/gather specify an nseg of 1 (see
dev/ic/mlx.c:295); as does other code that I was directed to for 
examples (dev/pci/if_bge.c, dev/pci/hifn7751.c, dev/ic/i82557.c).

Switch gears to FreeBSD code. The hardware in question supports
ATH_MAX_SCATTER descriptors. This number is passed into 
bus_dma_tag_create, as the "maximum number of discontinuities 
(scatter/gather segments)" supported by the device. bus_dmamap_alloc
is now called, with that DMA tag. FreeBSD's dmamap_alloc gets most
of it's parameters by frobbing the DMA tag - so surely it would 
allocate ATH_MAX_SCATTER descriptors?

Now the plot thickens. After the dmamap_alloc, the FreeBSD driver calls
dmamap_load. This function (effectively) returns a pointer to an
array of bus_dma_segment_t's; via the pointer, the driver accesses the
ds_addr of the first bus_dma_segement_t, and saves it into a softc
structure that corresponds to the physical address of the start of
the DMA memory. Essentially, the code _assumes_ there will be only
one segment, as it is not possible to infer the address of one segment
by looking at another (they are discontiguous, by definition). 

Finally, the twist in the tale: FreeBSD's bus_space(9) says that
bus_dma_alloc "will allocate all requests as a single segment [...]
*in the current implementation*." So now we have three possibilities:

 (a) The butler did it. Sam Leffler's code is wrong and will blow up
     in a future version of FreeBSD, when someone changes dmamem_alloc.
 (b) It was the jester. Sam's code uses multiple segments correctly, 
     it's just that I'm to dumb to see how.
 (c) It's the Colonel with the limp. Sam's code uses one segment, and
     does so correctly.

In short, somebody please tell me what I should pass into bus_dmamem_alloc
for nsegs. The code is at http://bjan.net/ath-hacked.c.gz, and the fun
starts at line 1270.

TIA & HAND.
-- 
Bruce J.A. Nourish <bjan+JUNK@bjan.net>