summaryrefslogtreecommitdiffstats
path: root/sound/pci/lola
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-03 16:41:02 +0200
committerTakashi Iwai <tiwai@suse.de>2011-05-03 16:41:02 +0200
commit333ff3971f374d9a057fd6d1492a2ef78989974d (patch)
tree194f15d828c478ff3dfe22e597cf202383fd2ddd /sound/pci/lola
parenta426c787233c87587b6cac797ac840162bdb09c2 (diff)
downloadlinux-333ff3971f374d9a057fd6d1492a2ef78989974d.tar.gz
linux-333ff3971f374d9a057fd6d1492a2ef78989974d.tar.bz2
linux-333ff3971f374d9a057fd6d1492a2ef78989974d.zip
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>
Diffstat (limited to 'sound/pci/lola')
-rw-r--r--sound/pci/lola/lola.h2
-rw-r--r--sound/pci/lola/lola_pcm.c78
2 files changed, 49 insertions, 31 deletions
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index 23831a1a95ad..1041b0f0e20f 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -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];
};
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index bf17f921d45f..a656439915c8 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -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);
}
/*