Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
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 17:31:37 +0200	[thread overview]
Message-ID: <cceaeb53-06df-ced0-1f54-f5c0eb65f824@linux.intel.com> (raw)
In-Reply-To: <878rdwjs1s.wl-tiwai@suse.de>

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)

>> 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. Then capture stream starts and seems to assume that 
registers were already set, so it doesn't write them to hw. 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.


  reply	other threads:[~2023-05-11 15:33 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 [this message]
2023-05-11 15:58     ` Takashi Iwai
2023-05-11 17:20       ` Amadeusz Sławiński
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=cceaeb53-06df-ced0-1f54-f5c0eb65f824@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