[alsa-devel] [RFC PATCH] ALSA: hda - hdmi begin to support dynamic PCM assignment
Yang, Libin
libin.yang at intel.com
Sat Nov 14 01:18:59 CET 2015
> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai at suse.de]
> Sent: Friday, November 13, 2015 11:56 PM
> To: Yang, Libin
> Cc: libin.yang at linux.intel.com; alsa-devel at alsa-project.org;
> mengdong.lin at linux.intel.com
> Subject: Re: [alsa-devel] [RFC PATCH] ALSA: hda - hdmi begin to support
> dynamic PCM assignment
>
> On Fri, 13 Nov 2015 16:33:22 +0100,
> Yang, Libin wrote:
> >
> >
> > > -----Original Message-----
> > > From: Takashi Iwai [mailto:tiwai at suse.de]
> > > Sent: Friday, November 13, 2015 5:21 PM
> > > To: libin.yang at linux.intel.com
> > > Cc: alsa-devel at alsa-project.org; mengdong.lin at linux.intel.com; Yang,
> > > Libin
> > > Subject: Re: [alsa-devel] [RFC PATCH] ALSA: hda - hdmi begin to
> support
> > > dynamic PCM assignment
> > >
> > > On Fri, 13 Nov 2015 09:56:30 +0100,
> > > libin.yang at linux.intel.com wrote:
> > > >
> > > > From: Libin Yang <libin.yang at linux.intel.com>
> > > >
> > > > Begin to support dynamic PCM assignment to pin in
> > > > hdmi audio driver.
> > > >
> > > > This means PCM will not be statically bound with pin.
> > > > When there is a monitor connected, the corresponding pin
> > > > will try to find a proper PCM to bind. When the monitor
> > > > is disconnected, the corresponding pin will unbind
> > > > the PCM. This helps to reduce the PCM number when there
> > > > are many pins (device entries in DP MST mode) and only
> > > > a few of them work at the same time.
> > > >
> > > > This patch adds the pcm member in struct hdmi_spec_per_pin.
> > > > When PCM is dynamically bound to the pin, the member pcm
> > > > will pointer to the corresponding pcm_rec[] in hdmi_spec,
> > > > which means the hda_pcm is bound to the pin.
> > > >
> > > > Signed-off-by: Libin Yang <libin.yang at linux.intel.com>
> > > > ---
> > > > sound/pci/hda/patch_hdmi.c | 26 +++++++++++++++++++++-----
> > > > 1 file changed, 21 insertions(+), 5 deletions(-)
> > > >
> > > > diff --git a/sound/pci/hda/patch_hdmi.c
> > > b/sound/pci/hda/patch_hdmi.c
> > > > index f503a88..f3363b8 100644
> > > > --- a/sound/pci/hda/patch_hdmi.c
> > > > +++ b/sound/pci/hda/patch_hdmi.c
> > > > @@ -82,6 +82,7 @@ struct hdmi_spec_per_pin {
> > > > struct mutex lock;
> > > > struct delayed_work work;
> > > > struct snd_kcontrol *eld_ctl;
> > > > + struct hda_pcm *pcm; /* pointer to spec->pcm_rec[n]
> > > dynamically*/
> > > > int repoll_count;
> > > > bool setup; /* the stream has been set up by prepare callback */
> > > > int channels; /* current number of channels */
> > > > @@ -140,7 +141,8 @@ struct hdmi_spec {
> > > > struct hdmi_ops ops;
> > > >
> > > > bool dyn_pin_out;
> > > > -
> > > > + bool dyn_pcm_assign;
> > > > + struct mutex pcm_lock;
> > > > /*
> > > > * Non-generic VIA/NVIDIA specific
> > > > */
> > > > @@ -378,13 +380,26 @@ static int hinfo_to_pin_index(struct
> > > hda_codec *codec,
> > > > struct hda_pcm_stream *hinfo)
> > > > {
> > > > struct hdmi_spec *spec = codec->spec;
> > > > + struct hdmi_spec_per_pin *per_pin;
> > > > int pin_idx;
> > > >
> > > > - for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
> > > > - if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
> > > > - return pin_idx;
> > > > + if (!spec->dyn_pcm_assign) {
> > > > + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
> > > > + if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
> > > > + return pin_idx;
> > > > + } else {
> > > > + mutex_lock(&spec->pcm_lock);
> > > > + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
> > > > + per_pin = get_pin(spec, pin_idx);
> > > > + if (per_pin->pcm && per_pin->pcm->stream ==
> > > hinfo) {
> > > > + mutex_unlock(&spec->pcm_lock);
> > > > + return pin_idx;
> > > > + }
> > > > + }
> > > > + mutex_unlock(&spec->pcm_lock);
> > >
> > > You can assign per_pin->pcm statically at init time when
> > > dyn_pcm_assign=false. Then the same code is used in the above.
> >
> > Yes, I will change it.
> >
> > >
> > > The need of spec->pcm_lock isn't clear at this moment. I guess you're
> > > trying to avoid the race of dynamic pin assignment and release. But
> > > then the code above doesn't protect anything because you return the
> > > pin_idx as an available value after the unlock. Then the pin release
> > > can happen after this point while you're accessing with the pin_idx.
> > >
> > > So, better to consider the implementation of lock or other mechanism
> > > once when the whole picture is ready.
> >
> > I add the lock to avoid:
> > if (per_pin->pcm && per_pin->pcm->stream == hinfo)
> > per_pin->pcm is not null at first and when judge
> > "per_pin->pcm->stream == hinfo" per_pin->pcm has been null.
> >
> > I found it's very hard to protect the pin_idx in the whole process.
> > For example, pin is connected when open, but disconnected when
> > prepare or close, or vise verse. Or open is called twice at the same
> > time, but pin is assigned to 2 different PCMs (hotplug happens).
>
> I think it's feasible. We need to protect it only in each PCM
> operation, not through the whole PCM open time, i.e. only in each
> prepare(), cleanup() or whatever call. For example, make a rw
> semaphore and do read lock in each operation. When the PCM assign or
> release happens, it takes write lock. So it waits until the PCM
> operation finishes and blocks it while switching.
Get it. Thanks.
>
> > Maybe we can keep the lock now, and will refine it later? This lock
> > can make sure when per_pin->pcm->stream == hinfo, it will never
> > access invalid memory.
>
> As I wrote, there is no reason to introduce the lock in *this* patch,
> as there is no race at all here. There will be a race in future, but
> then let's think the best way at that point.
Get it. I will remove the lock.
Regards,
Libin
>
> Also, the mapping between hinfo and per_pin can be done in a different
> way instead of loop search. We may still need some lock, but then the
> required lock would be different, too.
>
>
> Takashi
More information about the Alsa-devel
mailing list