aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-05-11 04:21:46 -0400
committerJaroslav Kysela <perex@perex.cz>2010-05-11 04:21:46 -0400
commite54637205b00837bf00de916b0ae361c6aa0b139 (patch)
treea2f320d89b345dbd03e91b61427bdb87a48012ae /sound/pci/hda/hda_intel.c
parentbeaffc399397eb9427225f37c1e56c099571b2df (diff)
[ALSA] snd-hda-intel: use WALLCLK register to check for early irqs
Use 24Mhz WALLCLK register to ignore too early interrupts and wrong interrupt status. The bad timing confuses the higher ALSA layer and causes audio skipping. More information about behaviour and debugging can be found in kernel bz#15912. https://bugzilla.kernel.org/show_bug.cgi?id=15912 Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c42
1 files changed, 23 insertions, 19 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index cad9b70c27a..0a6c55bb7d6 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -174,7 +174,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
174#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ 174#define ICH6_GSTS_FSTS (1 << 1) /* flush status */
175#define ICH6_REG_INTCTL 0x20 175#define ICH6_REG_INTCTL 0x20
176#define ICH6_REG_INTSTS 0x24 176#define ICH6_REG_INTSTS 0x24
177#define ICH6_REG_WALCLK 0x30 177#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
178#define ICH6_REG_SYNC 0x34 178#define ICH6_REG_SYNC 0x34
179#define ICH6_REG_CORBLBASE 0x40 179#define ICH6_REG_CORBLBASE 0x40
180#define ICH6_REG_CORBUBASE 0x44 180#define ICH6_REG_CORBUBASE 0x44
@@ -340,8 +340,8 @@ struct azx_dev {
340 unsigned int period_bytes; /* size of the period in bytes */ 340 unsigned int period_bytes; /* size of the period in bytes */
341 unsigned int frags; /* number for period in the play buffer */ 341 unsigned int frags; /* number for period in the play buffer */
342 unsigned int fifo_size; /* FIFO size */ 342 unsigned int fifo_size; /* FIFO size */
343 unsigned long start_jiffies; /* start + minimum jiffies */ 343 unsigned long start_wallclk; /* start + minimum wallclk */
344 unsigned long min_jiffies; /* minimum jiffies before position is valid */ 344 unsigned long period_wallclk; /* wallclk for period */
345 345
346 void __iomem *sd_addr; /* stream descriptor pointer */ 346 void __iomem *sd_addr; /* stream descriptor pointer */
347 347
@@ -361,7 +361,6 @@ struct azx_dev {
361 unsigned int opened :1; 361 unsigned int opened :1;
362 unsigned int running :1; 362 unsigned int running :1;
363 unsigned int irq_pending :1; 363 unsigned int irq_pending :1;
364 unsigned int start_flag: 1; /* stream full start flag */
365 /* 364 /*
366 * For VIA: 365 * For VIA:
367 * A flag to ensure DMA position is 0 366 * A flag to ensure DMA position is 0
@@ -1676,8 +1675,9 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
1676 return err; 1675 return err;
1677 } 1676 }
1678 1677
1679 azx_dev->min_jiffies = (runtime->period_size * HZ) / 1678 /* wallclk has 24Mhz clock source */
1680 (runtime->rate * 2); 1679 azx_dev->period_wallclk = (((runtime->period_size * 24000) /
1680 runtime->rate) * 1000);
1681 azx_setup_controller(chip, azx_dev); 1681 azx_setup_controller(chip, azx_dev);
1682 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1682 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1683 azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; 1683 azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1731,14 +1731,15 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1731 if (s->pcm->card != substream->pcm->card) 1731 if (s->pcm->card != substream->pcm->card)
1732 continue; 1732 continue;
1733 azx_dev = get_azx_dev(s); 1733 azx_dev = get_azx_dev(s);
1734 if (rstart) { 1734 if (start) {
1735 azx_dev->start_flag = 1; 1735 azx_dev->start_wallclk = azx_readl(chip, WALLCLK);
1736 azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; 1736 if (!rstart)
1737 } 1737 azx_dev->start_wallclk -=
1738 if (start) 1738 azx_dev->period_wallclk;
1739 azx_stream_start(chip, azx_dev); 1739 azx_stream_start(chip, azx_dev);
1740 else 1740 } else {
1741 azx_stream_stop(chip, azx_dev); 1741 azx_stream_stop(chip, azx_dev);
1742 }
1742 azx_dev->running = start; 1743 azx_dev->running = start;
1743 } 1744 }
1744 spin_unlock(&chip->reg_lock); 1745 spin_unlock(&chip->reg_lock);
@@ -1885,13 +1886,14 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
1885 */ 1886 */
1886static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) 1887static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
1887{ 1888{
1889 u32 wallclk;
1888 unsigned int pos; 1890 unsigned int pos;
1889 int stream; 1891 int stream;
1890 1892
1891 if (azx_dev->start_flag && 1893 wallclk = azx_readl(chip, WALLCLK);
1892 time_before_eq(jiffies, azx_dev->start_jiffies)) 1894 if ((wallclk - azx_dev->start_wallclk) <
1895 (azx_dev->period_wallclk * 2) / 3)
1893 return -1; /* bogus (too early) interrupt */ 1896 return -1; /* bogus (too early) interrupt */
1894 azx_dev->start_flag = 0;
1895 1897
1896 stream = azx_dev->substream->stream; 1898 stream = azx_dev->substream->stream;
1897 pos = azx_get_position(chip, azx_dev); 1899 pos = azx_get_position(chip, azx_dev);
@@ -1906,13 +1908,12 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
1906 chip->position_fix[stream] = POS_FIX_POSBUF; 1908 chip->position_fix[stream] = POS_FIX_POSBUF;
1907 } 1909 }
1908 1910
1909 if (!bdl_pos_adj[chip->dev_index])
1910 return 1; /* no delayed ack */
1911 if (WARN_ONCE(!azx_dev->period_bytes, 1911 if (WARN_ONCE(!azx_dev->period_bytes,
1912 "hda-intel: zero azx_dev->period_bytes")) 1912 "hda-intel: zero azx_dev->period_bytes"))
1913 return 0; /* this shouldn't happen! */ 1913 return 0; /* this shouldn't happen! */
1914 if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) 1914 if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
1915 return 0; /* NG - it's below the period boundary */ 1915 return 0; /* NG - it's below the period boundary */
1916 azx_dev->start_wallclk = wallclk;
1916 return 1; /* OK, it's fine */ 1917 return 1; /* OK, it's fine */
1917} 1918}
1918 1919
@@ -1922,7 +1923,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
1922static void azx_irq_pending_work(struct work_struct *work) 1923static void azx_irq_pending_work(struct work_struct *work)
1923{ 1924{
1924 struct azx *chip = container_of(work, struct azx, irq_pending_work); 1925 struct azx *chip = container_of(work, struct azx, irq_pending_work);
1925 int i, pending; 1926 int i, pending, ok;
1926 1927
1927 if (!chip->irq_pending_warned) { 1928 if (!chip->irq_pending_warned) {
1928 printk(KERN_WARNING 1929 printk(KERN_WARNING
@@ -1941,11 +1942,14 @@ static void azx_irq_pending_work(struct work_struct *work)
1941 !azx_dev->substream || 1942 !azx_dev->substream ||
1942 !azx_dev->running) 1943 !azx_dev->running)
1943 continue; 1944 continue;
1944 if (azx_position_ok(chip, azx_dev)) { 1945 ok = azx_position_ok(chip, azx_dev);
1946 if (ok > 0) {
1945 azx_dev->irq_pending = 0; 1947 azx_dev->irq_pending = 0;
1946 spin_unlock(&chip->reg_lock); 1948 spin_unlock(&chip->reg_lock);
1947 snd_pcm_period_elapsed(azx_dev->substream); 1949 snd_pcm_period_elapsed(azx_dev->substream);
1948 spin_lock(&chip->reg_lock); 1950 spin_lock(&chip->reg_lock);
1951 } else if (ok < 0) {
1952 pending = 0; /* too early */
1949 } else 1953 } else
1950 pending++; 1954 pending++;
1951 } 1955 }