Page MenuHomeFreeBSD

D58372.diff
No OneTemporary

D58372.diff

diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -562,14 +562,13 @@
length -= offset;
}
} else {
- /* Position per channel is n times smaller than PCM. */
+ /* Snapshot the write position before synchronizing the buffer. */
pos = sndbuf_getfreeptr(ch->buffer) / n;
- /* Get DMA buffer write position. */
dma_pos = hdspe_read_2(sc, HDSPE_STATUS_REG);
dma_pos &= HDSPE_BUF_POSITION_MASK;
- /* Copy what is newly available. */
length = (dma_pos + HDSPE_CHANBUF_SIZE) - pos;
length %= HDSPE_CHANBUF_SIZE;
+ bus_dmamap_sync(sc->dmat, sc->rmap, BUS_DMASYNC_POSTREAD);
}
/* Position and length in samples (4 bytes). */
@@ -598,6 +597,12 @@
row = hdspe_port_first(ports);
}
+ if (ch->dir == PCMDIR_PLAY && length > 0) {
+ bus_dmamap_sync(sc->dmat, sc->pmap, BUS_DMASYNC_PREWRITE);
+ } else if (ch->dir == PCMDIR_REC) {
+ bus_dmamap_sync(sc->dmat, sc->rmap, BUS_DMASYNC_PREREAD);
+ }
+
ch->position = ((pos + length) * 4) % HDSPE_CHANBUF_SIZE;
}
@@ -617,6 +622,11 @@
if (ch->dir == PCMDIR_PLAY)
buf = sc->pbuf;
+ if (ch->dir == PCMDIR_PLAY)
+ bus_dmamap_sync(sc->dmat, sc->pmap, BUS_DMASYNC_POSTWRITE);
+ else
+ bus_dmamap_sync(sc->dmat, sc->rmap, BUS_DMASYNC_POSTREAD);
+
/* Iterate through rows of ports with contiguous slots. */
ports = ch->ports;
row = hdspe_port_first_row(ports);
@@ -632,6 +642,12 @@
row = hdspe_port_first_row(ports);
}
+ if (ch->dir == PCMDIR_PLAY)
+ bus_dmamap_sync(sc->dmat, sc->pmap, BUS_DMASYNC_PREWRITE);
+ else
+ bus_dmamap_sync(sc->dmat, sc->rmap,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
ch->position = 0;
return (0);
@@ -749,8 +765,8 @@
#if 0
device_printf(scp->dev, "hdspechan_trigger(): stop or abort\n");
#endif
- clean(ch);
hdspechan_enable(ch, 0);
+ clean(ch);
hdspe_stop_audio(sc);
break;
diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h
--- a/sys/dev/sound/pci/hdspe.h
+++ b/sys/dev/sound/pci/hdspe.h
@@ -125,6 +125,8 @@
#define HDSPE_CHANBUF_SAMPLES (16 * 1024)
#define HDSPE_CHANBUF_SIZE (4 * HDSPE_CHANBUF_SAMPLES)
#define HDSPE_DMASEGSIZE (HDSPE_CHANBUF_SIZE * HDSPE_MAX_SLOTS)
+#define HDSPE_DMA_PAGE_SIZE 4096
+#define HDSPE_DMA_PAGES (HDSPE_DMASEGSIZE / HDSPE_DMA_PAGE_SIZE)
#define HDSPE_CHAN_AIO_LINE (1 << 0)
#define HDSPE_CHAN_AIO_EXT (1 << 1)
@@ -240,6 +242,9 @@
uint32_t bufsize;
bus_dmamap_t pmap;
bus_dmamap_t rmap;
+ /* DMA buffer page addresses. */
+ uint32_t paddr[HDSPE_DMA_PAGES];
+ uint32_t raddr[HDSPE_DMA_PAGES];
uint32_t period;
uint32_t speed;
uint32_t force_period;
diff --git a/sys/dev/sound/pci/hdspe.c b/sys/dev/sound/pci/hdspe.c
--- a/sys/dev/sound/pci/hdspe.c
+++ b/sys/dev/sound/pci/hdspe.c
@@ -137,17 +137,57 @@
mtx_unlock(&sc->lock);
}
+struct hdspe_dma_map {
+ uint32_t *pages;
+ unsigned int npages;
+ int error;
+};
+
static void
-hdspe_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+hdspe_dma_map_pages(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
-#if 0
- device_printf(sc->dev, "hdspe_dmapsetmap()\n");
-#endif
+ struct hdspe_dma_map *map;
+ bus_addr_t addr;
+ bus_size_t len;
+ int i;
+
+ map = arg;
+ map->npages = 0;
+ map->error = error;
+ if (error != 0)
+ return;
+
+ for (i = 0; i < nseg; i++) {
+ addr = segs[i].ds_addr;
+ len = segs[i].ds_len;
+ if (addr % HDSPE_DMA_PAGE_SIZE != 0 ||
+ len % HDSPE_DMA_PAGE_SIZE != 0) {
+ map->error = EINVAL;
+ return;
+ }
+ while (len != 0) {
+ if (map->npages == HDSPE_DMA_PAGES) {
+ map->error = EFBIG;
+ return;
+ }
+ map->pages[map->npages++] = (uint32_t)addr;
+ addr += HDSPE_DMA_PAGE_SIZE;
+ len -= HDSPE_DMA_PAGE_SIZE;
+ }
+ }
+ if (map->npages != HDSPE_DMA_PAGES)
+ map->error = EFBIG;
}
static int
hdspe_alloc_resources(struct sc_info *sc)
{
+ struct hdspe_dma_map map;
+ bool pmap_loaded, rmap_loaded;
+ int error;
+
+ pmap_loaded = false;
+ rmap_loaded = false;
/* Allocate resource. */
sc->csid = PCIR_BAR(0);
@@ -171,76 +211,103 @@
bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV,
NULL, hdspe_intr, sc, &sc->ih)) {
device_printf(sc->dev, "Unable to alloc interrupt resource.\n");
- return (ENXIO);
+ goto fail;
}
- /* Allocate DMA resources. */
+ /* Allocate page-aligned DMA segments for each direction. */
if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
- /*alignment*/4,
+ /*alignment*/HDSPE_DMA_PAGE_SIZE,
/*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL,
/*filterarg*/NULL,
- /*maxsize*/2 * HDSPE_DMASEGSIZE,
- /*nsegments*/2,
+ /*maxsize*/HDSPE_DMASEGSIZE,
+ /*nsegments*/HDSPE_DMA_PAGES,
/*maxsegsz*/HDSPE_DMASEGSIZE,
/*flags*/0,
/*lockfunc*/NULL,
/*lockarg*/NULL,
/*dmatag*/&sc->dmat) != 0) {
device_printf(sc->dev, "Unable to create dma tag.\n");
- return (ENXIO);
+ goto fail;
}
sc->bufsize = HDSPE_DMASEGSIZE;
/* pbuf (play buffer). */
- if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_WAITOK,
- &sc->pmap)) {
+ if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf,
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->pmap)) {
device_printf(sc->dev, "Can't alloc pbuf.\n");
- return (ENXIO);
+ goto fail;
}
- if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize,
- hdspe_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
+ map.pages = sc->paddr;
+ map.error = 0;
+ error = bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize,
+ hdspe_dma_map_pages, &map, BUS_DMA_NOWAIT);
+ if (error == 0)
+ pmap_loaded = true;
+ if (error != 0 || map.error != 0) {
device_printf(sc->dev, "Can't load pbuf.\n");
- return (ENXIO);
+ goto fail;
}
/* rbuf (rec buffer). */
- if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_WAITOK,
- &sc->rmap)) {
+ if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf,
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->rmap)) {
device_printf(sc->dev, "Can't alloc rbuf.\n");
- return (ENXIO);
+ goto fail;
}
- if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize,
- hdspe_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
+ map.pages = sc->raddr;
+ map.error = 0;
+ error = bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize,
+ hdspe_dma_map_pages, &map, BUS_DMA_NOWAIT);
+ if (error == 0)
+ rmap_loaded = true;
+ if (error != 0 || map.error != 0) {
device_printf(sc->dev, "Can't load rbuf.\n");
- return (ENXIO);
+ goto fail;
}
- bzero(sc->pbuf, sc->bufsize);
- bzero(sc->rbuf, sc->bufsize);
+ /* Synchronize the buffers before the first DMA cycle. */
+ bus_dmamap_sync(sc->dmat, sc->pmap, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->dmat, sc->rmap, BUS_DMASYNC_PREREAD);
return (0);
+
+fail:
+ if (sc->ih != NULL)
+ bus_teardown_intr(sc->dev, sc->irq, sc->ih);
+ if (rmap_loaded)
+ bus_dmamap_unload(sc->dmat, sc->rmap);
+ if (sc->rbuf != NULL)
+ bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
+ if (pmap_loaded)
+ bus_dmamap_unload(sc->dmat, sc->pmap);
+ if (sc->pbuf != NULL)
+ bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
+ if (sc->dmat != NULL)
+ bus_dma_tag_destroy(sc->dmat);
+ if (sc->irq != NULL)
+ bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq);
+ if (sc->cs != NULL)
+ bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->csid, sc->cs);
+ return (ENXIO);
}
static void
hdspe_map_dmabuf(struct sc_info *sc)
{
- uint32_t paddr, raddr;
int i;
- paddr = vtophys(sc->pbuf);
- raddr = vtophys(sc->rbuf);
-
- for (i = 0; i < HDSPE_MAX_SLOTS * 16; i++) {
+ /* Program the hardware page tables with DMA page addresses. */
+ for (i = 0; i < HDSPE_DMA_PAGES; i++) {
hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_OUT + 4 * i,
- paddr + i * 4096);
+ sc->paddr[i]);
hdspe_write_4(sc, HDSPE_PAGE_ADDR_BUF_IN + 4 * i,
- raddr + i * 4096);
+ sc->raddr[i]);
}
}
@@ -770,6 +837,7 @@
err = hdspe_alloc_resources(sc);
if (err) {
device_printf(dev, "Unable to allocate system resources.\n");
+ mtx_destroy(&sc->lock);
return (ENXIO);
}
@@ -857,6 +925,8 @@
hdspe_dmafree(struct sc_info *sc)
{
+ bus_dmamap_sync(sc->dmat, sc->rmap, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_sync(sc->dmat, sc->pmap, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->dmat, sc->rmap);
bus_dmamap_unload(sc->dmat, sc->pmap);
bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);

File Metadata

Mime Type
text/plain
Expires
Thu, Jul 23, 10:12 PM (9 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35417480
Default Alt Text
D58372.diff (8 KB)

Event Timeline