ALSA: lola - Fix PCM stalls

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 16c6cad..4d82215 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -73,6 +73,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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) {
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index 1041b0f..839779d 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -305,6 +305,7 @@
 
 	/* flags */
 	unsigned int opened:1;
+	unsigned int prepared:1;
 	unsigned int running:1;
 };
 
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index a656439..ef738e6 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -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 @@
 	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 @@
 	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);
-	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)
-{
-	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 @@
 	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 @@
 				 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 @@
 	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 @@
 				 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 @@
 	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;
-	}
+	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)