ALSA: lola - Fix PCM stalls
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
333ff3971f
commit
0f8f56c959
@ -73,6 +73,7 @@ static int corb_send_verb(struct lola *chip, unsigned int nid,
|
|||||||
chip->last_data = data;
|
chip->last_data = data;
|
||||||
chip->last_extdata = extdata;
|
chip->last_extdata = extdata;
|
||||||
data |= (nid << 20) | (verb << 8);
|
data |= (nid << 20) | (verb << 8);
|
||||||
|
|
||||||
spin_lock_irqsave(&chip->reg_lock, flags);
|
spin_lock_irqsave(&chip->reg_lock, flags);
|
||||||
if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
|
if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 1) {
|
||||||
unsigned int wp = chip->corb.wp + 1;
|
unsigned int wp = chip->corb.wp + 1;
|
||||||
@ -338,8 +339,6 @@ static int setup_corb_rirb(struct lola *chip)
|
|||||||
chip->corb.buf = (u32 *)chip->rb.area;
|
chip->corb.buf = (u32 *)chip->rb.area;
|
||||||
chip->rirb.addr = chip->rb.addr + 2048;
|
chip->rirb.addr = chip->rb.addr + 2048;
|
||||||
chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
|
chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
|
||||||
lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr);
|
|
||||||
lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr));
|
|
||||||
|
|
||||||
/* disable ringbuffer DMAs */
|
/* disable ringbuffer DMAs */
|
||||||
lola_writeb(chip, BAR0, RIRBCTL, 0);
|
lola_writeb(chip, BAR0, RIRBCTL, 0);
|
||||||
@ -496,6 +495,10 @@ static int lola_parse_tree(struct lola *chip)
|
|||||||
if (!chip->cold_reset) {
|
if (!chip->cold_reset) {
|
||||||
lola_reset_setups(chip);
|
lola_reset_setups(chip);
|
||||||
chip->cold_reset = 1;
|
chip->cold_reset = 1;
|
||||||
|
} else {
|
||||||
|
/* set the granularity if it is not the default */
|
||||||
|
if (chip->granularity != LOLA_GRANULARITY_MIN)
|
||||||
|
lola_set_granularity(chip, chip->granularity, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -561,8 +564,14 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
|
|||||||
chip->pci = pci;
|
chip->pci = pci;
|
||||||
chip->irq = -1;
|
chip->irq = -1;
|
||||||
|
|
||||||
chip->sample_rate_min = 48000;
|
/* below a sample_rate of 16kHz the analogue audio quality
|
||||||
chip->granularity = LOLA_GRANULARITY_MIN;
|
* is NOT excellent
|
||||||
|
*/
|
||||||
|
chip->sample_rate_min = 16000;
|
||||||
|
/* for instance use always max granularity which is compatible
|
||||||
|
* with all sample rates
|
||||||
|
*/
|
||||||
|
chip->granularity = LOLA_GRANULARITY_MAX;
|
||||||
|
|
||||||
err = pci_request_regions(pci, DRVNAME);
|
err = pci_request_regions(pci, DRVNAME);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -305,6 +305,7 @@ struct lola_stream {
|
|||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
unsigned int opened:1;
|
unsigned int opened:1;
|
||||||
|
unsigned int prepared:1;
|
||||||
unsigned int running:1;
|
unsigned int running:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
/* #define USE_SG_BUFFER */
|
/* #define USE_SG_BUFFER */
|
||||||
|
|
||||||
#define LOLA_MAX_BDL_ENTRIES 8
|
#define LOLA_MAX_BDL_ENTRIES 8
|
||||||
#define LOLA_MAX_FRAG 8
|
|
||||||
#define LOLA_MAX_BUF_SIZE (1024*1024*1024)
|
#define LOLA_MAX_BUF_SIZE (1024*1024*1024)
|
||||||
#define LOLA_BDL_ENTRY_SIZE (16 * 16)
|
#define LOLA_BDL_ENTRY_SIZE (16 * 16)
|
||||||
|
|
||||||
@ -111,12 +110,6 @@ static void lola_stream_stop(struct lola *chip, struct lola_stream *str,
|
|||||||
lola_stream_clear_pending_irq(chip, str);
|
lola_stream_clear_pending_irq(chip, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lola_stream_clear(struct lola *chip, struct lola_stream *str)
|
|
||||||
{
|
|
||||||
lola_dsd_write(chip, str->dsd, CTL, 0);
|
|
||||||
lola_stream_clear_pending_irq(chip, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wait_for_srst_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(200);
|
unsigned long end_time = jiffies + msecs_to_jiffies(200);
|
||||||
@ -130,22 +123,15 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str)
|
|||||||
printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
|
printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
|
static int lola_stream_wait_for_fifo(struct lola *chip,
|
||||||
|
struct lola_stream *str,
|
||||||
|
bool ready)
|
||||||
{
|
{
|
||||||
lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
|
unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
|
||||||
wait_for_srst_clear(chip, str);
|
unsigned long end_time = jiffies + msecs_to_jiffies(200);
|
||||||
lola_dsd_write(chip, str->dsd, LVI, 0);
|
|
||||||
lola_dsd_write(chip, str->dsd, BDPU, 0);
|
|
||||||
lola_dsd_write(chip, str->dsd, BDPL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lola_stream_wait_for_fifo_ready(struct lola *chip,
|
|
||||||
struct lola_stream *str)
|
|
||||||
{
|
|
||||||
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
|
|
||||||
while (time_before(jiffies, end_time)) {
|
while (time_before(jiffies, end_time)) {
|
||||||
unsigned int val = lola_dsd_read(chip, str->dsd, STS);
|
unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
|
||||||
if (val & LOLA_DSD_STS_FIFORDY)
|
if ((reg & LOLA_DSD_STS_FIFORDY) == val)
|
||||||
return 0;
|
return 0;
|
||||||
msleep(1);
|
msleep(1);
|
||||||
}
|
}
|
||||||
@ -153,6 +139,23 @@ static int lola_stream_wait_for_fifo_ready(struct lola *chip,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lola_stream_reset(struct lola *chip, struct lola_stream *str)
|
||||||
|
{
|
||||||
|
if (str->prepared) {
|
||||||
|
str->prepared = 0;
|
||||||
|
|
||||||
|
lola_dsd_write(chip, str->dsd, CTL,
|
||||||
|
LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE);
|
||||||
|
lola_stream_wait_for_fifo(chip, str, false);
|
||||||
|
lola_stream_clear_pending_irq(chip, str);
|
||||||
|
lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST);
|
||||||
|
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 struct snd_pcm_hardware lola_pcm_hw = {
|
static struct snd_pcm_hardware lola_pcm_hw = {
|
||||||
.info = (SNDRV_PCM_INFO_MMAP |
|
.info = (SNDRV_PCM_INFO_MMAP |
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
@ -163,16 +166,16 @@ static struct snd_pcm_hardware lola_pcm_hw = {
|
|||||||
SNDRV_PCM_FMTBIT_S24_LE |
|
SNDRV_PCM_FMTBIT_S24_LE |
|
||||||
SNDRV_PCM_FMTBIT_S32_LE |
|
SNDRV_PCM_FMTBIT_S32_LE |
|
||||||
SNDRV_PCM_FMTBIT_FLOAT_LE),
|
SNDRV_PCM_FMTBIT_FLOAT_LE),
|
||||||
.rates = SNDRV_PCM_RATE_48000,
|
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||||
.rate_min = 48000,
|
.rate_min = 8000,
|
||||||
.rate_max = 48000,
|
.rate_max = 192000,
|
||||||
.channels_min = 1,
|
.channels_min = 1,
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
.buffer_bytes_max = LOLA_MAX_BUF_SIZE,
|
.buffer_bytes_max = LOLA_MAX_BUF_SIZE,
|
||||||
.period_bytes_min = 128,
|
.period_bytes_min = 128,
|
||||||
.period_bytes_max = LOLA_MAX_BUF_SIZE / 2,
|
.period_bytes_max = LOLA_MAX_BUF_SIZE / 2,
|
||||||
.periods_min = 2,
|
.periods_min = 2,
|
||||||
.periods_max = LOLA_MAX_FRAG,
|
.periods_max = LOLA_MAX_BDL_ENTRIES,
|
||||||
.fifo_size = 0,
|
.fifo_size = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,10 +197,13 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
|
|||||||
runtime->hw = lola_pcm_hw;
|
runtime->hw = lola_pcm_hw;
|
||||||
runtime->hw.channels_max = pcm->num_streams - str->index;
|
runtime->hw.channels_max = pcm->num_streams - str->index;
|
||||||
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
/* period size = multiple of chip->granularity (8, 16 or 32 frames)
|
||||||
128);
|
* use LOLA_GRANULARITY_MAX = 32 for instance
|
||||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
*/
|
||||||
128);
|
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
|
||||||
|
LOLA_GRANULARITY_MAX);
|
||||||
|
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
|
||||||
|
LOLA_GRANULARITY_MAX);
|
||||||
mutex_unlock(&chip->open_mutex);
|
mutex_unlock(&chip->open_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -383,16 +389,24 @@ static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
|
|||||||
struct lola_stream *str)
|
struct lola_stream *str)
|
||||||
{
|
{
|
||||||
dma_addr_t bdl;
|
dma_addr_t bdl;
|
||||||
|
|
||||||
|
if (str->prepared)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* set up BDL */
|
/* set up BDL */
|
||||||
bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index;
|
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, BDPL, (u32)bdl);
|
||||||
lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
|
lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl));
|
||||||
/* program the stream LVI (last valid index) of the BDL */
|
/* program the stream LVI (last valid index) of the BDL */
|
||||||
lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
|
lola_dsd_write(chip, str->dsd, LVI, str->frags - 1);
|
||||||
lola_stream_stop(chip, str, lola_get_tstamp(chip, false));
|
lola_stream_clear_pending_irq(chip, str);
|
||||||
lola_stream_wait_for_fifo_ready(chip, str);
|
|
||||||
|
|
||||||
return 0;
|
lola_dsd_write(chip, str->dsd, CTL,
|
||||||
|
LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN);
|
||||||
|
|
||||||
|
str->prepared = 1;
|
||||||
|
|
||||||
|
return lola_stream_wait_for_fifo(chip, str, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lola_pcm_prepare(struct snd_pcm_substream *substream)
|
static int lola_pcm_prepare(struct snd_pcm_substream *substream)
|
||||||
@ -421,22 +435,25 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
|
|||||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||||
format_verb = lola_get_format_verb(substream);
|
format_verb = lola_get_format_verb(substream);
|
||||||
|
|
||||||
if (bufsize != str->bufsize ||
|
str->bufsize = bufsize;
|
||||||
period_bytes != str->period_bytes ||
|
str->period_bytes = period_bytes;
|
||||||
format_verb != str->format_verb) {
|
str->format_verb = format_verb;
|
||||||
str->bufsize = bufsize;
|
|
||||||
str->period_bytes = period_bytes;
|
err = lola_setup_periods(chip, pcm, substream, str);
|
||||||
str->format_verb = format_verb;
|
if (err < 0)
|
||||||
err = lola_setup_periods(chip, pcm, substream, str);
|
return err;
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = lola_set_stream_config(chip, str, runtime->channels);
|
err = lola_set_stream_config(chip, str, runtime->channels);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return lola_setup_controller(chip, pcm, str);
|
err = lola_setup_controller(chip, pcm, str);
|
||||||
|
if (err < 0) {
|
||||||
|
lola_stream_reset(chip, str);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
static int lola_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user