public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
Subject: [PATCH 5.15 28/76] ALSA: usb-audio: Refcount multiple accesses on the single clock
Date: Wed, 13 Mar 2024 12:41:35 -0400	[thread overview]
Message-ID: <20240313164223.615640-29-sashal@kernel.org> (raw)
In-Reply-To: <20240313164223.615640-1-sashal@kernel.org>

From: Takashi Iwai <tiwai@suse.de>

[ Upstream commit c11117b634f4f832c4420d3cf41c44227f140ce1 ]

When a clock source is connected to multiple nodes / endpoints, the
current USB-audio driver tries to set up at each time one of them is
configured.  Although it reads the current rate and updates only if it
differs, some devices seem unhappy with this behavior and spew the
errors when reading/updating the rate unnecessarily.

This patch tries to reduce the redundant clock setup by introducing a
refcount for each clock source.  When the stream is actually running,
a clock rate is "locked", and it bypasses the clock and/or refuse to
change any longer.

BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=215934
Link: https://lore.kernel.org/r/20220516104807.16482-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Stable-dep-of: 7822baa844a8 ("ALSA: usb-audio: add quirk for RODE NT-USB+")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 sound/usb/card.c     |  1 +
 sound/usb/card.h     |  3 +-
 sound/usb/endpoint.c | 90 +++++++++++++++++++++++++++++++++++++++-----
 sound/usb/usbaudio.h |  1 +
 4 files changed, 85 insertions(+), 10 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 550c6a72fb5bc..bebd42413fadb 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -643,6 +643,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
 	INIT_LIST_HEAD(&chip->pcm_list);
 	INIT_LIST_HEAD(&chip->ep_list);
 	INIT_LIST_HEAD(&chip->iface_ref_list);
+	INIT_LIST_HEAD(&chip->clock_ref_list);
 	INIT_LIST_HEAD(&chip->midi_list);
 	INIT_LIST_HEAD(&chip->mixer_list);
 
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 87f042d06ce08..ca75f2206170f 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -44,6 +44,7 @@ struct audioformat {
 
 struct snd_usb_substream;
 struct snd_usb_iface_ref;
+struct snd_usb_clock_ref;
 struct snd_usb_endpoint;
 struct snd_usb_power_domain;
 
@@ -62,6 +63,7 @@ struct snd_urb_ctx {
 struct snd_usb_endpoint {
 	struct snd_usb_audio *chip;
 	struct snd_usb_iface_ref *iface_ref;
+	struct snd_usb_clock_ref *clock_ref;
 
 	int opened;		/* open refcount; protect with chip->mutex */
 	atomic_t running;	/* running status */
@@ -138,7 +140,6 @@ struct snd_usb_endpoint {
 	unsigned int cur_period_frames;
 	unsigned int cur_period_bytes;
 	unsigned int cur_buffer_periods;
-	unsigned char cur_clock;
 
 	spinlock_t lock;
 	struct list_head list;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 6c7d842d04965..803053d4c9dbc 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -35,6 +35,14 @@ struct snd_usb_iface_ref {
 	struct list_head list;
 };
 
+/* clock refcounting */
+struct snd_usb_clock_ref {
+	unsigned char clock;
+	atomic_t locked;
+	int rate;
+	struct list_head list;
+};
+
 /*
  * snd_usb_endpoint is a model that abstracts everything related to an
  * USB endpoint and its streaming.
@@ -598,6 +606,25 @@ iface_ref_find(struct snd_usb_audio *chip, int iface)
 	return ip;
 }
 
+/* Similarly, a refcount object for clock */
+static struct snd_usb_clock_ref *
+clock_ref_find(struct snd_usb_audio *chip, int clock)
+{
+	struct snd_usb_clock_ref *ref;
+
+	list_for_each_entry(ref, &chip->clock_ref_list, list)
+		if (ref->clock == clock)
+			return ref;
+
+	ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+	if (!ref)
+		return NULL;
+	ref->clock = clock;
+	atomic_set(&ref->locked, 0);
+	list_add_tail(&ref->list, &chip->clock_ref_list);
+	return ref;
+}
+
 /*
  * Get the existing endpoint object corresponding EP
  * Returns NULL if not present.
@@ -775,6 +802,14 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
 			goto unlock;
 		}
 
+		if (fp->protocol != UAC_VERSION_1) {
+			ep->clock_ref = clock_ref_find(chip, fp->clock);
+			if (!ep->clock_ref) {
+				ep = NULL;
+				goto unlock;
+			}
+		}
+
 		ep->cur_audiofmt = fp;
 		ep->cur_channels = fp->channels;
 		ep->cur_rate = params_rate(params);
@@ -784,7 +819,6 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
 		ep->cur_period_frames = params_period_size(params);
 		ep->cur_period_bytes = ep->cur_period_frames * ep->cur_frame_bytes;
 		ep->cur_buffer_periods = params_periods(params);
-		ep->cur_clock = fp->clock;
 
 		if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
 			endpoint_set_syncinterval(chip, ep);
@@ -902,8 +936,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
 		ep->altsetting = 0;
 		ep->cur_audiofmt = NULL;
 		ep->cur_rate = 0;
-		ep->cur_clock = 0;
 		ep->iface_ref = NULL;
+		ep->clock_ref = NULL;
 		usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num);
 	}
 	mutex_unlock(&chip->mutex);
@@ -915,6 +949,8 @@ void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
 	ep->need_setup = true;
 	if (ep->iface_ref)
 		ep->iface_ref->need_setup = true;
+	if (ep->clock_ref)
+		ep->clock_ref->rate = 0;
 }
 
 /*
@@ -1321,6 +1357,33 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
 	return 0;
 }
 
+static int init_sample_rate(struct snd_usb_audio *chip,
+			    struct snd_usb_endpoint *ep)
+{
+	struct snd_usb_clock_ref *clock = ep->clock_ref;
+	int err;
+
+	if (clock) {
+		if (atomic_read(&clock->locked))
+			return 0;
+		if (clock->rate == ep->cur_rate)
+			return 0;
+		if (clock->rate && clock->rate != ep->cur_rate) {
+			usb_audio_dbg(chip, "Mismatched sample rate %d vs %d for EP 0x%x\n",
+				      clock->rate, ep->cur_rate, ep->ep_num);
+			return -EINVAL;
+		}
+	}
+
+	err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, ep->cur_rate);
+	if (err < 0)
+		return err;
+
+	if (clock)
+		clock->rate = ep->cur_rate;
+	return 0;
+}
+
 /*
  * snd_usb_endpoint_configure: Configure the endpoint
  *
@@ -1350,8 +1413,7 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
 		 * to update at each EP configuration
 		 */
 		if (ep->cur_audiofmt->protocol == UAC_VERSION_1) {
-			err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt,
-						       ep->cur_rate);
+			err = init_sample_rate(chip, ep);
 			if (err < 0)
 				goto unlock;
 		}
@@ -1381,7 +1443,7 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
 	if (err < 0)
 		goto unlock;
 
-	err = snd_usb_init_sample_rate(chip, ep->cur_audiofmt, ep->cur_rate);
+	err = init_sample_rate(chip, ep);
 	if (err < 0)
 		goto unlock;
 
@@ -1414,15 +1476,15 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
 /* get the current rate set to the given clock by any endpoint */
 int snd_usb_endpoint_get_clock_rate(struct snd_usb_audio *chip, int clock)
 {
-	struct snd_usb_endpoint *ep;
+	struct snd_usb_clock_ref *ref;
 	int rate = 0;
 
 	if (!clock)
 		return 0;
 	mutex_lock(&chip->mutex);
-	list_for_each_entry(ep, &chip->ep_list, list) {
-		if (ep->cur_clock == clock && ep->cur_rate) {
-			rate = ep->cur_rate;
+	list_for_each_entry(ref, &chip->clock_ref_list, list) {
+		if (ref->clock == clock) {
+			rate = ref->rate;
 			break;
 		}
 	}
@@ -1463,6 +1525,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
 	if (atomic_inc_return(&ep->running) != 1)
 		return 0;
 
+	if (ep->clock_ref)
+		atomic_inc(&ep->clock_ref->locked);
+
 	ep->active_mask = 0;
 	ep->unlink_mask = 0;
 	ep->phase = 0;
@@ -1572,6 +1637,9 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, bool keep_pending)
 		if (ep->sync_source)
 			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;
 	}
 }
 
@@ -1598,12 +1666,16 @@ void snd_usb_endpoint_free_all(struct snd_usb_audio *chip)
 {
 	struct snd_usb_endpoint *ep, *en;
 	struct snd_usb_iface_ref *ip, *in;
+	struct snd_usb_clock_ref *cp, *cn;
 
 	list_for_each_entry_safe(ep, en, &chip->ep_list, list)
 		kfree(ep);
 
 	list_for_each_entry_safe(ip, in, &chip->iface_ref_list, list)
 		kfree(ip);
+
+	list_for_each_entry_safe(cp, cn, &chip->clock_ref_list, list)
+		kfree(ip);
 }
 
 /*
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index ec06f441e890f..e97141ef730ad 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -46,6 +46,7 @@ struct snd_usb_audio {
 	struct list_head pcm_list;	/* list of pcm streams */
 	struct list_head ep_list;	/* list of audio-related endpoints */
 	struct list_head iface_ref_list; /* list of interface refcounts */
+	struct list_head clock_ref_list; /* list of clock refcounts */
 	int pcm_devs;
 
 	struct list_head midi_list;	/* list of midi interfaces */
-- 
2.43.0


  parent reply	other threads:[~2024-03-13 16:42 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-13 16:41 [PATCH 5.15 00/76] 5.15.152-rc1 review Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 01/76] mmc: mmci: stm32: use a buffer for unaligned DMA requests Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 02/76] mmc: mmci: stm32: fix DMA API overlapping mappings warning Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 03/76] net: lan78xx: fix runtime PM count underflow on link stop Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 04/76] ixgbe: {dis, en}able irqs in ixgbe_txrx_ring_{dis, en}able Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 05/76] i40e: disable NAPI right after disabling irqs when handling xsk_pool Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 06/76] tracing/net_sched: Fix tracepoints that save qdisc_dev() as a string Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 07/76] geneve: make sure to pull inner header in geneve_rx() Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 08/76] net: sparx5: Fix use after free inside sparx5_del_mact_entry Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 09/76] net: ice: Fix potential NULL pointer dereference in ice_bridge_setlink() Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 10/76] net/ipv6: avoid possible UAF in ip6_route_mpath_notify() Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 11/76] cpumap: Zero-initialise xdp_rxq_info struct before running XDP program Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 12/76] net/rds: fix WARNING in rds_conn_connect_if_down Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 13/76] netfilter: nft_ct: fix l3num expectations with inet pseudo family Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 14/76] netfilter: nf_conntrack_h323: Add protection for bmp length out of range Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 15/76] erofs: apply proper VMA alignment for memory mapped files on THP Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 16/76] netrom: Fix a data-race around sysctl_netrom_default_path_quality Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 17/76] netrom: Fix a data-race around sysctl_netrom_obsolescence_count_initialiser Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 18/76] netrom: Fix data-races around sysctl_netrom_network_ttl_initialiser Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 19/76] netrom: Fix a data-race around sysctl_netrom_transport_timeout Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 20/76] netrom: Fix a data-race around sysctl_netrom_transport_maximum_tries Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 21/76] netrom: Fix a data-race around sysctl_netrom_transport_acknowledge_delay Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 22/76] netrom: Fix a data-race around sysctl_netrom_transport_busy_delay Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 23/76] netrom: Fix a data-race around sysctl_netrom_transport_requested_window_size Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 24/76] netrom: Fix a data-race around sysctl_netrom_transport_no_activity_timeout Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 25/76] netrom: Fix a data-race around sysctl_netrom_routing_control Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 26/76] netrom: Fix a data-race around sysctl_netrom_link_fails_count Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 27/76] netrom: Fix data-races around sysctl_net_busy_read Sasha Levin
2024-03-13 16:41 ` Sasha Levin [this message]
2024-03-13 16:41 ` [PATCH 5.15 29/76] ALSA: usb-audio: Clear fixed clock rate at closing EP Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 30/76] ALSA: usb-audio: Split endpoint setups for hw_params and prepare (take#2) Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 31/76] ALSA: usb-audio: Properly refcounting clock rate Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 32/76] ALSA: usb-audio: Apply mutex around snd_usb_endpoint_set_params() Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 33/76] ALSA: usb-audio: Correct the return code from snd_usb_endpoint_set_params() Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 34/76] ALSA: usb-audio: Avoid superfluous endpoint setup Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 35/76] ALSA: usb-audio: Add quirk for Tascam Model 12 Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 36/76] ALSA: usb-audio: Add new quirk FIXED_RATE for JBL Quantum810 Wireless Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 37/76] ALSA: usb-audio: Fix microphone sound on Nexigo webcam Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 38/76] ALSA: usb-audio: add quirk for RODE NT-USB+ Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 39/76] drm/amd/display: Fix uninitialized variable usage in core_link_ 'read_dpcd() & write_dpcd()' functions Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 40/76] nfp: flower: add goto_chain_index for ct entry Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 41/76] nfp: flower: add hardware offload check for post " Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 42/76] selftests/mm: switch to bash from sh Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 43/76] selftests: mm: fix map_hugetlb failure on 64K page size systems Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 44/76] modpost: Include '.text.*' in TEXT_SECTIONS Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 45/76] modpost: Add '.ltext' and '.ltext.*' to TEXT_SECTIONS Sasha Levin
2024-03-13 17:12   ` Nathan Chancellor
2024-03-13 20:13     ` Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 46/76] xhci: process isoc TD properly when there was a transaction error mid TD Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 47/76] xhci: handle isoc Babble and Buffer Overrun events properly Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 48/76] serial: max310x: use regmap methods for SPI batch operations Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 49/76] serial: max310x: use a separate regmap for each port Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 50/76] serial: max310x: prevent infinite while() loop in port startup Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 51/76] drm/amd/pm: do not expose the API used internally only in kv_dpm.c Sasha Levin
2024-03-13 16:41 ` [PATCH 5.15 52/76] drm/amdgpu: Reset IH OVERFLOW_CLEAR bit Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 53/76] selftests: mptcp: decrease BW in simult flows Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 54/76] hv_netvsc: use netif_is_bond_master() instead of open code Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 55/76] hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 56/76] drm/amd/display: Re-arrange FPU code structure for dcn2x Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 57/76] drm/amd/display: move calcs folder into DML Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 58/76] drm/amd/display: remove DML Makefile duplicate lines Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 59/76] drm/amd/display: Increase frame-larger-than for all display_mode_vba files Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 60/76] getrusage: add the "signal_struct *sig" local variable Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 61/76] getrusage: move thread_group_cputime_adjusted() outside of lock_task_sighand() Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 62/76] getrusage: use __for_each_thread() Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 63/76] getrusage: use sig->stats_lock rather than lock_task_sighand() Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 64/76] proc: Use task_is_running() for wchan in /proc/$pid/stat Sasha Levin
2024-03-14  3:04   ` Kees Cook
2024-03-15 18:31     ` Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 65/76] fs/proc: do_task_stat: move thread_group_cputime_adjusted() outside of lock_task_sighand() Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 66/76] exit: Fix typo in comment: s/sub-theads/sub-threads Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 67/76] exit: wait_task_zombie: kill the no longer necessary spin_lock_irq(siglock) Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 68/76] ALSA: usb-audio: Fix wrong kfree issue in snd_usb_endpoint_free_all Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 69/76] ALSA: usb-audio: Always initialize fixed_rate in snd_usb_find_implicit_fb_sync_format() Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 70/76] ALSA: usb-audio: Add FIXED_RATE quirk for JBL Quantum610 Wireless Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 71/76] ALSA: usb-audio: Sort quirk table entries Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 72/76] regmap: allow to define reg_update_bits for no bus configuration Sasha Levin
2024-03-13 16:46   ` Mark Brown
2024-03-13 17:16     ` Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 73/76] regmap: Add bulk read/write callbacks into regmap_config Sasha Levin
2024-03-13 16:46   ` Mark Brown
2024-03-13 17:14     ` Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 74/76] serial: max310x: make accessing revision id interface-agnostic Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 75/76] serial: max310x: fix IO data corruption in batched operations Sasha Levin
2024-03-13 16:42 ` [PATCH 5.15 76/76] Linux 5.15.152-rc1 Sasha Levin
2024-03-13 19:21 ` [PATCH 5.15 00/76] 5.15.152-rc1 review Daniel Díaz
2024-03-13 20:21   ` Sasha Levin
2024-03-14 15:02 ` Harshit Mogalapalli
2024-03-14 20:14 ` Florian Fainelli
2024-03-14 23:08 ` SeongJae Park
2024-03-15 10:43 ` Shreeya Patel

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=20240313164223.615640-29-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --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