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