bus_dma_tag_create(9) broken?
Pyun YongHyeon
yongari at kt-is.co.kr
Mon Aug 30 01:40:33 PDT 2004
While checking the possibility of "Trident 4D-Wave NX PCI" sound
card on sparc64, I encountered an unexpected behavior from bus_dma(9).
Since the audio card can't access address ranges larger than 1GB,
I had to reduce possible DMA space with 0x3fffffff. But this
generated an error in bus_dmamem_load(9) so the card couldn't get
proper DMA-capable address.
In i386, it seems that there is no such limitations at all.
(Both BUS_SPACE_MAXADDR_24BIT, 0x3fffffff works OK.)
Anyway the driver snd_t4dwave was broken since it failed to limit
DMA addresses. I wonder how the driver worked on i386/amd64.
In sparc64, is it intended behavior of bus_dma_tag_create(9)?
If this is inherited feature from sparc64 H/W, the Trident audio
card couldn't be supported at all. I guess other drivers that
don't support 32bit DMA addressing such as maestro/maestro3 has
the same issue too.
The attached file is sample code I used.
Regards,
Pyun YongHyeon
--
Pyun YongHyeon <http://www.kr.freebsd.org/~yongari>
-------------- next part --------------
#
.PATH: ${.CURDIR}
KMOD= bus_alloc
SRCS= bus_alloc_test.c
.include <bsd.kmod.mk>
-------------- next part --------------
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/bus.h>
#define ALLOC_SIZE (16*1024)
static int foo_alloc(void);
static void foo_free(void);
bus_dma_tag_t dmat = NULL;
bus_dmamap_t dmamap = 0;
char *vbuf = NULL;
bus_addr_t pbuf = 0;
static void
call_back(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
if (error == 0)
pbuf = segs[0].ds_addr;
else
pbuf = 0;
}
static int
foo_alloc(void)
{
if (bus_dma_tag_create(
NULL,
2,
0,
/*BUS_SPACE_MAXADDR_32BIT,*/
0x3fffffff,
BUS_SPACE_MAXADDR,
NULL,
NULL,
ALLOC_SIZE,
1,
ALLOC_SIZE,
BUS_DMA_ALLOCNOW,
NULL,
NULL,
&dmat) != 0) {
printf("unable to create dma tag\n");
return (-1);
}
if (bus_dmamem_alloc(dmat, (void **)&vbuf, BUS_DMA_NOWAIT,
&dmamap)) {
printf("bus_dmamem_alloc() fail\n");
foo_free();
}
if (bus_dmamap_load(dmat, dmamap, vbuf, ALLOC_SIZE, call_back, NULL, 0)) {
printf("bus_dmamap_load() fail\n");
foo_free();
}
printf("pbuf = 0x%lx\n", pbuf);
return (0);
}
static void
foo_free(void)
{
if (dmamap)
bus_dmamap_unload(dmat, dmamap);
if (dmamap)
bus_dmamem_free(dmat, vbuf, dmamap);
if (dmat)
bus_dma_tag_destroy(dmat);
dmat = NULL;
dmamap = 0;
vbuf = NULL;
pbuf = 0;
}
static int
bus_modevent(module_t mod, int type, void *data)
{
int err = 0;
switch(type) {
case MOD_LOAD:
foo_alloc();
break;
case MOD_UNLOAD:
foo_free();
break;
default:
err = EINVAL;
break;
}
return (err);
}
static moduledata_t bus_alloc = {
"bus_alloc",
bus_modevent,
0
};
DECLARE_MODULE(bus_alloc, bus_alloc, SI_SUB_PSEUDO, SI_ORDER_FIRST);
MODULE_VERSION(bus_alloc, 1);
More information about the freebsd-sparc64
mailing list