[alsa-devel] snd-hda-intel - wallclk patch
Takashi Iwai
tiwai at suse.de
Tue May 11 12:51:12 CEST 2010
At Tue, 11 May 2010 12:23:19 +0200 (CEST),
Jaroslav Kysela wrote:
>
> On Tue, 11 May 2010, Takashi Iwai wrote:
>
> > At Tue, 11 May 2010 11:07:05 +0200 (CEST),
> > Jaroslav Kysela wrote:
> >>
> >> On Tue, 11 May 2010, Takashi Iwai wrote:
> >>
> >>> At Tue, 11 May 2010 10:44:17 +0200 (CEST),
> >>> Jaroslav Kysela wrote:
> >>>>
> >>>> On Tue, 11 May 2010, Takashi Iwai wrote:
> >>>>
> >>>>> At Tue, 11 May 2010 10:28:50 +0200 (CEST),
> >>>>> Jaroslav Kysela wrote:
> >>>>>>
> >>>>>> On Mon, 10 May 2010, Jaroslav Kysela wrote:
> >>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>> I would like to ask HDA gurus to check this patch (I will include it
> >>>>>>> to my tree once acked). The patch uses WALLCLK from HDA chips (marked as
> >>>>>>> required in the HDA specification) to check for bogus - too early - interrups
> >>>>>>> which confuses the upper PCM layer (sound skipping issues).
> >>>>>>>
> >>>>>>> More details about patch testing on problematic hardware can be found
> >>>>>>> at:
> >>>>>>>
> >>>>>>> https://bugzilla.kernel.org/show_bug.cgi?id=15912
> >>>>>>
> >>>>>> No objections received, so I pushed this code to my master/devel branches.
> >>>>>
> >>>>> Heh, that was quick, I had no time to review :)
> >>>>>
> >>>>> The change looks good to me. Thanks for your fix (and rebasing).
> >>>>>
> >>>>> One thing is that you removed bdl_pos_adj=0 check. This was there
> >>>>> explicitly to avoid the delayed irq handling no matter whether the
> >>>>> value is correct or not. I guess it's safer to take it back, or
> >>>>> give any other way for user to avoid the delayed irq handling.
> >>>>
> >>>> I see. But I need the pos % period_bytes check too. What about this
> >>>> change?
> >>>
> >>> With bdl_pos_adj==0, it should return 1 (non-error), but otherwise
> >>> this should be OK, I guess.
> >>
> >> The problem with returning value 1 -> call snd_pcm_elapsed() - is that the
> >> upper layer will be most probably confused on broken hw. From logs in
> >> kernel bz#15912, the bad irq can be triggered at any time (I really don't
> >> know why INTSTS register is set).
> >>
> >> The first wallclk check uses to check for first 2/3 of period and the
> >> pos % period_bytes check checks for second half of period. Writing this, I
> >> think that the extra check can be added to the second condition to do
> >> position related check for first next period only:
> >
> > Isn't a similar check done in PCM core side?
> > Filtering or delaying ack is perhaps better done here, though...
>
> Unfortunately, the check in PCM core expects that at least 'period_time'
> is elapsed between two snd_pcm_elapsed() calls:
>
> if (in_interrupt) {
> /* we know that one period was processed */
> /* delta = "expected next hw_ptr" for in_interrupt != 0 */
> delta = runtime->hw_ptr_interrupt + runtime->period_size;
>
> In situation, when the driver calls the snd_pcm_elapsed() too early,
> the pointers will be updated wrongly (whole ring buffer size will be
> added to hw_ptr).
Yeah, that's bad.
> >> diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
> >> index 0a6c55b..d4d532a 100644
> >> --- a/sound/pci/hda/hda_intel.c
> >> +++ b/sound/pci/hda/hda_intel.c
> >> @@ -1890,9 +1890,8 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
> >> unsigned int pos;
> >> int stream;
> >>
> >> - wallclk = azx_readl(chip, WALLCLK);
> >> - if ((wallclk - azx_dev->start_wallclk) <
> >> - (azx_dev->period_wallclk * 2) / 3)
> >> + wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk;
> >> + if (wallclk < (azx_dev->period_wallclk * 2) / 3)
> >> return -1; /* bogus (too early) interrupt */
> >>
> >> stream = azx_dev->substream->stream;
> >> @@ -1910,9 +1909,12 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
> >>
> >> if (WARN_ONCE(!azx_dev->period_bytes,
> >> "hda-intel: zero azx_dev->period_bytes"))
> >> - return 0; /* this shouldn't happen! */
> >> - if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
> >> - return 0; /* NG - it's below the period boundary */
> >> + /* this shouldn't happen! */
> >> + return bdl_pos_adj[chip->dev_index] ? 0 : -1;
> >> + if (wallclk <= azx_dev->period_wallclk &&
> >> + pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
> >> + /* NG - it's below the first next period boundary */
> >> + return bdl_pos_adj[chip->dev_index] ? 0 : -1;
> >> azx_dev->start_wallclk = wallclk;
> >> return 1; /* OK, it's fine */
> >> }
> >>
> >> I don't see any reason to call snd_pcm_elapsed() in bad time. It's better
> >> to return -1 (ignore) and wait for next interrupt.
> >
> > Hm, judging from the current situation, a missing IRQ is harmless than
> > the wrong position ack, indeed.
> >
> > But delaying the period handling is a bit different from filtering
> > bogus IRQs. I'm not entirely sure which is the cause in the bug
> > above. If it's a bogus IRQ, could it be filtered out. If it's an IRQ
> > at wrong time (too early), the delayed ack is needed. If it's the
> > wrong position read, the delayed ack isn't needed but the position
> > correction is needed.
> >
> > So, I'm a bit afraid of adding too much checks that might give a
> > reaction based on wrong information. We'd need to take a detailed
> > look again at each cause...
>
> I'm also not so much happy to have this code in the driver, but it seems
> that HDA hardware does not respect the standard behaviour in some cases.
> Anyway, it's good to have the code robust.
>
> > BTW, now I looked back again, and think
> > WARN_ONCE(!azx_dev->period_bytes) should be also returning -1 for
> > normal cases, no? This is just a sanity check, and if this happens,
> > the chance that you get the right IRQ at the next moment isn't high,
> > since something got screwed up.
>
> I agree. I put all suggested changes to my tree into "[ALSA]
> snd-hda-intel: Improve azx_position_ok()" commit.
Thanks! I pulled now this, too.
Takashi
More information about the Alsa-devel
mailing list