[alsa-devel] [PATCH v2] ALSA: hda - suspend codecs in parallel
Lin, Mengdong
mengdong.lin at intel.com
Wed Nov 27 05:14:58 CET 2013
> -----Original Message-----
> From: Takashi Iwai [mailto:tiwai at suse.de]
> Sent: Tuesday, November 26, 2013 10:05 PM
> > +#ifdef CONFIG_PM
> > + bus->pm_wq = create_workqueue("hda-pm-workq");
>
> Better to use a unique name, e.g. with a card number suffix.
Ok.
> > + if (!bus->pm_wq) {
> > + snd_printk(KERN_ERR "cannot create PM workqueue\n");
> > + snd_hda_bus_free(bus);
> > + return -ENOMEM;
> > + }
> > + workqueue_set_max_active(bus->pm_wq, HDA_MAX_NUM_CODECS);
>
> As mentioned in another post, this can be set dynamically, e.g. at
> snd_hda_suspend() with bus->num_codecs.
Can I move this to snd_hda_codec_new() like this?
list_add_tail(&codec->list, &bus->codec_list);
+bus->num_codecs++;
+workqueue_set_max_active(bus->pm_wq, bus->num_codecs);
The codec number does not change after initialization, and usually 1 or 2 codecs are connected to the bus.
> > err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
> > if (err < 0) {
> > snd_hda_bus_free(bus);
> > @@ -1434,6 +1451,8 @@ int snd_hda_codec_new(struct hda_bus *bus,
> > */
> > hda_keep_power_on(codec);
> > hda_call_pm_notify(bus, true);
> > +
> > + INIT_WORK(&codec->pm_work, hda_pm_work);
>
> Better to put this before hda_keep_power_on() call.
Ok.
> > if (codec->bus->modelname) {
> > @@ -1445,6 +1464,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
> > }
> >
> > list_add_tail(&codec->list, &bus->codec_list);
> > + bus->num_codecs++;
> > bus->caddr_tbl[codec_addr] = codec;
> >
> > codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
>
> Also decrease bus->num_codecs in snd_hda_codec_free(), just to be sure.
Can I decrease bus->num_codecs in snd_hda_bus_free(), after the codec is freed?
list_for_each_entry_safe(codec, n, &bus->codec_list, list) {
snd_hda_codec_free(codec);
+ bus->num_codecs--;
}
>
> > @@ -5032,6 +5052,14 @@ int snd_hda_check_amp_list_power(struct
> hda_codec *codec,
> > return 0;
> > }
> > EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power);
> > +
> > +static void hda_pm_work(struct work_struct *work) {
> > + struct hda_codec *codec =
> > + container_of(work, struct hda_codec, pm_work);
> > +
> > + hda_call_codec_suspend(codec, false); }
> > #endif
> >
> > /*
> > @@ -5595,11 +5623,27 @@
> EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
> > int snd_hda_suspend(struct hda_bus *bus) {
> > struct hda_codec *codec;
> > + unsigned int mask = 0;
> >
> > list_for_each_entry(codec, &bus->codec_list, list) {
> > cancel_delayed_work_sync(&codec->jackpoll_work);
> > - if (hda_codec_is_power_on(codec))
> > - hda_call_codec_suspend(codec, false);
> > + if (hda_codec_is_power_on(codec)) {
> > + if (bus->num_codecs == 1)
> > + hda_call_codec_suspend(codec, false);
> > + else {
> > + mask |= 1 << codec->addr;
> > + queue_work(bus->pm_wq, &codec->pm_work);
> > + }
> > + }
> > + }
> > +
> > + if (!mask)
> > + return 0;
> > +
> > + list_for_each_entry(codec, &bus->codec_list, list) {
> > + if (mask & (1 << codec->addr))
> > + flush_work(&codec->pm_work);
> > +
> > }
>
> You can drop the mask bit things, and here can be replaced with just a
> single call like:
> if (bus->num_codecs > 1)
> flush_workqueue(bus->pm_wq);
Ok. This is much better.
Thanks again!
Mengdong
More information about the Alsa-devel
mailing list