ALSA: lola - Use a single BDL
Use a single BDL for both buffers instead of allocating for each. Also a few tune-up to avoid the stream stalls in the PCM code and the prelimianry work for SG-buffer support are added, too. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
a426c78723
commit
333ff3971f
|
@ -299,7 +299,6 @@ struct lola_stream {
|
|||
unsigned int bufsize;
|
||||
unsigned int period_bytes;
|
||||
unsigned int frags;
|
||||
struct snd_dma_buffer bdl; /* BDL buffer */
|
||||
|
||||
/* format + channel setup */
|
||||
unsigned int format_verb;
|
||||
|
@ -314,6 +313,7 @@ struct lola_stream {
|
|||
|
||||
struct lola_pcm {
|
||||
unsigned int num_streams;
|
||||
struct snd_dma_buffer bdl; /* BDL buffer */
|
||||
struct lola_stream streams[MAX_STREAM_COUNT];
|
||||
};
|
||||
|
||||
|
|
|
@ -26,10 +26,28 @@
|
|||
#include <sound/pcm.h>
|
||||
#include "lola.h"
|
||||
|
||||
#define BDL_SIZE 4096
|
||||
#define LOLA_MAX_BDL_ENTRIES (BDL_SIZE / 16)
|
||||
#define LOLA_MAX_FRAG 32
|
||||
/* #define USE_SG_BUFFER */
|
||||
|
||||
#define LOLA_MAX_BDL_ENTRIES 8
|
||||
#define LOLA_MAX_FRAG 8
|
||||
#define LOLA_MAX_BUF_SIZE (1024*1024*1024)
|
||||
#define LOLA_BDL_ENTRY_SIZE (16 * 16)
|
||||
|
||||
#ifdef USE_SG_BUFFER
|
||||
#define get_addr(substream, ofs) \
|
||||
snd_pcm_sgbuf_get_addr(substream, ofs)
|
||||
#define get_size(substream, ofs, size) \
|
||||
snd_pcm_sgbuf_get_chunk_size(substream, ofs, size)
|
||||
#define ops_page snd_pcm_sgbuf_ops_page
|
||||
#define PREALLOC_TYPE SNDRV_DMA_TYPE_DEV_SG
|
||||
#else
|
||||
#define get_addr(substream, ofs) \
|
||||
((substream)->runtime->dma_addr + ofs)
|
||||
#define get_size(substream, ofs, size) \
|
||||
(size)
|
||||
#define ops_page NULL
|
||||
#define PREALLOC_TYPE SNDRV_DMA_TYPE_DEV
|
||||
#endif
|
||||
|
||||
static struct lola_pcm *lola_get_pcm(struct snd_pcm_substream *substream)
|
||||
{
|
||||
|
@ -101,7 +119,7 @@ static void lola_stream_clear(struct lola *chip, struct lola_stream *str)
|
|||
|
||||
static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
|
||||
{
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(50);
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(200);
|
||||
while (time_before(jiffies, end_time)) {
|
||||
unsigned int val;
|
||||
val = lola_dsd_read(chip, str->dsd, CTL);
|
||||
|
@ -115,16 +133,16 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
|
|||
static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
|
||||
{
|
||||
lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
|
||||
wait_for_srst_clear(chip, str);
|
||||
lola_dsd_write(chip, str->dsd, LVI, 0);
|
||||
lola_dsd_write(chip, str->dsd, BDPU, 0);
|
||||
lola_dsd_write(chip, str->dsd, BDPL, 0);
|
||||
wait_for_srst_clear(chip, str);
|
||||
}
|
||||
|
||||
static int lola_stream_wait_for_fifo_ready(struct lola *chip,
|
||||
struct lola_stream *str)
|
||||
{
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(50);
|
||||
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
|
||||
while (time_before(jiffies, end_time)) {
|
||||
unsigned int val = lola_dsd_read(chip, str->dsd, STS);
|
||||
if (val & LOLA_DSD_STS_FIFORDY)
|
||||
|
@ -164,21 +182,12 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
|
|||
struct lola_pcm *pcm = lola_get_pcm(substream);
|
||||
struct lola_stream *str = lola_get_stream(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int err;
|
||||
|
||||
mutex_lock(&chip->open_mutex);
|
||||
if (str->opened) {
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
|
||||
snd_dma_pci_data(chip->pci),
|
||||
PAGE_SIZE, &str->bdl);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
printk(KERN_ERR SFX "Can't allocate BDL\n");
|
||||
return err;
|
||||
}
|
||||
str->substream = substream;
|
||||
str->master = NULL;
|
||||
str->opened = 1;
|
||||
|
@ -216,7 +225,6 @@ static int lola_pcm_close(struct snd_pcm_substream *substream)
|
|||
str->substream = NULL;
|
||||
str->opened = 0;
|
||||
}
|
||||
snd_dma_free_pages(&str->bdl);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -262,12 +270,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
|
|||
if (str->frags >= LOLA_MAX_BDL_ENTRIES)
|
||||
return -EINVAL;
|
||||
|
||||
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
|
||||
addr = get_addr(substream, ofs);
|
||||
/* program the address field of the BDL entry */
|
||||
bdl[0] = cpu_to_le32((u32)addr);
|
||||
bdl[1] = cpu_to_le32(upper_32_bits(addr));
|
||||
/* program the size field of the BDL entry */
|
||||
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
|
||||
chunk = get_size(substream, ofs, size);
|
||||
bdl[2] = cpu_to_le32(chunk);
|
||||
/* program the IOC to enable interrupt
|
||||
* only when the whole fragment is processed
|
||||
|
@ -285,7 +293,7 @@ static int setup_bdle(struct snd_pcm_substream *substream,
|
|||
/*
|
||||
* set up BDL entries
|
||||
*/
|
||||
static int lola_setup_periods(struct lola *chip,
|
||||
static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct lola_stream *str)
|
||||
{
|
||||
|
@ -296,7 +304,7 @@ static int lola_setup_periods(struct lola *chip,
|
|||
periods = str->bufsize / period_bytes;
|
||||
|
||||
/* program the initial BDL entries */
|
||||
bdl = (u32 *)str->bdl.area;
|
||||
bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
|
||||
ofs = 0;
|
||||
str->frags = 0;
|
||||
for (i = 0; i < periods; i++) {
|
||||
|
@ -371,13 +379,14 @@ static int lola_set_stream_config(struct lola *chip,
|
|||
/*
|
||||
* set up the SD for streaming
|
||||
*/
|
||||
static int lola_setup_controller(struct lola *chip, struct lola_stream *str)
|
||||
static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
|
||||
struct lola_stream *str)
|
||||
{
|
||||
/* make sure the run bit is zero for SD */
|
||||
lola_stream_clear(chip, str);
|
||||
dma_addr_t bdl;
|
||||
/* set up BDL */
|
||||
lola_dsd_write(chip, str->dsd, BDPL, (u32)str->bdl.addr);
|
||||
lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(str->bdl.addr));
|
||||
bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
|
||||
lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl);
|
||||
lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
|
||||
/* program the stream LVI (last valid index) of the BDL */
|
||||
lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
|
||||
lola_stream_stop(chip, str, lola_get_tstamp(chip, false));
|
||||
|
@ -418,7 +427,7 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
str->bufsize = bufsize;
|
||||
str->period_bytes = period_bytes;
|
||||
str->format_verb = format_verb;
|
||||
err = lola_setup_periods(chip, substream, str);
|
||||
err = lola_setup_periods(chip, pcm, substream, str);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -427,7 +436,7 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return lola_setup_controller(chip, str);
|
||||
return lola_setup_controller(chip, pcm, str);
|
||||
}
|
||||
|
||||
static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
|
@ -504,7 +513,7 @@ static struct snd_pcm_ops lola_pcm_ops = {
|
|||
.prepare = lola_pcm_prepare,
|
||||
.trigger = lola_pcm_trigger,
|
||||
.pointer = lola_pcm_pointer,
|
||||
.page = snd_pcm_sgbuf_ops_page,
|
||||
.page = ops_page,
|
||||
};
|
||||
|
||||
int __devinit lola_create_pcm(struct lola *chip)
|
||||
|
@ -512,6 +521,14 @@ int __devinit lola_create_pcm(struct lola *chip)
|
|||
struct snd_pcm *pcm;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
|
||||
snd_dma_pci_data(chip->pci),
|
||||
PAGE_SIZE, &chip->pcm[i].bdl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_pcm_new(chip->card, "Digigram Lola", 0,
|
||||
chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
|
||||
chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
|
||||
|
@ -525,7 +542,7 @@ int __devinit lola_create_pcm(struct lola *chip)
|
|||
snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
|
||||
}
|
||||
/* buffer pre-allocation */
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, PREALLOC_TYPE,
|
||||
snd_dma_pci_data(chip->pci),
|
||||
1024 * 64, 32 * 1024 * 1024);
|
||||
return 0;
|
||||
|
@ -533,7 +550,8 @@ int __devinit lola_create_pcm(struct lola *chip)
|
|||
|
||||
void lola_free_pcm(struct lola *chip)
|
||||
{
|
||||
/* nothing to do */
|
||||
snd_dma_free_pages(&chip->pcm[0].bdl);
|
||||
snd_dma_free_pages(&chip->pcm[1].bdl);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue