--- /dev/null
+From: Jaroslav Kysela <perex@perex.cz>
+Subject: [ALSA] hda_intel: fix unexpected ring buffer positions
+Patch-mainline: 2.6.30-rc3
+References: bnc#502733
+
+I found two issues with ICH7-M (it should be related to other HDA chipsets
+as well):
+
+- the ring buffer position is not reset when stream restarts (after xrun) -
+ solved by moving azx_stream_reset() call from open() to prepare() callback
+ and reset posbuf to zero (it might be filled with hw later than position()
+ callback is called)
+- irq_ignore flag should be set also when ring buffer memory area is not
+ changed in prepare() callback - this patch replaces irq_ignore with
+ more universal check based on jiffies clock
+
+Signed-off-by: Jaroslav Kysela <perex@perex.cz>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+ sound/pci/hda/hda_intel.c | 39 +++++++++++++++++++++++++--------------
+ 1 file changed, 25 insertions(+), 14 deletions(-)
+
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -304,6 +304,9 @@ struct azx_dev {
+ unsigned int period_bytes; /* size of the period in bytes */
+ unsigned int frags; /* number for period in the play buffer */
+ unsigned int fifo_size; /* FIFO size */
++ unsigned int start_flag: 1; /* stream full start flag */
++ unsigned long start_jiffies; /* start + minimum jiffies */
++ unsigned long min_jiffies; /* minimum jiffies before position is valid */
+
+ void __iomem *sd_addr; /* stream descriptor pointer */
+
+@@ -322,7 +325,6 @@ struct azx_dev {
+ unsigned int opened :1;
+ unsigned int running :1;
+ unsigned int irq_pending :1;
+- unsigned int irq_ignore :1;
+ /*
+ * For VIA:
+ * A flag to ensure DMA position is 0
+@@ -964,7 +966,7 @@ static irqreturn_t azx_interrupt(int irq
+ struct azx *chip = dev_id;
+ struct azx_dev *azx_dev;
+ u32 status;
+- int i;
++ int i, ok;
+
+ spin_lock(&chip->reg_lock);
+
+@@ -980,18 +982,14 @@ static irqreturn_t azx_interrupt(int irq
+ azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
+ if (!azx_dev->substream || !azx_dev->running)
+ continue;
+- /* ignore the first dummy IRQ (due to pos_adj) */
+- if (azx_dev->irq_ignore) {
+- azx_dev->irq_ignore = 0;
+- continue;
+- }
+ /* check whether this IRQ is really acceptable */
+- if (azx_position_ok(chip, azx_dev)) {
++ ok = azx_position_ok(chip, azx_dev);
++ if (ok == 1) {
+ azx_dev->irq_pending = 0;
+ spin_unlock(&chip->reg_lock);
+ snd_pcm_period_elapsed(azx_dev->substream);
+ spin_lock(&chip->reg_lock);
+- } else if (chip->bus && chip->bus->workq) {
++ } else if (ok == 0 && chip->bus && chip->bus->workq) {
+ /* bogus IRQ, process it later */
+ azx_dev->irq_pending = 1;
+ queue_work(chip->bus->workq,
+@@ -1080,7 +1078,6 @@ static int azx_setup_periods(struct azx
+ bdl = (u32 *)azx_dev->bdl.area;
+ ofs = 0;
+ azx_dev->frags = 0;
+- azx_dev->irq_ignore = 0;
+ pos_adj = bdl_pos_adj[chip->dev_index];
+ if (pos_adj > 0) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+@@ -1101,7 +1098,6 @@ static int azx_setup_periods(struct azx
+ &bdl, ofs, pos_adj, 1);
+ if (ofs < 0)
+ goto error;
+- azx_dev->irq_ignore = 1;
+ }
+ } else
+ pos_adj = 0;
+@@ -1147,6 +1143,9 @@ static void azx_stream_reset(struct azx
+ while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
+ --timeout)
+ ;
++
++ /* reset first position - may not be synced with hw at this time */
++ *azx_dev->posbuf = 0;
+ }
+
+ /*
+@@ -1396,7 +1395,6 @@ static int azx_pcm_open(struct snd_pcm_s
+ snd_pcm_set_sync(substream);
+ mutex_unlock(&chip->open_mutex);
+
+- azx_stream_reset(chip, azx_dev);
+ return 0;
+ }
+
+@@ -1461,6 +1459,7 @@ static int azx_pcm_prepare(struct snd_pc
+ unsigned int bufsize, period_bytes, format_val;
+ int err;
+
++ azx_stream_reset(chip, azx_dev);
+ format_val = snd_hda_calc_stream_format(runtime->rate,
+ runtime->channels,
+ runtime->format,
+@@ -1489,6 +1488,8 @@ static int azx_pcm_prepare(struct snd_pc
+ return err;
+ }
+
++ azx_dev->min_jiffies = (runtime->period_size * HZ) /
++ (runtime->rate * 2);
+ azx_setup_controller(chip, azx_dev);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
+@@ -1505,13 +1506,14 @@ static int azx_pcm_trigger(struct snd_pc
+ struct azx *chip = apcm->chip;
+ struct azx_dev *azx_dev;
+ struct snd_pcm_substream *s;
+- int start, nsync = 0, sbits = 0;
++ int rstart = 0, start, nsync = 0, sbits = 0;
+ int nwait, timeout;
+
+ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ rstart = 1;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+- case SNDRV_PCM_TRIGGER_START:
+ start = 1;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+@@ -1541,6 +1543,10 @@ static int azx_pcm_trigger(struct snd_pc
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+ azx_dev = get_azx_dev(s);
++ if (rstart) {
++ azx_dev->start_flag = 1;
++ azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
++ }
+ if (start)
+ azx_stream_start(chip, azx_dev);
+ else
+@@ -1690,6 +1696,11 @@ static int azx_position_ok(struct azx *c
+ {
+ unsigned int pos;
+
++ if (azx_dev->start_flag &&
++ time_before_eq(jiffies, azx_dev->start_jiffies))
++ return -1; /* bogus (too early) interrupt */
++ azx_dev->start_flag = 0;
++
+ pos = azx_get_position(chip, azx_dev);
+ if (chip->position_fix == POS_FIX_AUTO) {
+ if (!pos) {