From: "Amadeusz Sławiński" <amadeuszx.slawinski@linux.intel.com>
To: Takashi Iwai <tiwai@suse.de>
Cc: Cezary Rojewski <cezary.rojewski@intel.com>,
"alsa-devel@alsa-project.org" <alsa-devel@alsa-project.org>
Subject: Re: HDA, power saving and recording
Date: Thu, 11 May 2023 19:20:17 +0200 [thread overview]
Message-ID: <41417b90-1881-0cbb-52e1-d63923dd8cd6@linux.intel.com> (raw)
In-Reply-To: <87jzxe5084.wl-tiwai@suse.de>
On 5/11/2023 5:58 PM, Takashi Iwai wrote:
> On Thu, 11 May 2023 17:31:37 +0200,
> Amadeusz Sławiński wrote:
>>
>> On 5/10/2023 2:21 PM, Takashi Iwai wrote:
>>> On Tue, 09 May 2023 12:10:06 +0200,
>>> Amadeusz Sławiński wrote:
>>>>
>>>> Hi Takashi,
>>>>
>>>> I have a question related to HDA codecs, power saving and sending verb
>>>> configuration. In our tests we test avs driver with HDA codec
>>>> configuration and we see problem when arecord is started before codec
>>>> goes to first sleep.
>>>>
>>>> In ASoC code we set power save timeout to 2 seconds [1], if we start
>>>> recording before codec goes to sleep, we record only silence.
>>>>
>>>> Now I've spend some time investigating the issue and as far as I can
>>>> tell, when codec is being initialized channels are being set to mute
>>>> and when one starts stream before first "sleep" it never sends proper
>>>> configuration to codec.
>>>
>>> Who does set channels to mute? Or do you mean that the hardware
>>> initial value set on the codec is muted? If yes, anyone should have
>>> unmuted. Was it tracked?
>>>
>>
>> It is done on probe, first two backtraces in my dmesg show it (one for
>> left and other for right channel). It is something along the lines of:
>> hda_codec_driver_probe -> snd_hda_codec_build_controls -> alc_init ->
>> snd_hda_codec_amp_init_stereo and then it writes mute verbs
>> (0x00935080 and 0x00936080)
>
> Sofar, that's the expected behavior. The driver initially mutes the
> mixers explicitly. But, something else must unmute the mixer
> afterwards for allowing recording.
>
>>>> However if one allows codec to go to sleep
>>>> proper configuration is being send on resume.
>>>
>>> We need to track down in which level the inconsistency happens.
>>> First of all, we need to check whether the HD-audio regmap holds the
>>> right value (unmuted) at the time of the first arecord, as well as the
>>> actual (raw) value from the codec.
>>>
>>>
>>
>> Well, my first idea was that some interaction between power management
>> and regmap goes awry somehow.
>>
>>>> I've also managed to reproduce it with non DSP configuration (using
>>>> snd_hda_intel driver). One needs to set power_save to non zero value
>>>> and start recording, before it first goes into first sleep.
>>>>
>>>> Here are the steps:
>>>> 1. Add following to /etc/modprobe.d/test.conf
>>>> options snd_intel_dspcfg dsp_driver=1
>>>> options snd_hda_intel power_save=5
>>>> blacklist snd_hda_intel
>>>> 2. Reboot the machine
>>>> 3. Run something like (it is time sensitive, so I just run it all in
>>>> one line):
>>>> echo "PRE MODPROBE" > /dev/kmsg; modprobe snd_hda_intel; echo "POST
>>>> MODPROBE" > /dev/kmsg; sleep 1; echo "PRE ARECORD" > /dev/kmsg;
>>>> arecord -Dhw:PCH,0 -r48 -c2 -fS16_LE -d 20 -vvv /tmp/cap.wav; echo
>>>> "POST ARECORD" > /dev/kmsg;
>>>> 4. Observe silence in above file
>>>> 5. Run after waiting more than 5 seconds:
>>>> echo "PRE SECOND ARECORD" > /dev/kmsg; arecord -Dhw:PCH,0 -r48 -c2
>>>> -fS16_LE -d 20 -vvv /tmp/cap.wav; echo "POST SECOND ARECORD" >
>>>> /dev/kmsg;
>>>>
>>>> I'm also attaching logs from my reproduction with debug.diff (also
>>>> attached) applied. Main purpose of debug.diff is to log when
>>>> snd_hdac_exec_verb() is called and to log backtraces for when record
>>>> input is muted on load and set on startup.
>>>>
>>>> When looking at attached dmesg, it is easy to see that when first
>>>> arecord is being run almost no configuration happens.
>>>
>>> The driver itself doesn't unmute. It should be alsactl or PA/PW that
>>> unmutes. At the initialization, HDA codec driver calls
>>> snd_hda_codec_amp_init() for each codec amp, and this reads the
>>> current value from the chip and updates *only* the regmap cache.
>>> When a program like alsactl/PA/PW updates the mute/volume, it's
>>> checked with the regmap cache and updated only if the value differs.
>>>
>>> So, the inconsistency may happen at this level, too. By some reason,
>>> it might believe the values unchanged, hence the registers might be
>>> left untouched.
>>>
>>> This needs further checks, obviously...
>>>
>>
>> And playing with controls is good suggestion, it made it a bit easier
>> to debug. Seems like hda_reg_write() exits early here:
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/hda/hdac_regmap.c#n297
>> this happens because codec_pm_lock returns -1. While in working case
>> it goes through whole hda_reg_write() function.
>>
>> So codec_pm_lock() calls snd_hdac_keep_power_up(), according to
>> comment snd_hdac_keep_power_up() returns -1 when codec is not powered
>> up.
>>
>> With additional logs I see that when snd_hdac_keep_power_up() is
>> called codec->dev->power.usage_count indeed is 0.
>>
>>
>> The call to snd_hda_power_down() which seems to set power to off,
>> seems to be in:
>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/pci/hda/hda_codec.c#n833
>>
>>
>> So broken order of operations seems to be:
>> snd_hda_intel driver gets loaded, it initializes codec. While it
>> initializes it sets amplifier to mute. It finishes initialization and
>> powers off. Then control gets set from alsactl, but as power is off it
>> gets cached.
>
> So far, so good. The mixer amp update during the codec power down
> changes only the cache. And, this modified cached value must be
> written to the hardware at the codec power up. But...
>
>> Then capture stream starts and seems to assume that
>> registers were already set, so it doesn't write them to hw.
>
> ... it seems this didn't happen, and that's the inconsistency.
>
> So the further question is:
> At the point just before you start recording, is the codec in runtime
> suspended? Or it's running?
>
> If it's runtime-suspended, snd_hda_regmap_sync() must be called from
> alc269_resume() via runtime-resume, and this must write out the
> cached values. Then the bug can be along with that line.
>
> Or if it's running, it means that the previous check of
> snd_hdac_keep_power_up() was bogus (or racy).
>
Well, it is in... let's call it semi powered state. When snd_hda_intel
driver is loaded with power_save=X option it sets timeout to X seconds
and problem only happens when I start the stream before those X seconds
pass and it runs first runtime suspend. After it suspends it then uses
standard pm_runtime_resume and works correctly. That's why the
pm_runtime_force_suspend(&codec->core.dev); mentioned in first email in
thread "fixes" the problem, as it forces it to be instantly suspended
instead of waiting for timeout and then later normal
resume-play/record-suspend flow can be followed.
>
> Takashi
>
>> Also using
>> alsamixer while "broken" stream is running doesn't result in any
>> writes being done.
>>
>> Contrasted with working case:
>> Codec is being brought up from sleep, registers get set to proper
>> value via call to snd_hda_regmap_sync(). Capture stream gets started
>> (and assumes that registers were set, and they were this time, as
>> runtime resume sets them) and continues with working volume set.
>>
>>
>> However when I tried to put snd_hda_regmap_sync() in few places while
>> stream is started it doesn't seem to help :/ I will continue looking
>> tomorrow, but any suggestions are still welcome.
>>
next prev parent reply other threads:[~2023-05-11 17:21 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-09 10:10 HDA, power saving and recording Amadeusz Sławiński
2023-05-10 12:21 ` Takashi Iwai
2023-05-11 15:31 ` Amadeusz Sławiński
2023-05-11 15:58 ` Takashi Iwai
2023-05-11 17:20 ` Amadeusz Sławiński [this message]
2023-05-12 11:23 ` Takashi Iwai
2023-05-12 11:33 ` Takashi Iwai
2023-05-12 12:00 ` Amadeusz Sławiński
2023-05-12 12:24 ` Takashi Iwai
2023-05-15 11:19 ` Amadeusz Sławiński
2023-05-15 13:02 ` Takashi Iwai
2023-05-15 14:49 ` Amadeusz Sławiński
2023-05-15 15:33 ` Takashi Iwai
2023-05-17 13:15 ` Cezary Rojewski
2023-05-17 14:52 ` Takashi Iwai
2023-05-18 9:00 ` Cezary Rojewski
2023-05-18 11:02 ` Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=41417b90-1881-0cbb-52e1-d63923dd8cd6@linux.intel.com \
--to=amadeuszx.slawinski@linux.intel.com \
--cc=alsa-devel@alsa-project.org \
--cc=cezary.rojewski@intel.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox