Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f8f56c9 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: lola - Fix PCM stalls



Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 333ff397
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static int corb_send_verb(struct lola *chip, unsigned int nid,
	chip->last_data = data;
	chip->last_extdata = extdata;
	data |= (nid << 20) | (verb << 8);

	spin_lock_irqsave(&chip->reg_lock, flags);
	if (chip->rirb.cmds < LOLA_CORB_ENTRIES - 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->rirb.addr = chip->rb.addr + 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 */
	lola_writeb(chip, BAR0, RIRBCTL, 0);
@@ -496,6 +495,10 @@ static int lola_parse_tree(struct lola *chip)
	if (!chip->cold_reset) {
		lola_reset_setups(chip);
		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;
@@ -561,8 +564,14 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
	chip->pci = pci;
	chip->irq = -1;

	chip->sample_rate_min = 48000;
	chip->granularity = LOLA_GRANULARITY_MIN;
	/* below a sample_rate of 16kHz the analogue audio quality
	 * 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);
	if (err < 0) {
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ struct lola_stream {

	/* flags */
	unsigned int opened:1;
	unsigned int prepared:1;
	unsigned int running:1;
};

+60 −43
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@
/* #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)

@@ -111,12 +110,6 @@ static void lola_stream_stop(struct lola *chip, struct lola_stream *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)
{
	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);
}

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);
}

static int lola_stream_wait_for_fifo_ready(struct lola *chip,
					   struct lola_stream *str)
static int lola_stream_wait_for_fifo(struct lola *chip,
				     struct lola_stream *str,
				     bool ready)
{
	unsigned long end_time = jiffies + msecs_to_jiffies(1000);
	unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0;
	unsigned long end_time = jiffies + msecs_to_jiffies(200);
	while (time_before(jiffies, end_time)) {
		unsigned int val = lola_dsd_read(chip, str->dsd, STS);
		if (val & LOLA_DSD_STS_FIFORDY)
		unsigned int reg = lola_dsd_read(chip, str->dsd, STS);
		if ((reg & LOLA_DSD_STS_FIFORDY) == val)
			return 0;
		msleep(1);
	}
@@ -153,6 +139,23 @@ static int lola_stream_wait_for_fifo_ready(struct lola *chip,
	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 = {
	.info =			(SNDRV_PCM_INFO_MMAP |
				 SNDRV_PCM_INFO_INTERLEAVED |
@@ -163,16 +166,16 @@ static struct snd_pcm_hardware lola_pcm_hw = {
				 SNDRV_PCM_FMTBIT_S24_LE |
				 SNDRV_PCM_FMTBIT_S32_LE |
				 SNDRV_PCM_FMTBIT_FLOAT_LE),
	.rates =		SNDRV_PCM_RATE_48000,
	.rate_min =		48000,
	.rate_max =		48000,
	.rates =		SNDRV_PCM_RATE_8000_192000,
	.rate_min =		8000,
	.rate_max =		192000,
	.channels_min =		1,
	.channels_max =		2,
	.buffer_bytes_max =	LOLA_MAX_BUF_SIZE,
	.period_bytes_min =	128,
	.period_bytes_max =	LOLA_MAX_BUF_SIZE / 2,
	.periods_min =		2,
	.periods_max =		LOLA_MAX_FRAG,
	.periods_max =		LOLA_MAX_BDL_ENTRIES,
	.fifo_size =		0,
};

@@ -194,10 +197,13 @@ static int lola_pcm_open(struct snd_pcm_substream *substream)
	runtime->hw = lola_pcm_hw;
	runtime->hw.channels_max = pcm->num_streams - str->index;
	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
				   128);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
				   128);
	/* period size = multiple of chip->granularity (8, 16 or 32 frames)
	 * use LOLA_GRANULARITY_MAX = 32 for instance
	 */
	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);
	return 0;
}
@@ -383,16 +389,24 @@ static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm,
				 struct lola_stream *str)
{
	dma_addr_t bdl;

	if (str->prepared)
		return -EINVAL;

	/* set up BDL */
	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));
	lola_stream_wait_for_fifo_ready(chip, str);
	lola_stream_clear_pending_irq(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)
@@ -421,22 +435,25 @@ static int lola_pcm_prepare(struct snd_pcm_substream *substream)
	period_bytes = snd_pcm_lib_period_bytes(substream);
	format_verb = lola_get_format_verb(substream);

	if (bufsize != str->bufsize ||
	    period_bytes != str->period_bytes ||
	    format_verb != str->format_verb) {
	str->bufsize = bufsize;
	str->period_bytes = period_bytes;
	str->format_verb = format_verb;

	err = lola_setup_periods(chip, pcm, substream, str);
	if (err < 0)
		return err;
	}

	err = lola_set_stream_config(chip, str, runtime->channels);
	if (err < 0)
		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)