ALSA: usb-audio: Properly refcounting clock rate
authorTakashi Iwai <tiwai@suse.de>
Tue, 20 Sep 2022 18:11:26 +0000 (20:11 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 20 Sep 2022 18:12:50 +0000 (20:12 +0200)
We fixed the bug introduced by the patch for managing the shared
clocks at the commit 809f44a0cc5a ("ALSA: usb-audio: Clear fixed clock
rate at closing EP"), but it was merely a workaround.  By this change,
the clock reference rate is cleared at each EP close, hence the still
remaining EP may need a re-setup of rate unnecessarily.

This patch introduces the proper refcounting for the clock reference
object so that the clock setup is done only when needed.

Fixes: 809f44a0cc5a ("ALSA: usb-audio: Clear fixed clock rate at closing EP")
Fixes: c11117b634f4 ("ALSA: usb-audio: Refcount multiple accesses on the single clock")
Link: https://lore.kernel.org/r/20220920181126.4912-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/endpoint.c

index 0c94ebc98e90da137bf86023680ad221f452559f..b2d0b42b581f7199d4181f7fd587edcfac3d522b 100644 (file)
@@ -39,6 +39,7 @@ struct snd_usb_iface_ref {
 struct snd_usb_clock_ref {
        unsigned char clock;
        atomic_t locked;
+       int opened;
        int rate;
        bool need_setup;
        struct list_head list;
@@ -803,6 +804,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
                                ep = NULL;
                                goto unlock;
                        }
+                       ep->clock_ref->opened++;
                }
 
                ep->cur_audiofmt = fp;
@@ -926,8 +928,10 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
                endpoint_set_interface(chip, ep, false);
 
        if (!--ep->opened) {
-               if (ep->clock_ref && !atomic_read(&ep->clock_ref->locked))
-                       ep->clock_ref->rate = 0;
+               if (ep->clock_ref) {
+                       if (!--ep->clock_ref->opened)
+                               ep->clock_ref->rate = 0;
+               }
                ep->iface = 0;
                ep->altsetting = 0;
                ep->cur_audiofmt = NULL;
@@ -1649,8 +1653,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending)
                        WRITE_ONCE(ep->sync_source->sync_sink, NULL);
                stop_urbs(ep, false, keep_pending);
                if (ep->clock_ref)
-                       if (!atomic_dec_return(&ep->clock_ref->locked))
-                               ep->clock_ref->rate = 0;
+                       atomic_dec(&ep->clock_ref->locked);
        }
 }