rpms/kernel/F-10 alsa-dont-reset-stream-at-each-prepare-callb.patch, NONE, 1.1 alsa-hda-dont-reset-BDL-unnecessarily.patch, NONE, 1.1 alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch, NONE, 1.1 alsa-hda_intel-prealloc-4mb-dmabuffer.patch, NONE, 1.1 alsa-pcm-always-reset-invalid-position.patch, NONE, 1.1 alsa-pcm-fix-delta-calc-at-overlap.patch, NONE, 1.1 alsa-pcm-midlevel-add-more-strict-buffer-position.patch, NONE, 1.1 alsa-pcm-safer-boundary-checks.patch, NONE, 1.1 kernel.spec, 1.1321, 1.1322

Chuck Ebbert cebbert at fedoraproject.org
Mon Apr 13 18:21:12 UTC 2009


Author: cebbert

Update of /cvs/pkgs/rpms/kernel/F-10
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv31585

Modified Files:
	kernel.spec 
Added Files:
	alsa-dont-reset-stream-at-each-prepare-callb.patch 
	alsa-hda-dont-reset-BDL-unnecessarily.patch 
	alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch 
	alsa-hda_intel-prealloc-4mb-dmabuffer.patch 
	alsa-pcm-always-reset-invalid-position.patch 
	alsa-pcm-fix-delta-calc-at-overlap.patch 
	alsa-pcm-midlevel-add-more-strict-buffer-position.patch 
	alsa-pcm-safer-boundary-checks.patch 
Log Message:
Copy ALSA pulseaudio fixes from F-11.

alsa-dont-reset-stream-at-each-prepare-callb.patch:

--- NEW FILE alsa-dont-reset-stream-at-each-prepare-callb.patch ---
>From fc546201dfe40d09c1a1e82384dc3774025984da Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai at suse.de>
Date: Wed, 18 Mar 2009 15:15:37 +0100
Subject: ALSA: hda - Don't reset stream at each prepare callback

Don't reset the stream at each prepare callback but do it only once
after the open.

Signed-off-by: Takashi Iwai <tiwai at suse.de>
---
 sound/pci/hda/hda_intel.c |   33 ++++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index b7a61a1..931a62d 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -858,13 +858,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
 		      SD_CTL_DMA_START | SD_INT_MASK);
 }
 
-/* stop a stream */
-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+/* stop DMA */
+static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
 {
-	/* stop DMA */
 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
 		      ~(SD_CTL_DMA_START | SD_INT_MASK));
 	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+}
+
+/* stop a stream */
+static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
+{
+	azx_stream_clear(chip, azx_dev);
 	/* disable SIE */
 	azx_writeb(chip, INTCTL,
 		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
@@ -1125,18 +1130,14 @@ static int azx_setup_periods(struct azx *chip,
 	return -EINVAL;
 }
 
-/*
- * set up the SD for streaming
- */
-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+/* reset stream */
+static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
 {
 	unsigned char val;
 	int timeout;
 
-	/* make sure the run bit is zero for SD */
-	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
-		      ~SD_CTL_DMA_START);
-	/* reset stream */
+	azx_stream_clear(chip, azx_dev);
+
 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
 		      SD_CTL_STREAM_RESET);
 	udelay(3);
@@ -1153,7 +1154,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
 	while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
 	       --timeout)
 		;
+}
 
+/*
+ * set up the SD for streaming
+ */
+static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
+{
+	/* make sure the run bit is zero for SD */
+	azx_stream_clear(chip, azx_dev);
 	/* program the stream_tag */
 	azx_sd_writel(azx_dev, SD_CTL,
 		      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
@@ -1399,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
 	runtime->private_data = azx_dev;
 	snd_pcm_set_sync(substream);
 	mutex_unlock(&chip->open_mutex);
+
+	azx_stream_reset(chip, azx_dev);
 	return 0;
 }
 
-- 
1.6.2.2


alsa-hda-dont-reset-BDL-unnecessarily.patch:

--- NEW FILE alsa-hda-dont-reset-BDL-unnecessarily.patch ---
>From b98a9f6d1619b7fe32c2a6a4e5190121830f979b Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai at suse.de>
Date: Wed, 18 Mar 2009 15:09:13 +0100
Subject: ALSA: hda - Don't reset BDL unnecessarily

So far, the prepare callback is called multiple times, BDL entries
are reset and re-programmed at each time.

This patch adds the check to avoid the reset of BDL entries when the
same parameters are used.

Signed-off-by: Takashi Iwai <tiwai at suse.de>
---
 sound/pci/hda/hda_intel.c |   46 +++++++++++++++++++++++++++++++-------------
 1 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index f3b5723..b7a61a1 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1075,8 +1075,7 @@ static int azx_setup_periods(struct azx *chip,
 	azx_sd_writel(azx_dev, SD_BDLPL, 0);
 	azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
-	period_bytes = snd_pcm_lib_period_bytes(substream);
-	azx_dev->period_bytes = period_bytes;
+	period_bytes = azx_dev->period_bytes;
 	periods = azx_dev->bufsize / period_bytes;
 
 	/* program the initial BDL entries */
@@ -1123,9 +1122,6 @@ static int azx_setup_periods(struct azx *chip,
  error:
 	snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
 		   azx_dev->bufsize, period_bytes);
-	/* reset */
-	azx_sd_writel(azx_dev, SD_BDLPL, 0);
-	azx_sd_writel(azx_dev, SD_BDLPU, 0);
 	return -EINVAL;
 }
 
@@ -1429,6 +1425,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
 static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *hw_params)
 {
+	struct azx_dev *azx_dev = get_azx_dev(substream);
+
+	azx_dev->bufsize = 0;
+	azx_dev->period_bytes = 0;
+	azx_dev->format_val = 0;
 	return snd_pcm_lib_malloc_pages(substream,
 					params_buffer_bytes(hw_params));
 }
@@ -1443,6 +1444,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 	azx_sd_writel(azx_dev, SD_BDLPL, 0);
 	azx_sd_writel(azx_dev, SD_BDLPU, 0);
 	azx_sd_writel(azx_dev, SD_CTL, 0);
+	azx_dev->bufsize = 0;
+	azx_dev->period_bytes = 0;
+	azx_dev->format_val = 0;
 
 	hinfo->ops.cleanup(hinfo, apcm->codec, substream);
 
@@ -1456,23 +1460,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int bufsize, period_bytes, format_val;
+	int err;
 
-	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
-	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
-							 runtime->channels,
-							 runtime->format,
-							 hinfo->maxbps);
-	if (!azx_dev->format_val) {
+	format_val = snd_hda_calc_stream_format(runtime->rate,
+						runtime->channels,
+						runtime->format,
+						hinfo->maxbps);
+	if (!format_val) {
 		snd_printk(KERN_ERR SFX
 			   "invalid format_val, rate=%d, ch=%d, format=%d\n",
 			   runtime->rate, runtime->channels, runtime->format);
 		return -EINVAL;
 	}
 
+	bufsize = snd_pcm_lib_buffer_bytes(substream);
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+
 	snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
-		    azx_dev->bufsize, azx_dev->format_val);
-	if (azx_setup_periods(chip, substream, azx_dev) < 0)
-		return -EINVAL;
+		    bufsize, format_val);
+
+	if (bufsize != azx_dev->bufsize ||
+	    period_bytes != azx_dev->period_bytes ||
+	    format_val != azx_dev->format_val) {
+		azx_dev->bufsize = bufsize;
+		azx_dev->period_bytes = period_bytes;
+		azx_dev->format_val = format_val;
+		err = azx_setup_periods(chip, substream, azx_dev);
+		if (err < 0)
+			return err;
+	}
+
 	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;
-- 
1.6.2.2


alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch:

--- NEW FILE alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch ---
>From 8820b651ddf48830af44520a13e63f5b9c5b9f9f Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex at perex.cz>
Date: Fri, 10 Apr 2009 12:20:45 +0200
Subject: [ALSA] hda_intel: fix unexpected ring buffer positions

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 at perex.cz>
---
 sound/pci/hda/hda_intel.c |   39 +++++++++++++++++++++++++--------------
 1 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 931a62d..7112e0e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -312,6 +312,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 */
 
@@ -330,7 +333,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
@@ -974,7 +976,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 	struct azx *chip = dev_id;
 	struct azx_dev *azx_dev;
 	u32 status;
-	int i;
+	int i, ok;
 
 	spin_lock(&chip->reg_lock);
 
@@ -990,18 +992,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 			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,
@@ -1087,7 +1085,6 @@ static int azx_setup_periods(struct azx *chip,
 	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;
@@ -1108,7 +1105,6 @@ static int azx_setup_periods(struct azx *chip,
 					 &bdl, ofs, pos_adj, 1);
 			if (ofs < 0)
 				goto error;
-			azx_dev->irq_ignore = 1;
 		}
 	} else
 		pos_adj = 0;
@@ -1154,6 +1150,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
 	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;
 }
 
 /*
@@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
 	snd_pcm_set_sync(substream);
 	mutex_unlock(&chip->open_mutex);
 
-	azx_stream_reset(chip, azx_dev);
 	return 0;
 }
 
@@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 	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,
@@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 			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;
@@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	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:
@@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		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
@@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
 {
 	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) {
-- 
1.6.2.2


alsa-hda_intel-prealloc-4mb-dmabuffer.patch:

--- NEW FILE alsa-hda_intel-prealloc-4mb-dmabuffer.patch ---
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c8d9178..7d3bb15 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1774,6 +1774,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
 	struct azx_pcm *apcm;
 	int pcm_dev = cpcm->device;
 	int s, err;
+	size_t prealloc_min = 64*1024;	/* 64KB */
 
 	if (pcm_dev >= AZX_MAX_PCMS) {
 		snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
@@ -1807,10 +1808,21 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
 		if (cpcm->stream[s].substreams)
 			snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
 	}
+
 	/* buffer pre-allocation */
+
+	/* subtle, don't allocate a big buffer for modems...
+	 * also, don't just test 32BIT_MASK, since azx supports
+	 * 64-bit DMA in some cases.
+	 */
+	/* lennart wants a 2.2MB buffer for 2sec of 48khz */
+	if (pcm->dev_class == SNDRV_PCM_CLASS_GENERIC &&
+	    chip->pci->dma_mask >= DMA_32BIT_MASK)
+		prealloc_min = 4 * 1024 * 1024;	/* 4MB */
+
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
-					      1024 * 64, 32 * 1024 * 1024);
+					      prealloc_min, 32 * 1024 * 1024);
 	return 0;
 }
 

alsa-pcm-always-reset-invalid-position.patch:

--- NEW FILE alsa-pcm-always-reset-invalid-position.patch ---
From: Takashi Iwai <tiwai at suse.de>
Date: Thu, 19 Mar 2009 09:01:47 +0000 (+0100)
Subject: ALSA: pcm - Reset invalid position even without debug option
X-Git-Url: http://git.alsa-project.org/?p=alsa-kernel.git;a=commitdiff_plain;h=f28f43ce9ae6573952d2348bb6da859cad762143

ALSA: pcm - Reset invalid position even without debug option

Always reset the invalind hw_ptr position returned by the pointer
callback.  The behavior should be consitent independently from the
debug option.

Also, add the printk_ratelimit() check to avoid flooding debug
prints.

Signed-off-by: Takashi Iwai <tiwai at suse.de>
Signed-off-by: Jaroslav Kysela <perex at perex.cz>
---

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 3026547..92ed6d8 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -159,11 +159,15 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
 	pos = substream->ops->pointer(substream);
 	if (pos == SNDRV_PCM_POS_XRUN)
 		return pos; /* XRUN */
-#ifdef CONFIG_SND_DEBUG
 	if (pos >= runtime->buffer_size) {
-		snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
+		if (printk_ratelimit()) {
+			snd_printd(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, "
+				   "buffer size = 0x%lx, period size = 0x%lx\n",
+				   substream->stream, pos, runtime->buffer_size,
+				   runtime->period_size);
+		}
+		pos = 0;
 	}
-#endif
 	pos -= pos % runtime->min_align;
 	return pos;
 }

alsa-pcm-fix-delta-calc-at-overlap.patch:

--- NEW FILE alsa-pcm-fix-delta-calc-at-overlap.patch ---
From: Takashi Iwai <tiwai at suse.de>
Date: Thu, 19 Mar 2009 09:08:49 +0000 (+0100)
Subject: ALSA: pcm - Fix delta calculation at boundary overlap
X-Git-Url: http://git.alsa-project.org/?p=alsa-kernel.git;a=commitdiff_plain;h=09a067199b6caa61818fc04f4759048dff13b21c

ALSA: pcm - Fix delta calculation at boundary overlap

When the hw_ptr_interrupt reaches the boundary, it must check whether
the hw_base was already lapped and corret the delta value appropriately.

Also, rebasing the hw_ptr needs a correction because buffer_size isn't
always aligned to period_size.

Signed-off-by: Takashi Iwai <tiwai at suse.de>
Signed-off-by: Jaroslav Kysela <perex at perex.cz>
---

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 92ed6d8..063c675 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -221,8 +221,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 	new_hw_ptr = hw_base + pos;
 	hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
 	delta = new_hw_ptr - hw_ptr_interrupt;
-	if (hw_ptr_interrupt == runtime->boundary)
-		hw_ptr_interrupt = 0;
+	if (hw_ptr_interrupt >= runtime->boundary) {
+		hw_ptr_interrupt %= runtime->boundary;
+		if (!hw_base) /* hw_base was already lapped; recalc delta */
+			delta = new_hw_ptr - hw_ptr_interrupt;
+	}
 	if (delta < 0) {
 		delta += runtime->buffer_size;
 		if (delta < 0) {
@@ -233,6 +236,8 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 				     (long)hw_ptr_interrupt);
 			/* rebase to interrupt position */
 			hw_base = new_hw_ptr = hw_ptr_interrupt;
+			/* align hw_base to buffer_size */
+			hw_base -= hw_base % runtime->buffer_size;
 			delta = 0;
 		} else {
 			hw_base += runtime->buffer_size;

alsa-pcm-midlevel-add-more-strict-buffer-position.patch:

--- NEW FILE alsa-pcm-midlevel-add-more-strict-buffer-position.patch ---
>From bbf6ad1399e9516b0a95de3ad58ffbaed670e4cc Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex at perex.cz>
Date: Fri, 10 Apr 2009 12:28:58 +0200
Subject: [ALSA] pcm-midlevel: Add more strict buffer position checks based on jiffies

Some drivers like Intel8x0 or Intel HDA are broken for some hardware variants.
This patch adds more strict buffer position checks based on jiffies when
internal hw_ptr is updated. Enable xrun_debug to see mangling of wrong
positions.

As a side effect, the hw_ptr interrupt update routine might do slightly better
job when many interrupts are lost.

Signed-off-by: Jaroslav Kysela <perex at perex.cz>
---
 include/sound/pcm.h  |    3 ++-
 sound/core/pcm_lib.c |   47 +++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 8904b19..c172968 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -268,7 +268,8 @@ struct snd_pcm_runtime {
 	int overrange;
 	snd_pcm_uframes_t avail_max;
 	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
-	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/
+	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
+	unsigned long hw_ptr_jiffies;	/* Time when hw_ptr is updated */
 
 	/* -- HW params -- */
 	snd_pcm_access_t access;	/* access mode */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index fbb2e39..63d088f 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)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t pos;
-	snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
-	snd_pcm_sframes_t delta;
+	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
+	snd_pcm_sframes_t hdelta, delta;
+	unsigned long jdelta;
 
+	old_hw_ptr = runtime->status->hw_ptr;
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
 	if (pos == SNDRV_PCM_POS_XRUN) {
 		xrun(substream);
@@ -247,7 +249,30 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 			new_hw_ptr = hw_base + pos;
 		}
 	}
-	if (delta > runtime->period_size) {
+	hdelta = new_hw_ptr - old_hw_ptr;
+	jdelta = jiffies - runtime->hw_ptr_jiffies;
+	if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
+		delta = jdelta /
+			(((runtime->period_size * HZ) / runtime->rate)
+								+ HZ/100);
+		hw_ptr_error(substream,
+			     "hw_ptr skipping! [Q] "
+			     "(pos=%ld, delta=%ld, period=%ld, "
+			     "jdelta=%lu/%lu/%lu)\n",
+			     (long)pos, (long)hdelta,
+			     (long)runtime->period_size, jdelta,
+			     ((hdelta * HZ) / runtime->rate), delta);
+		hw_ptr_interrupt = runtime->hw_ptr_interrupt +
+				   runtime->period_size * delta;
+		if (hw_ptr_interrupt >= runtime->boundary)
+			hw_ptr_interrupt -= runtime->boundary;
+		/* rebase to interrupt position */
+		hw_base = new_hw_ptr = hw_ptr_interrupt;
+		/* align hw_base to buffer_size */
+		hw_base -= hw_base % runtime->buffer_size;
+		delta = 0;
+	}
+	if (delta > runtime->period_size + runtime->period_size / 2) {
 		hw_ptr_error(substream,
 			     "Lost interrupts? "
 			     "(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)
 
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
+	runtime->hw_ptr_jiffies = jiffies;
 	runtime->hw_ptr_interrupt = hw_ptr_interrupt;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
@@ -275,6 +301,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t pos;
 	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
 	snd_pcm_sframes_t delta;
+	unsigned long jdelta;
 
 	old_hw_ptr = runtime->status->hw_ptr;
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -286,14 +313,15 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 	new_hw_ptr = hw_base + pos;
 
 	delta = new_hw_ptr - old_hw_ptr;
+	jdelta = jiffies - runtime->hw_ptr_jiffies;
 	if (delta < 0) {
 		delta += runtime->buffer_size;
 		if (delta < 0) {
 			hw_ptr_error(substream, 
 				     "Unexpected hw_pointer value [2] "
-				     "(stream=%i, pos=%ld, old_ptr=%ld)\n",
+				     "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
 				     substream->stream, (long)pos,
-				     (long)old_hw_ptr);
+				     (long)old_hw_ptr, jdelta);
 			return 0;
 		}
 		hw_base += runtime->buffer_size;
@@ -301,12 +329,13 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 			hw_base = 0;
 		new_hw_ptr = hw_base + pos;
 	}
-	if (delta > runtime->period_size && runtime->periods > 1) {
+	if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
 		hw_ptr_error(substream,
 			     "hw_ptr skipping! "
-			     "(pos=%ld, delta=%ld, period=%ld)\n",
+			     "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
 			     (long)pos, (long)delta,
-			     (long)runtime->period_size);
+			     (long)runtime->period_size, jdelta,
+			     ((delta * HZ) / runtime->rate));
 		return 0;
 	}
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -315,6 +344,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
+	runtime->hw_ptr_jiffies = jiffies;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -1441,6 +1471,7 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
 		runtime->status->hw_ptr %= runtime->buffer_size;
 	else
 		runtime->status->hw_ptr = 0;
+	runtime->hw_ptr_jiffies = jiffies;
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 	return 0;
 }
-- 
1.6.2.2


alsa-pcm-safer-boundary-checks.patch:

--- NEW FILE alsa-pcm-safer-boundary-checks.patch ---
From: Takashi Iwai <tiwai at suse.de>
Date: Fri, 20 Mar 2009 15:26:15 +0000 (+0100)
Subject: ALSA: pcm - Safer boundary checks
X-Git-Url: http://git.alsa-project.org/?p=alsa-kernel.git;a=commitdiff_plain;h=d9b59892fb7108f6ee33a4fcdc257587b68f2ed6

ALSA: pcm - Safer boundary checks

Make the boundary checks a bit safer.
These caese are rare or theoretically won't happen, but nothing
bad to keep the checks safer...

Signed-off-by: Takashi Iwai <tiwai at suse.de>
Signed-off-by: Jaroslav Kysela <perex at perex.cz>
---

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 063c675..fbb2e39 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -222,8 +222,9 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 	hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
 	delta = new_hw_ptr - hw_ptr_interrupt;
 	if (hw_ptr_interrupt >= runtime->boundary) {
-		hw_ptr_interrupt %= runtime->boundary;
-		if (!hw_base) /* hw_base was already lapped; recalc delta */
+		hw_ptr_interrupt -= runtime->boundary;
+		if (hw_base < runtime->boundary / 2)
+			/* hw_base was already lapped; recalc delta */
 			delta = new_hw_ptr - hw_ptr_interrupt;
 	}
 	if (delta < 0) {
@@ -241,7 +242,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 			delta = 0;
 		} else {
 			hw_base += runtime->buffer_size;
-			if (hw_base == runtime->boundary)
+			if (hw_base >= runtime->boundary)
 				hw_base = 0;
 			new_hw_ptr = hw_base + pos;
 		}
@@ -296,7 +297,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 			return 0;
 		}
 		hw_base += runtime->buffer_size;
-		if (hw_base == runtime->boundary)
+		if (hw_base >= runtime->boundary)
 			hw_base = 0;
 		new_hw_ptr = hw_base + pos;
 	}


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-10/kernel.spec,v
retrieving revision 1.1321
retrieving revision 1.1322
diff -u -r1.1321 -r1.1322
--- kernel.spec	13 Apr 2009 17:30:44 -0000	1.1321
+++ kernel.spec	13 Apr 2009 18:21:11 -0000	1.1322
@@ -629,7 +629,15 @@
 Patch580: linux-2.6-sparc-selinux-mprotect-checks.patch
 
 Patch600: linux-2.6-defaults-alsa-hda-beep-off.patch
-Patch602: alsa-rewrite-hw_ptr-updaters.patch
+Patch601: alsa-rewrite-hw_ptr-updaters.patch
+Patch602: alsa-pcm-always-reset-invalid-position.patch
+Patch603: alsa-pcm-fix-delta-calc-at-overlap.patch
+Patch604: alsa-pcm-safer-boundary-checks.patch
+Patch605: alsa-hda-dont-reset-BDL-unnecessarily.patch
+Patch606: alsa-dont-reset-stream-at-each-prepare-callb.patch
+Patch607: alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch
+Patch608: alsa-pcm-midlevel-add-more-strict-buffer-position.patch
+Patch609: alsa-hda_intel-prealloc-4mb-dmabuffer.patch
 
 Patch670: linux-2.6-ata-quirk.patch
 
@@ -1189,8 +1197,16 @@
 # fix cpqarray pci enable
 ApplyPatch linux-2.6-scsi-cpqarray-set-master.patch
 
-# ALSA
+# fix alsa for pulseaudio
 ApplyPatch alsa-rewrite-hw_ptr-updaters.patch
+ApplyPatch alsa-pcm-always-reset-invalid-position.patch
+ApplyPatch alsa-pcm-fix-delta-calc-at-overlap.patch
+ApplyPatch alsa-pcm-safer-boundary-checks.patch
+ApplyPatch alsa-hda-dont-reset-BDL-unnecessarily.patch
+ApplyPatch alsa-dont-reset-stream-at-each-prepare-callb.patch
+ApplyPatch alsa-hda_intel-fix-unexpected-ring-buffer-positio.patch
+ApplyPatch alsa-pcm-midlevel-add-more-strict-buffer-position.patch
+ApplyPatch alsa-hda_intel-prealloc-4mb-dmabuffer.patch
 
 # Networking
 
@@ -1847,6 +1863,9 @@
 %kernel_variant_files -k vmlinux %{with_kdump} kdump
 
 %changelog
+* Mon Apr 13 2009 Chuck Ebbert <cebbert at redhat.com> 2.6.29.1-21
+- Copy ALSA pulseaudio fixes from F-11.
+
 * Mon Apr 13 2009 John W. Linville <linville at redhat.com>  2.6.29.1-20
 - Remove iwl3945: rely on priv->lock to protect priv access
 




More information about the fedora-extras-commits mailing list