This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167b. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This reverts commit 9ce650a75a.
This commit causes watchdog lockups on my machine, and while I have no
idea what the cause is, it bisected right to this commit, and reverting
the change promptly fixes it.
At least occasionally one of the watchdog call traces was
Call Trace:
_raw_spin_lock_irqsave+0x35/0x40
snd_pcm_period_elapsed+0x1b/0xa0 [snd_pcm]
snd_usb_endpoint_start+0x1a0/0x3c0 [snd_usb_audio]
start_endpoints+0x23/0x90 [snd_usb_audio]
snd_usb_substream_playback_trigger+0x7b/0x1a0 [snd_usb_audio]
snd_pcm_common_ioctl+0x1c44/0x2360 [snd_pcm]
snd_pcm_ioctl+0x2e/0x40 [snd_pcm]
__se_sys_ioctl+0x72/0xc0
do_syscall_64+0x4c/0xa0
entry_SYSCALL_64_after_hwframe+0x44/0xae
so presumably it's a locking error on that substream spinlock that
snd_pcm_period_elapsed() takes. But at this point I just want to have a
working system so that I can continue the merge window work tomorrow.
Cc: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Clang warns:
sound/usb/mixer_scarlett_gen2.c:1189:32: warning: expression result
unused [-Wunused-value]
for (i = 0; i < count; i++, (u16 *)buf++)
^ ~~~~~
1 warning generated.
It appears the intention was to cast the void pointer to a u16 pointer
so that the data could be iterated through like an array of u16 values.
However, the cast happens after the increment because a cast is an
rvalue, whereas the post-increment operator only works on lvalues, so
the loop does not iterate as expected. This is not a bug in practice
because count is not greater than one at the moment but this could
change in the future so this should be fixed.
Replace the cast with a temporary variable of the proper type, which is
less error prone and fixes the iteration. Do the same thing for the
'u8 *' below this if block.
Fixes: ac34df733d ("ALSA: usb-audio: scarlett2: Update get_config to do endian conversion")
Link: https://github.com/ClangBuiltLinux/linux/issues/1408
Acked-by: Geoffrey D. Bennett <g@b4.vu>
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Link: https://lore.kernel.org/r/20210627051202.1888250-1-nathan@kernel.org
Signed-off-by: Takashi Iwai <tiwai@suse.de>
For configuration items with a size of 16, scarlett2_usb_get_config()
was filling *buf with little-endian data. Update it to convert to CPU
endian. This function is not currently used so affects nothing yet;
will be used by the upcoming talkback feature.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/cbc8b6eedd859dd27086ab4126d724a86dd50bcb.1624379707.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The 18i8 and 18i20 Gen 3 support "speaker switching". Add a Speaker
Switch control which can be set to Off/Main/Alt.
When speaker switching is enabled or disabled, the interface may
change the state of the Analog Outputs 3 and 4 routing and the global
mute button, so use a flag private->speaker_switching_switched to note
that those should be checked when the next "monitor other"
notification is received.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/874193a534cd0aeb6f2e108ae761cadd2dc25ad2.1624379707.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Split part of scarlett2_sw_hw_enum_ctl_put() out into
scarlett2_sw_hw_change() so that the code which actually makes the
change is available in its own function. This will be used by the
speaker switching support which needs to set the SW/HW switch to HW
when speaker switching is enabled.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/f2cf91841ba067b490e7709bc4b14f4532b4ddd5.1624379707.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The current way of the scarlett2 mixer code managing the
usb_mixer_elem_info object is wrong in two ways: it passes its
internal index to the head.id field, and the val_type field is
uninitialized. This ended up with the wrong execution at the resume
because a bogus unit id is passed wrongly. Also, in the later code
extensions, we'll have more mixer elements, and passing the index will
overflow the unit id size (of 256).
This patch corrects those issues. It introduces a new value type,
USB_MIXER_BESPOKEN, which indicates a non-standard mixer element, and
use this type for all scarlett2 mixer elements, as well as
initializing the fixed unit id 0 for avoiding the overflow.
Tested-by: Geoffrey D. Bennett <g@b4.vu>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/49721219f45b7e175e729b0d9d9c142fd8f4342a.1624379707.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Some Gen 3 devices do not put all of the mux entries for the same port
types together in order in the "set mux" message data. To prepare for
this, replace the struct scarlett2_ports num[] array and the
assignment_order[] array with mux_assignment[], a list of port types
and ranges that is defined in the struct scarlett2_device_info.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/08e8d784d78262cb57496d28ef1ad7b6213a90ab.1624294591.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
For each analogue output, in addition to the output volume (gain)
control, the hardware also has a mute control. Add ALSA mute controls
for each analogue output.
If the device has the line_out_hw_vol feature, then the mute control
is disabled along with the output volume control when the switch is
set to HW.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/6fad82174b44633e46cfd96332a038de74d544f2.1624294591.git.g@b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
At extending the available mixer values for 32bit types, we forgot to
add the corresponding entries for the format dump in the proc output.
This may result in OOB access. Here adds the missing entries.
Fixes: bc18e31c30 ("ALSA: usb-audio: Fix parameter block size for UAC2 control requests")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210622090647.14021-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Fix mixer control callbacks to use the correct members of the struct
snd_ctl_elem_value. The use of value.integer and value.enumerated were
swapped in a few places.
Update scarlett2_mux_src_enum_ctl_put() to use min() instead of
clamp() as value.enumerated.item is unsigned.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164647.GA9226@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The private->vol_updated flag was being checked outside of the
mutex_lock/unlock() of private->data_mutex leading to the volume data
being fetched twice from the device unnecessarily or old volume data
being returned.
Update scarlett2_*_ctl_get() and include the private->vol_updated flag
check inside the critical region.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164643.GA9216@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Rename struct scarlett2_mixer_data to struct scarlett2_data. A
less-wordy name is better because it is used everywhere, and although
this is a mixer driver, it also controls other vendor-specific
features.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164639.GA9206@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
To match the vendor's terminology, change #defines, identifiers, and
comments:
- mute/dim/hardware buttons are now called dim/mute
- mixer status/interrupt is now notify
- vol is now monitor
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164636.GA9199@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
The per-model button_count value was used to determine whether
dim/mute controls should be added, but these are present iff
line_out_hw_vol is true. Remove button_count and replace with
SCARLETT2_BUTTON_MAX and a check for line_out_hw_vol true.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164634.GA9193@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Just ignore instead of printing an error if the interrupt data is not
the expected length. This check was for development and the condition
has not been observed.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/20210620164632.GA9186@m.b4.vu
Signed-off-by: Takashi Iwai <tiwai@suse.de>