aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-04-15 05:21:13 -0400
committerTakashi Iwai <tiwai@suse.de>2009-04-15 05:21:13 -0400
commit45c27fc8c89d39956930abeff8433c33d07a8d5f (patch)
tree712e9882d975b050662d9a399a63b36785642f0c /sound
parent0882e8dd3aad33eca41696d463bb896e6c8817eb (diff)
parent2ec775e7053c82bc90858ede011b35aeb416995b (diff)
Merge branch 'master' of git://git.alsa-project.org/alsa-kernel into for-linus
* 'master' of git://git.alsa-project.org/alsa-kernel: [ALSA] intel8x0: add one retry to the ac97_clock measurement routine [ALSA] intel8x0: fix wrong conditions in ac97_clock measure routine [ALSA] intel8x0: do not use zero value from PICB register [ALSA] intel8x0: an attempt to make ac97_clock measurement more reliable [ALSA] pcm-midlevel: Add more strict buffer position checks based on jiffies [ALSA] hda_intel: fix unexpected ring buffer positions
Diffstat (limited to 'sound')
-rw-r--r--sound/core/pcm_lib.c47
-rw-r--r--sound/pci/hda/hda_intel.c39
-rw-r--r--sound/pci/intel8x0.c91
3 files changed, 134 insertions, 43 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index fbb2e391591e..63d088f2265f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -209,9 +209,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
209{ 209{
210 struct snd_pcm_runtime *runtime = substream->runtime; 210 struct snd_pcm_runtime *runtime = substream->runtime;
211 snd_pcm_uframes_t pos; 211 snd_pcm_uframes_t pos;
212 snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base; 212 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
213 snd_pcm_sframes_t delta; 213 snd_pcm_sframes_t hdelta, delta;
214 unsigned long jdelta;
214 215
216 old_hw_ptr = runtime->status->hw_ptr;
215 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 217 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
216 if (pos == SNDRV_PCM_POS_XRUN) { 218 if (pos == SNDRV_PCM_POS_XRUN) {
217 xrun(substream); 219 xrun(substream);
@@ -247,7 +249,30 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
247 new_hw_ptr = hw_base + pos; 249 new_hw_ptr = hw_base + pos;
248 } 250 }
249 } 251 }
250 if (delta > runtime->period_size) { 252 hdelta = new_hw_ptr - old_hw_ptr;
253 jdelta = jiffies - runtime->hw_ptr_jiffies;
254 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
255 delta = jdelta /
256 (((runtime->period_size * HZ) / runtime->rate)
257 + HZ/100);
258 hw_ptr_error(substream,
259 "hw_ptr skipping! [Q] "
260 "(pos=%ld, delta=%ld, period=%ld, "
261 "jdelta=%lu/%lu/%lu)\n",
262 (long)pos, (long)hdelta,
263 (long)runtime->period_size, jdelta,
264 ((hdelta * HZ) / runtime->rate), delta);
265 hw_ptr_interrupt = runtime->hw_ptr_interrupt +
266 runtime->period_size * delta;
267 if (hw_ptr_interrupt >= runtime->boundary)
268 hw_ptr_interrupt -= runtime->boundary;
269 /* rebase to interrupt position */
270 hw_base = new_hw_ptr = hw_ptr_interrupt;
271 /* align hw_base to buffer_size */
272 hw_base -= hw_base % runtime->buffer_size;
273 delta = 0;
274 }
275 if (delta > runtime->period_size + runtime->period_size / 2) {
251 hw_ptr_error(substream, 276 hw_ptr_error(substream,
252 "Lost interrupts? " 277 "Lost interrupts? "
253 "(stream=%i, delta=%ld, intr_ptr=%ld)\n", 278 "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
@@ -263,6 +288,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
263 288
264 runtime->hw_ptr_base = hw_base; 289 runtime->hw_ptr_base = hw_base;
265 runtime->status->hw_ptr = new_hw_ptr; 290 runtime->status->hw_ptr = new_hw_ptr;
291 runtime->hw_ptr_jiffies = jiffies;
266 runtime->hw_ptr_interrupt = hw_ptr_interrupt; 292 runtime->hw_ptr_interrupt = hw_ptr_interrupt;
267 293
268 return snd_pcm_update_hw_ptr_post(substream, runtime); 294 return snd_pcm_update_hw_ptr_post(substream, runtime);
@@ -275,6 +301,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
275 snd_pcm_uframes_t pos; 301 snd_pcm_uframes_t pos;
276 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; 302 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
277 snd_pcm_sframes_t delta; 303 snd_pcm_sframes_t delta;
304 unsigned long jdelta;
278 305
279 old_hw_ptr = runtime->status->hw_ptr; 306 old_hw_ptr = runtime->status->hw_ptr;
280 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 307 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -286,14 +313,15 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
286 new_hw_ptr = hw_base + pos; 313 new_hw_ptr = hw_base + pos;
287 314
288 delta = new_hw_ptr - old_hw_ptr; 315 delta = new_hw_ptr - old_hw_ptr;
316 jdelta = jiffies - runtime->hw_ptr_jiffies;
289 if (delta < 0) { 317 if (delta < 0) {
290 delta += runtime->buffer_size; 318 delta += runtime->buffer_size;
291 if (delta < 0) { 319 if (delta < 0) {
292 hw_ptr_error(substream, 320 hw_ptr_error(substream,
293 "Unexpected hw_pointer value [2] " 321 "Unexpected hw_pointer value [2] "
294 "(stream=%i, pos=%ld, old_ptr=%ld)\n", 322 "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
295 substream->stream, (long)pos, 323 substream->stream, (long)pos,
296 (long)old_hw_ptr); 324 (long)old_hw_ptr, jdelta);
297 return 0; 325 return 0;
298 } 326 }
299 hw_base += runtime->buffer_size; 327 hw_base += runtime->buffer_size;
@@ -301,12 +329,13 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
301 hw_base = 0; 329 hw_base = 0;
302 new_hw_ptr = hw_base + pos; 330 new_hw_ptr = hw_base + pos;
303 } 331 }
304 if (delta > runtime->period_size && runtime->periods > 1) { 332 if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
305 hw_ptr_error(substream, 333 hw_ptr_error(substream,
306 "hw_ptr skipping! " 334 "hw_ptr skipping! "
307 "(pos=%ld, delta=%ld, period=%ld)\n", 335 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
308 (long)pos, (long)delta, 336 (long)pos, (long)delta,
309 (long)runtime->period_size); 337 (long)runtime->period_size, jdelta,
338 ((delta * HZ) / runtime->rate));
310 return 0; 339 return 0;
311 } 340 }
312 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 341 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -315,6 +344,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
315 344
316 runtime->hw_ptr_base = hw_base; 345 runtime->hw_ptr_base = hw_base;
317 runtime->status->hw_ptr = new_hw_ptr; 346 runtime->status->hw_ptr = new_hw_ptr;
347 runtime->hw_ptr_jiffies = jiffies;
318 348
319 return snd_pcm_update_hw_ptr_post(substream, runtime); 349 return snd_pcm_update_hw_ptr_post(substream, runtime);
320} 350}
@@ -1441,6 +1471,7 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
1441 runtime->status->hw_ptr %= runtime->buffer_size; 1471 runtime->status->hw_ptr %= runtime->buffer_size;
1442 else 1472 else
1443 runtime->status->hw_ptr = 0; 1473 runtime->status->hw_ptr = 0;
1474 runtime->hw_ptr_jiffies = jiffies;
1444 snd_pcm_stream_unlock_irqrestore(substream, flags); 1475 snd_pcm_stream_unlock_irqrestore(substream, flags);
1445 return 0; 1476 return 0;
1446} 1477}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 7ba8db5d4c42..bc882f8f163c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -312,6 +312,9 @@ struct azx_dev {
312 unsigned int period_bytes; /* size of the period in bytes */ 312 unsigned int period_bytes; /* size of the period in bytes */
313 unsigned int frags; /* number for period in the play buffer */ 313 unsigned int frags; /* number for period in the play buffer */
314 unsigned int fifo_size; /* FIFO size */ 314 unsigned int fifo_size; /* FIFO size */
315 unsigned int start_flag: 1; /* stream full start flag */
316 unsigned long start_jiffies; /* start + minimum jiffies */
317 unsigned long min_jiffies; /* minimum jiffies before position is valid */
315 318
316 void __iomem *sd_addr; /* stream descriptor pointer */ 319 void __iomem *sd_addr; /* stream descriptor pointer */
317 320
@@ -330,7 +333,6 @@ struct azx_dev {
330 unsigned int opened :1; 333 unsigned int opened :1;
331 unsigned int running :1; 334 unsigned int running :1;
332 unsigned int irq_pending :1; 335 unsigned int irq_pending :1;
333 unsigned int irq_ignore :1;
334 /* 336 /*
335 * For VIA: 337 * For VIA:
336 * A flag to ensure DMA position is 0 338 * A flag to ensure DMA position is 0
@@ -975,7 +977,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
975 struct azx *chip = dev_id; 977 struct azx *chip = dev_id;
976 struct azx_dev *azx_dev; 978 struct azx_dev *azx_dev;
977 u32 status; 979 u32 status;
978 int i; 980 int i, ok;
979 981
980 spin_lock(&chip->reg_lock); 982 spin_lock(&chip->reg_lock);
981 983
@@ -991,18 +993,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
991 azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); 993 azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
992 if (!azx_dev->substream || !azx_dev->running) 994 if (!azx_dev->substream || !azx_dev->running)
993 continue; 995 continue;
994 /* ignore the first dummy IRQ (due to pos_adj) */
995 if (azx_dev->irq_ignore) {
996 azx_dev->irq_ignore = 0;
997 continue;
998 }
999 /* check whether this IRQ is really acceptable */ 996 /* check whether this IRQ is really acceptable */
1000 if (azx_position_ok(chip, azx_dev)) { 997 ok = azx_position_ok(chip, azx_dev);
998 if (ok == 1) {
1001 azx_dev->irq_pending = 0; 999 azx_dev->irq_pending = 0;
1002 spin_unlock(&chip->reg_lock); 1000 spin_unlock(&chip->reg_lock);
1003 snd_pcm_period_elapsed(azx_dev->substream); 1001 snd_pcm_period_elapsed(azx_dev->substream);
1004 spin_lock(&chip->reg_lock); 1002 spin_lock(&chip->reg_lock);
1005 } else if (chip->bus && chip->bus->workq) { 1003 } else if (ok == 0 && chip->bus && chip->bus->workq) {
1006 /* bogus IRQ, process it later */ 1004 /* bogus IRQ, process it later */
1007 azx_dev->irq_pending = 1; 1005 azx_dev->irq_pending = 1;
1008 queue_work(chip->bus->workq, 1006 queue_work(chip->bus->workq,
@@ -1088,7 +1086,6 @@ static int azx_setup_periods(struct azx *chip,
1088 bdl = (u32 *)azx_dev->bdl.area; 1086 bdl = (u32 *)azx_dev->bdl.area;
1089 ofs = 0; 1087 ofs = 0;
1090 azx_dev->frags = 0; 1088 azx_dev->frags = 0;
1091 azx_dev->irq_ignore = 0;
1092 pos_adj = bdl_pos_adj[chip->dev_index]; 1089 pos_adj = bdl_pos_adj[chip->dev_index];
1093 if (pos_adj > 0) { 1090 if (pos_adj > 0) {
1094 struct snd_pcm_runtime *runtime = substream->runtime; 1091 struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1109,7 +1106,6 @@ static int azx_setup_periods(struct azx *chip,
1109 &bdl, ofs, pos_adj, 1); 1106 &bdl, ofs, pos_adj, 1);
1110 if (ofs < 0) 1107 if (ofs < 0)
1111 goto error; 1108 goto error;
1112 azx_dev->irq_ignore = 1;
1113 } 1109 }
1114 } else 1110 } else
1115 pos_adj = 0; 1111 pos_adj = 0;
@@ -1155,6 +1151,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
1155 while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && 1151 while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
1156 --timeout) 1152 --timeout)
1157 ; 1153 ;
1154
1155 /* reset first position - may not be synced with hw at this time */
1156 *azx_dev->posbuf = 0;
1158} 1157}
1159 1158
1160/* 1159/*
@@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
1409 snd_pcm_set_sync(substream); 1408 snd_pcm_set_sync(substream);
1410 mutex_unlock(&chip->open_mutex); 1409 mutex_unlock(&chip->open_mutex);
1411 1410
1412 azx_stream_reset(chip, azx_dev);
1413 return 0; 1411 return 0;
1414} 1412}
1415 1413
@@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
1474 unsigned int bufsize, period_bytes, format_val; 1472 unsigned int bufsize, period_bytes, format_val;
1475 int err; 1473 int err;
1476 1474
1475 azx_stream_reset(chip, azx_dev);
1477 format_val = snd_hda_calc_stream_format(runtime->rate, 1476 format_val = snd_hda_calc_stream_format(runtime->rate,
1478 runtime->channels, 1477 runtime->channels,
1479 runtime->format, 1478 runtime->format,
@@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
1502 return err; 1501 return err;
1503 } 1502 }
1504 1503
1504 azx_dev->min_jiffies = (runtime->period_size * HZ) /
1505 (runtime->rate * 2);
1505 azx_setup_controller(chip, azx_dev); 1506 azx_setup_controller(chip, azx_dev);
1506 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1507 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1507 azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; 1508 azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1518 struct azx *chip = apcm->chip; 1519 struct azx *chip = apcm->chip;
1519 struct azx_dev *azx_dev; 1520 struct azx_dev *azx_dev;
1520 struct snd_pcm_substream *s; 1521 struct snd_pcm_substream *s;
1521 int start, nsync = 0, sbits = 0; 1522 int rstart = 0, start, nsync = 0, sbits = 0;
1522 int nwait, timeout; 1523 int nwait, timeout;
1523 1524
1524 switch (cmd) { 1525 switch (cmd) {
1526 case SNDRV_PCM_TRIGGER_START:
1527 rstart = 1;
1525 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1528 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1526 case SNDRV_PCM_TRIGGER_RESUME: 1529 case SNDRV_PCM_TRIGGER_RESUME:
1527 case SNDRV_PCM_TRIGGER_START:
1528 start = 1; 1530 start = 1;
1529 break; 1531 break;
1530 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1532 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1554 if (s->pcm->card != substream->pcm->card) 1556 if (s->pcm->card != substream->pcm->card)
1555 continue; 1557 continue;
1556 azx_dev = get_azx_dev(s); 1558 azx_dev = get_azx_dev(s);
1559 if (rstart) {
1560 azx_dev->start_flag = 1;
1561 azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
1562 }
1557 if (start) 1563 if (start)
1558 azx_stream_start(chip, azx_dev); 1564 azx_stream_start(chip, azx_dev);
1559 else 1565 else
@@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
1703{ 1709{
1704 unsigned int pos; 1710 unsigned int pos;
1705 1711
1712 if (azx_dev->start_flag &&
1713 time_before_eq(jiffies, azx_dev->start_jiffies))
1714 return -1; /* bogus (too early) interrupt */
1715 azx_dev->start_flag = 0;
1716
1706 pos = azx_get_position(chip, azx_dev); 1717 pos = azx_get_position(chip, azx_dev);
1707 if (chip->position_fix == POS_FIX_AUTO) { 1718 if (chip->position_fix == POS_FIX_AUTO) {
1708 if (!pos) { 1719 if (!pos) {
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 57648810eaf1..5dced5b79387 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -355,6 +355,9 @@ struct ichdev {
355 unsigned int fragsize1; 355 unsigned int fragsize1;
356 unsigned int position; 356 unsigned int position;
357 unsigned int pos_shift; 357 unsigned int pos_shift;
358 unsigned int last_pos;
359 unsigned long last_pos_jiffies;
360 unsigned int jiffy_to_bytes;
358 int frags; 361 int frags;
359 int lvi; 362 int lvi;
360 int lvi_frag; 363 int lvi_frag;
@@ -838,7 +841,10 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
838 ichdev->suspended = 0; 841 ichdev->suspended = 0;
839 /* fallthru */ 842 /* fallthru */
840 case SNDRV_PCM_TRIGGER_START: 843 case SNDRV_PCM_TRIGGER_START:
844 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
841 val = ICH_IOCE | ICH_STARTBM; 845 val = ICH_IOCE | ICH_STARTBM;
846 ichdev->last_pos = ichdev->position;
847 ichdev->last_pos_jiffies = jiffies;
842 break; 848 break;
843 case SNDRV_PCM_TRIGGER_SUSPEND: 849 case SNDRV_PCM_TRIGGER_SUSPEND:
844 ichdev->suspended = 1; 850 ichdev->suspended = 1;
@@ -849,9 +855,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
849 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 855 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
850 val = ICH_IOCE; 856 val = ICH_IOCE;
851 break; 857 break;
852 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
853 val = ICH_IOCE | ICH_STARTBM;
854 break;
855 default: 858 default:
856 return -EINVAL; 859 return -EINVAL;
857 } 860 }
@@ -1045,6 +1048,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
1045 ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; 1048 ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
1046 } 1049 }
1047 snd_intel8x0_setup_periods(chip, ichdev); 1050 snd_intel8x0_setup_periods(chip, ichdev);
1051 ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ;
1048 return 0; 1052 return 0;
1049} 1053}
1050 1054
@@ -1053,7 +1057,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
1053 struct intel8x0 *chip = snd_pcm_substream_chip(substream); 1057 struct intel8x0 *chip = snd_pcm_substream_chip(substream);
1054 struct ichdev *ichdev = get_ichdev(substream); 1058 struct ichdev *ichdev = get_ichdev(substream);
1055 size_t ptr1, ptr; 1059 size_t ptr1, ptr;
1056 int civ, timeout = 100; 1060 int civ, timeout = 10;
1057 unsigned int position; 1061 unsigned int position;
1058 1062
1059 spin_lock(&chip->reg_lock); 1063 spin_lock(&chip->reg_lock);
@@ -1069,9 +1073,19 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
1069 ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) 1073 ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
1070 break; 1074 break;
1071 } while (timeout--); 1075 } while (timeout--);
1072 ptr1 <<= ichdev->pos_shift; 1076 if (ptr1 != 0) {
1073 ptr = ichdev->fragsize1 - ptr1; 1077 ptr1 <<= ichdev->pos_shift;
1074 ptr += position; 1078 ptr = ichdev->fragsize1 - ptr1;
1079 ptr += position;
1080 ichdev->last_pos = ptr;
1081 ichdev->last_pos_jiffies = jiffies;
1082 } else {
1083 ptr1 = jiffies - ichdev->last_pos_jiffies;
1084 if (ptr1)
1085 ptr1 -= 1;
1086 ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes;
1087 ptr %= ichdev->size;
1088 }
1075 spin_unlock(&chip->reg_lock); 1089 spin_unlock(&chip->reg_lock);
1076 if (ptr >= ichdev->size) 1090 if (ptr >= ichdev->size)
1077 return 0; 1091 return 0;
@@ -2661,12 +2675,14 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2661 struct snd_pcm_substream *subs; 2675 struct snd_pcm_substream *subs;
2662 struct ichdev *ichdev; 2676 struct ichdev *ichdev;
2663 unsigned long port; 2677 unsigned long port;
2664 unsigned long pos, t; 2678 unsigned long pos, pos1, t;
2665 struct timeval start_time, stop_time; 2679 int civ, timeout = 1000, attempt = 1;
2680 struct timespec start_time, stop_time;
2666 2681
2667 if (chip->ac97_bus->clock != 48000) 2682 if (chip->ac97_bus->clock != 48000)
2668 return; /* specified in module option */ 2683 return; /* specified in module option */
2669 2684
2685 __again:
2670 subs = chip->pcm[0]->streams[0].substream; 2686 subs = chip->pcm[0]->streams[0].substream;
2671 if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { 2687 if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
2672 snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); 2688 snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
@@ -2674,7 +2690,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2674 } 2690 }
2675 ichdev = &chip->ichd[ICHD_PCMOUT]; 2691 ichdev = &chip->ichd[ICHD_PCMOUT];
2676 ichdev->physbuf = subs->dma_buffer.addr; 2692 ichdev->physbuf = subs->dma_buffer.addr;
2677 ichdev->size = chip->ichd[ICHD_PCMOUT].fragsize = INTEL8X0_TESTBUF_SIZE; 2693 ichdev->size = ichdev->fragsize = INTEL8X0_TESTBUF_SIZE;
2678 ichdev->substream = NULL; /* don't process interrupts */ 2694 ichdev->substream = NULL; /* don't process interrupts */
2679 2695
2680 /* set rate */ 2696 /* set rate */
@@ -2693,16 +2709,31 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2693 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); 2709 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
2694 iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); 2710 iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
2695 } 2711 }
2696 do_gettimeofday(&start_time); 2712 do_posix_clock_monotonic_gettime(&start_time);
2697 spin_unlock_irq(&chip->reg_lock); 2713 spin_unlock_irq(&chip->reg_lock);
2698 msleep(50); 2714 msleep(50);
2699 spin_lock_irq(&chip->reg_lock); 2715 spin_lock_irq(&chip->reg_lock);
2700 /* check the position */ 2716 /* check the position */
2701 pos = ichdev->fragsize1; 2717 do {
2702 pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift; 2718 civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
2703 pos += ichdev->position; 2719 pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
2720 if (pos1 == 0) {
2721 udelay(10);
2722 continue;
2723 }
2724 if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
2725 pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
2726 break;
2727 } while (timeout--);
2728 if (pos1 == 0) { /* oops, this value is not reliable */
2729 pos = 0;
2730 } else {
2731 pos = ichdev->fragsize1;
2732 pos -= pos1 << ichdev->pos_shift;
2733 pos += ichdev->position;
2734 }
2704 chip->in_measurement = 0; 2735 chip->in_measurement = 0;
2705 do_gettimeofday(&stop_time); 2736 do_posix_clock_monotonic_gettime(&stop_time);
2706 /* stop */ 2737 /* stop */
2707 if (chip->device_type == DEVICE_ALI) { 2738 if (chip->device_type == DEVICE_ALI) {
2708 iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); 2739 iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
@@ -2717,19 +2748,37 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2717 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); 2748 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
2718 spin_unlock_irq(&chip->reg_lock); 2749 spin_unlock_irq(&chip->reg_lock);
2719 2750
2751 if (pos == 0) {
2752 snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
2753 __retry:
2754 if (attempt < 2) {
2755 attempt++;
2756 goto __again;
2757 }
2758 return;
2759 }
2760
2761 pos /= 4;
2720 t = stop_time.tv_sec - start_time.tv_sec; 2762 t = stop_time.tv_sec - start_time.tv_sec;
2721 t *= 1000000; 2763 t *= 1000000;
2722 t += stop_time.tv_usec - start_time.tv_usec; 2764 t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000;
2723 printk(KERN_INFO "%s: measured %lu usecs\n", __func__, t); 2765 printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
2724 if (t == 0) { 2766 if (t == 0) {
2725 snd_printk(KERN_ERR "?? calculation error..\n"); 2767 snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n");
2726 return; 2768 goto __retry;
2727 } 2769 }
2728 pos = (pos / 4) * 1000; 2770 pos *= 1000;
2729 pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; 2771 pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
2730 if (pos < 40000 || pos >= 60000) 2772 if (pos < 40000 || pos >= 60000) {
2731 /* abnormal value. hw problem? */ 2773 /* abnormal value. hw problem? */
2732 printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); 2774 printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
2775 goto __retry;
2776 } else if (pos > 40500 && pos < 41500)
2777 /* first exception - 41000Hz reference clock */
2778 chip->ac97_bus->clock = 41000;
2779 else if (pos > 43600 && pos < 44600)
2780 /* second exception - 44100HZ reference clock */
2781 chip->ac97_bus->clock = 44100;
2733 else if (pos < 47500 || pos > 48500) 2782 else if (pos < 47500 || pos > 48500)
2734 /* not 48000Hz, tuning the clock.. */ 2783 /* not 48000Hz, tuning the clock.. */
2735 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; 2784 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;