Skip to content

Commit 24d0c9f

Browse files
committed
ALSA: usb-audio: Limit max buffer and period sizes per time
In the previous fix, we increased the max buffer bytes from 1MB to 4MB so that we can use bigger buffers for the modern HiFi devices with higher rates, more channels and wider formats. OTOH, extending this has a concern that too big buffer is allowed for the lower rates, less channels and narrower formats; when an application tries to allocate as big buffer as possible, it'll lead to unexpectedly too huge size. Also, we had a problem about the inconsistent max buffer and period bytes for the implicit feedback mode when both streams have different channels. This was fixed by the (relatively complex) patch to reduce the max buffer and period bytes accordingly. This is an alternative fix for those, a patch to kill two birds with one stone (*): instead of increasing the max buffer bytes blindly and applying the reduction per channels, we simply use the hw constraints for the buffer and period "time". Meanwhile the max buffer and period bytes are set unlimited instead. Since the inconsistency of buffer (and period) bytes comes from the difference of the channels in the tied streams, as long as we care only about the buffer (and period) time, it doesn't matter; the buffer time is same for different channels, although we still allow higher buffer size. Similarly, this will allow more buffer bytes for HiFi devices while it also keeps the reasonable size for the legacy devices, too. As of this patch, the max period and buffer time are set to 1 and 2 seconds, which should be large enough for all possible use cases. (*) No animals were harmed in the making of this patch. Fixes: 98c27ad ("ALSA: usb-audio: Cap upper limits of buffer/period bytes for implicit fb") Fixes: fee2ec8 ("ALSA: usb-audio: Increase max buffer size") Link: https://lore.kernel.org/r/20220412130740.18933-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 925ca89 commit 24d0c9f

1 file changed

Lines changed: 14 additions & 87 deletions

File tree

sound/usb/pcm.c

Lines changed: 14 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,6 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
659659
#define hwc_debug(fmt, args...) do { } while(0)
660660
#endif
661661

662-
#define MAX_BUFFER_BYTES (4 * 1024 * 1024)
663-
#define MAX_PERIOD_BYTES (512 * 1024)
664-
665662
static const struct snd_pcm_hardware snd_usb_hardware =
666663
{
667664
.info = SNDRV_PCM_INFO_MMAP |
@@ -672,9 +669,9 @@ static const struct snd_pcm_hardware snd_usb_hardware =
672669
SNDRV_PCM_INFO_PAUSE,
673670
.channels_min = 1,
674671
.channels_max = 256,
675-
.buffer_bytes_max = MAX_BUFFER_BYTES,
672+
.buffer_bytes_max = INT_MAX, /* limited by BUFFER_TIME later */
676673
.period_bytes_min = 64,
677-
.period_bytes_max = MAX_PERIOD_BYTES,
674+
.period_bytes_max = INT_MAX, /* limited by PERIOD_TIME later */
678675
.periods_min = 2,
679676
.periods_max = 1024,
680677
};
@@ -974,78 +971,6 @@ static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
974971
ep->cur_buffer_periods);
975972
}
976973

977-
/* get the adjusted max buffer (or period) bytes that can fit with the
978-
* paired format for implicit fb
979-
*/
980-
static unsigned int
981-
get_adjusted_max_bytes(struct snd_usb_substream *subs,
982-
struct snd_usb_substream *pair,
983-
struct snd_pcm_hw_params *params,
984-
unsigned int max_bytes,
985-
bool reverse_map)
986-
{
987-
const struct audioformat *fp, *pp;
988-
unsigned int rmax = 0, r;
989-
990-
list_for_each_entry(fp, &subs->fmt_list, list) {
991-
if (!fp->implicit_fb)
992-
continue;
993-
if (!reverse_map &&
994-
!hw_check_valid_format(subs, params, fp))
995-
continue;
996-
list_for_each_entry(pp, &pair->fmt_list, list) {
997-
if (pp->iface != fp->sync_iface ||
998-
pp->altsetting != fp->sync_altsetting ||
999-
pp->ep_idx != fp->sync_ep_idx)
1000-
continue;
1001-
if (reverse_map &&
1002-
!hw_check_valid_format(pair, params, pp))
1003-
break;
1004-
if (!reverse_map && pp->channels > fp->channels)
1005-
r = max_bytes * fp->channels / pp->channels;
1006-
else if (reverse_map && pp->channels < fp->channels)
1007-
r = max_bytes * pp->channels / fp->channels;
1008-
else
1009-
r = max_bytes;
1010-
rmax = max(rmax, r);
1011-
break;
1012-
}
1013-
}
1014-
return rmax;
1015-
}
1016-
1017-
/* Reduce the period or buffer bytes depending on the paired substream;
1018-
* when a paired configuration for implicit fb has a higher number of channels,
1019-
* we need to reduce the max size accordingly, otherwise it may become unusable
1020-
*/
1021-
static int hw_rule_bytes_implicit_fb(struct snd_pcm_hw_params *params,
1022-
struct snd_pcm_hw_rule *rule)
1023-
{
1024-
struct snd_usb_substream *subs = rule->private;
1025-
struct snd_usb_substream *pair;
1026-
struct snd_interval *it;
1027-
unsigned int max_bytes;
1028-
unsigned int rmax;
1029-
1030-
pair = &subs->stream->substream[!subs->direction];
1031-
if (!pair->ep_num)
1032-
return 0;
1033-
1034-
if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_BYTES)
1035-
max_bytes = MAX_PERIOD_BYTES;
1036-
else
1037-
max_bytes = MAX_BUFFER_BYTES;
1038-
1039-
rmax = get_adjusted_max_bytes(subs, pair, params, max_bytes, false);
1040-
if (!rmax)
1041-
rmax = get_adjusted_max_bytes(pair, subs, params, max_bytes, true);
1042-
if (!rmax)
1043-
return 0;
1044-
1045-
it = hw_param_interval(params, rule->var);
1046-
return apply_hw_params_minmax(it, 0, rmax);
1047-
}
1048-
1049974
/*
1050975
* set up the runtime hardware information.
1051976
*/
@@ -1139,6 +1064,18 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
11391064
return err;
11401065
}
11411066

1067+
/* set max period and buffer sizes for 1 and 2 seconds, respectively */
1068+
err = snd_pcm_hw_constraint_minmax(runtime,
1069+
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
1070+
0, 1000000);
1071+
if (err < 0)
1072+
return err;
1073+
err = snd_pcm_hw_constraint_minmax(runtime,
1074+
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
1075+
0, 2000000);
1076+
if (err < 0)
1077+
return err;
1078+
11421079
/* additional hw constraints for implicit fb */
11431080
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
11441081
hw_rule_format_implicit_fb, subs,
@@ -1160,16 +1097,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
11601097
SNDRV_PCM_HW_PARAM_PERIODS, -1);
11611098
if (err < 0)
11621099
return err;
1163-
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1164-
hw_rule_bytes_implicit_fb, subs,
1165-
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
1166-
if (err < 0)
1167-
return err;
1168-
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
1169-
hw_rule_bytes_implicit_fb, subs,
1170-
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
1171-
if (err < 0)
1172-
return err;
11731100

11741101
list_for_each_entry(fp, &subs->fmt_list, list) {
11751102
if (fp->implicit_fb) {

0 commit comments

Comments
 (0)