| 1 |
From 8820b651ddf48830af44520a13e63f5b9c5b9f9f Mon Sep 17 00:00:00 2001
|
| 2 |
From: Jaroslav Kysela <perex@perex.cz>
|
| 3 |
Date: Fri, 10 Apr 2009 12:20:45 +0200
|
| 4 |
Subject: [ALSA] hda_intel: fix unexpected ring buffer positions
|
| 5 |
|
| 6 |
I found two issues with ICH7-M (it should be related to other HDA chipsets
|
| 7 |
as well):
|
| 8 |
|
| 9 |
- the ring buffer position is not reset when stream restarts (after xrun) -
|
| 10 |
solved by moving azx_stream_reset() call from open() to prepare() callback
|
| 11 |
and reset posbuf to zero (it might be filled with hw later than position()
|
| 12 |
callback is called)
|
| 13 |
- irq_ignore flag should be set also when ring buffer memory area is not
|
| 14 |
changed in prepare() callback - this patch replaces irq_ignore with
|
| 15 |
more universal check based on jiffies clock
|
| 16 |
|
| 17 |
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
| 18 |
---
|
| 19 |
sound/pci/hda/hda_intel.c | 39 +++++++++++++++++++++++++--------------
|
| 20 |
1 files changed, 25 insertions(+), 14 deletions(-)
|
| 21 |
|
| 22 |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
|
| 23 |
index 931a62d..7112e0e 100644
|
| 24 |
--- a/sound/pci/hda/hda_intel.c
|
| 25 |
+++ b/sound/pci/hda/hda_intel.c
|
| 26 |
@@ -312,6 +312,9 @@ struct azx_dev {
|
| 27 |
unsigned int period_bytes; /* size of the period in bytes */
|
| 28 |
unsigned int frags; /* number for period in the play buffer */
|
| 29 |
unsigned int fifo_size; /* FIFO size */
|
| 30 |
+ unsigned int start_flag: 1; /* stream full start flag */
|
| 31 |
+ unsigned long start_jiffies; /* start + minimum jiffies */
|
| 32 |
+ unsigned long min_jiffies; /* minimum jiffies before position is valid */
|
| 33 |
|
| 34 |
void __iomem *sd_addr; /* stream descriptor pointer */
|
| 35 |
|
| 36 |
@@ -330,7 +333,6 @@ struct azx_dev {
|
| 37 |
unsigned int opened :1;
|
| 38 |
unsigned int running :1;
|
| 39 |
unsigned int irq_pending :1;
|
| 40 |
- unsigned int irq_ignore :1;
|
| 41 |
/*
|
| 42 |
* For VIA:
|
| 43 |
* A flag to ensure DMA position is 0
|
| 44 |
@@ -974,7 +976,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
| 45 |
struct azx *chip = dev_id;
|
| 46 |
struct azx_dev *azx_dev;
|
| 47 |
u32 status;
|
| 48 |
- int i;
|
| 49 |
+ int i, ok;
|
| 50 |
|
| 51 |
spin_lock(&chip->reg_lock);
|
| 52 |
|
| 53 |
@@ -990,18 +992,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
| 54 |
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
|
| 55 |
if (!azx_dev->substream || !azx_dev->running)
|
| 56 |
continue;
|
| 57 |
- /* ignore the first dummy IRQ (due to pos_adj) */
|
| 58 |
- if (azx_dev->irq_ignore) {
|
| 59 |
- azx_dev->irq_ignore = 0;
|
| 60 |
- continue;
|
| 61 |
- }
|
| 62 |
/* check whether this IRQ is really acceptable */
|
| 63 |
- if (azx_position_ok(chip, azx_dev)) {
|
| 64 |
+ ok = azx_position_ok(chip, azx_dev);
|
| 65 |
+ if (ok == 1) {
|
| 66 |
azx_dev->irq_pending = 0;
|
| 67 |
spin_unlock(&chip->reg_lock);
|
| 68 |
snd_pcm_period_elapsed(azx_dev->substream);
|
| 69 |
spin_lock(&chip->reg_lock);
|
| 70 |
- } else if (chip->bus && chip->bus->workq) {
|
| 71 |
+ } else if (ok == 0 && chip->bus && chip->bus->workq) {
|
| 72 |
/* bogus IRQ, process it later */
|
| 73 |
azx_dev->irq_pending = 1;
|
| 74 |
queue_work(chip->bus->workq,
|
| 75 |
@@ -1087,7 +1085,6 @@ static int azx_setup_periods(struct azx *chip,
|
| 76 |
bdl = (u32 *)azx_dev->bdl.area;
|
| 77 |
ofs = 0;
|
| 78 |
azx_dev->frags = 0;
|
| 79 |
- azx_dev->irq_ignore = 0;
|
| 80 |
pos_adj = bdl_pos_adj[chip->dev_index];
|
| 81 |
if (pos_adj > 0) {
|
| 82 |
struct snd_pcm_runtime *runtime = substream->runtime;
|
| 83 |
@@ -1108,7 +1105,6 @@ static int azx_setup_periods(struct azx *chip,
|
| 84 |
&bdl, ofs, pos_adj, 1);
|
| 85 |
if (ofs < 0)
|
| 86 |
goto error;
|
| 87 |
- azx_dev->irq_ignore = 1;
|
| 88 |
}
|
| 89 |
} else
|
| 90 |
pos_adj = 0;
|
| 91 |
@@ -1154,6 +1150,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
|
| 92 |
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
|
| 93 |
--timeout)
|
| 94 |
;
|
| 95 |
+
|
| 96 |
+ /* reset first position - may not be synced with hw at this time */
|
| 97 |
+ *azx_dev->posbuf = 0;
|
| 98 |
}
|
| 99 |
|
| 100 |
/*
|
| 101 |
@@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
| 102 |
snd_pcm_set_sync(substream);
|
| 103 |
mutex_unlock(&chip->open_mutex);
|
| 104 |
|
| 105 |
- azx_stream_reset(chip, azx_dev);
|
| 106 |
return 0;
|
| 107 |
}
|
| 108 |
|
| 109 |
@@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
| 110 |
unsigned int bufsize, period_bytes, format_val;
|
| 111 |
int err;
|
| 112 |
|
| 113 |
+ azx_stream_reset(chip, azx_dev);
|
| 114 |
format_val = snd_hda_calc_stream_format(runtime->rate,
|
| 115 |
runtime->channels,
|
| 116 |
runtime->format,
|
| 117 |
@@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
| 118 |
return err;
|
| 119 |
}
|
| 120 |
|
| 121 |
+ azx_dev->min_jiffies = (runtime->period_size * HZ) /
|
| 122 |
+ (runtime->rate * 2);
|
| 123 |
azx_setup_controller(chip, azx_dev);
|
| 124 |
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
| 125 |
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
|
| 126 |
@@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
| 127 |
struct azx *chip = apcm->chip;
|
| 128 |
struct azx_dev *azx_dev;
|
| 129 |
struct snd_pcm_substream *s;
|
| 130 |
- int start, nsync = 0, sbits = 0;
|
| 131 |
+ int rstart = 0, start, nsync = 0, sbits = 0;
|
| 132 |
int nwait, timeout;
|
| 133 |
|
| 134 |
switch (cmd) {
|
| 135 |
+ case SNDRV_PCM_TRIGGER_START:
|
| 136 |
+ rstart = 1;
|
| 137 |
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
| 138 |
case SNDRV_PCM_TRIGGER_RESUME:
|
| 139 |
- case SNDRV_PCM_TRIGGER_START:
|
| 140 |
start = 1;
|
| 141 |
break;
|
| 142 |
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
| 143 |
@@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
| 144 |
if (s->pcm->card != substream->pcm->card)
|
| 145 |
continue;
|
| 146 |
azx_dev = get_azx_dev(s);
|
| 147 |
+ if (rstart) {
|
| 148 |
+ azx_dev->start_flag = 1;
|
| 149 |
+ azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
|
| 150 |
+ }
|
| 151 |
if (start)
|
| 152 |
azx_stream_start(chip, azx_dev);
|
| 153 |
else
|
| 154 |
@@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
|
| 155 |
{
|
| 156 |
unsigned int pos;
|
| 157 |
|
| 158 |
+ if (azx_dev->start_flag &&
|
| 159 |
+ time_before_eq(jiffies, azx_dev->start_jiffies))
|
| 160 |
+ return -1; /* bogus (too early) interrupt */
|
| 161 |
+ azx_dev->start_flag = 0;
|
| 162 |
+
|
| 163 |
pos = azx_get_position(chip, azx_dev);
|
| 164 |
if (chip->position_fix == POS_FIX_AUTO) {
|
| 165 |
if (!pos) {
|
| 166 |
--
|
| 167 |
1.6.2.2
|
| 168 |
|