The new contigmalloc code is exposing a lot of misuses of busdma memory

allocation. Notably, in this case, the driver tries to allocate several
pieces of memory and then fails if the pieces allocated after the first
do not come after it physically, and within a specific range (8MB I
believe).  Of course, this could just as easily fail for any number of
reasons, but it almost always fails now that contiguous allocations start
at the end of possible specified memory locations rather than the beginning.

Allocate all the possibly-needed memory up front, even though it's a waste,
to get around this.  The least bogus solution would be to take the physical
address from the first allocation and create a new tag that specified that
further allocations must follow it within that 8MB window, then use that
when allocating new channels, but that's left for anyone else that really
feels like doing it.

Tested by:	Erwin Lansing <erwin@lansing.dk>
This commit is contained in:
Brian Feldman 2004-08-22 18:57:40 +00:00
parent c4bdc6fc32
commit bf5ab950e3

View File

@ -655,19 +655,10 @@ aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c,
ch->num = ess->playchns;
ch->dir = dir;
p = dma_malloc(ess, ess->bufsz, &physaddr);
if (p == NULL)
return NULL;
physaddr = ess->baseaddr + ch->offset;
p = ess->stat + ch->offset;
sndbuf_setup(b, p, ess->bufsz);
ch->offset = physaddr - ess->baseaddr;
if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) {
device_printf(ess->dev,
"offset %#llx exceeds limit. ", (long long)ch->offset);
dma_free(ess, sndbuf_getbuf(b));
return NULL;
}
ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
if (dir == PCMDIR_PLAY) {
@ -683,12 +674,6 @@ aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c,
static int
aggch_free(kobj_t obj, void *data)
{
struct agg_chinfo *ch = data;
struct agg_info *ess = ch->parent;
/* free up buffer - called after channel stopped */
dma_free(ess, sndbuf_getbuf(ch->buffer));
/* return 0 if ok */
return 0;
}
@ -957,6 +942,8 @@ agg_attach(device_t dev)
struct resource *irq = NULL;
void *ih = NULL;
char status[SND_STATUSLEN];
bus_addr_t offset;
int i;
if ((ess = malloc(sizeof *ess, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
device_printf(dev, "cannot allocate softc\n");
@ -971,21 +958,28 @@ agg_attach(device_t dev)
/*boundary*/WPWA_MAXADDR + 1,
/*lowaddr*/MAESTRO_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/ess->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
/*maxsize*/ess->bufsz * (1 + AGG_MAXPLAYCH + 1), /*nsegments*/1,
/*maxsegz*/0x3ffff, /*flags*/0, /*lockfunc*/busdma_lock_mutex,
/*lockarg*/&Giant, &ess->parent_dmat) != 0) {
device_printf(dev, "unable to create dma tag\n");
goto bad;
}
ess->stat = dma_malloc(ess, ess->bufsz, &ess->baseaddr);
ess->stat = dma_malloc(ess, ess->bufsz * (1 + AGG_MAXPLAYCH + 1),
&ess->baseaddr);
if (ess->stat == NULL) {
device_printf(dev, "cannot allocate status buffer\n");
device_printf(dev, "cannot allocate DMA memory\n");
goto bad;
}
if (bootverbose)
device_printf(dev, "Maestro DMA base: %#llx\n",
(long long)ess->baseaddr);
offset = ess->bufsz;
for (i = 0; i < AGG_MAXPLAYCH; i++) {
ess->pch[i].offset = offset;
offset += ess->bufsz;
}
ess->rch.offset = offset;
agg_power(ess, PPMI_D0);
DELAY(100000);