Subject: kern/26457: ac97 is not ready after suspend/resume (fix included, should be considered for 2.0)
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <Joachim.Thiemann@Mail.McGill.CA>
List: netbsd-bugs
Date: 07/28/2004 01:49:00
>Number:         26457
>Category:       kern
>Synopsis:       ac97 is not ready after suspend/resume (fix included, should be considered for 2.0)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 28 04:14:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Joachim Thiemann
>Release:        2.0_BETA
>Organization:
>Environment:
NetBSD codaget3002 2.0_BETA NetBSD 2.0_BETA (IBMT30) #28: Thu Jul 15 21:57:25 EDT 2004  thiemann@codaget3002:/home/thiemann/NetBSD/sys/arch/i386/compile/IBMT30 i386

from dmesg:
auich0 at pci0 dev 31 function 5: i82801CA (ICH3) AC-97 Audio
auich0: interrupting at irq 5
auich0: ac97: Analog Devices AD1881A codec; headphone, Analog Devices Phat Stereo
auich0: ac97: ext id 1<VRA>
auich0: measured ac97 link rate at 47277 Hz, will use 48000 Hz

>Description:
After a suspend/resume cycle of a laptop, the ac97 takes some time
to power up fully.  If registers are modified before that, it
the changes are ignored.  In particular, the ac97_restore_shadow
function is ignored, and the pre-suspend mixer values are lost.
Also, the chip may get stuck in the 48000 sample rate.
>How-To-Repeat:
Have a sound file sampled at low rate (eg. 8000 or 16000 Hz)
       
audioplay soundfile.wav
(suspend)
(resume)
audioplay soundfile.wav
mixerctl -w outputs.master.mute=off
mixerctl -w inputs.dac.mute=off
audioplay soundfile.wav
>Fix:
I have patched ac97.c to 1) wait until the power register claims that all subsystems are powered up, and 2) try modifying the master volume, until the write actually suceeds.

RCS file: /cvsroot/src/sys/dev/ic/ac97.c,v
retrieving revision 1.52
diff -c -r1.52 ac97.c
*** ac97.c      24 Nov 2003 16:05:10 -0000      1.52
--- ac97.c      28 Jul 2004 04:00:46 -0000
***************
*** 702,712 ****
        struct ac97_softc *as;
        const struct ac97_source_info *si;
        int idx;

        as = (struct ac97_softc *) self;
        for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
                si = &source_info[idx];
!               ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
        }

        if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
--- 702,740 ----
        struct ac97_softc *as;
        const struct ac97_source_info *si;
        int idx;
+       u_int16_t val;

        as = (struct ac97_softc *) self;
+
+       /* make sure chip is fully operational */
+       for (idx = 500000; idx >= 0; idx--) {
+               ac97_read(as, AC97_REG_POWER, &val);
+               if ((val & AC97_POWER_REF) &&
+                   (val & AC97_POWER_ANL) &&
+                   (val & AC97_POWER_DAC) &&
+                   (val & AC97_POWER_ADC)) break;
+               DELAY(1);
+       }
+
+       if (idx <= 0)
+               printf( "ac97 timeout on restore\n" );
+
+       /* actually try changing a value! */
+       for (idx = 500000; idx >= 0; idx--) {
+               as->host_if->write(as->host_if->arg, AC97_REG_MASTER_VOLUME, 0x1010);
+               ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
+               if (val == 0x1010) break;
+               DELAY(1);
+       }
+
+       if (idx <= 0)
+               printf( "ac97 timeout on ch reg\n" );
+
        for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
                si = &source_info[idx];
!               /* don't "restore" to the reset reg! */
!               if (si->reg)
!                       ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
        }

        if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA

>Release-Note:
>Audit-Trail:
>Unformatted: