[PATCH v2 0/3] Fix SND_HDA_PREALLOC issue

For context it started with user reporting failures when running arecord without any error or warning in dmesg (after fixing some configuration problems thet they had). https://bugzilla.kernel.org/show_bug.cgi?id=201251#c279
After spending time investigating the issue it was narrowed to quite big setting of CONFIG_SND_HDA_PREALLOC_SIZE (4096). When looking at code https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/soun... there is a limit of memory per card: max_alloc_per_card = 32UL * 1024UL * 1024UL
When SND_HDA_PREALLOC_SIZE is set to 4096 it only has memory to alloc for 8 frontends, while Skylake HDA card has 10 of them (6 playback and 4 capture), so preallocated memory is exhausted while probing. In consequence 2 of FEs end without allocated memory.
It can be workarounded on user side with setting SND_HDA_PREALLOC_SIZE to lower value, other is changing memory limit per card.
However in order to not waste user memory, change maximum allocation size on HDA controller to 4MB and force automatical memory allocation insted of preallocated one.
First patch adds prints, so similar issues can be easily identified in the future. Second changes maximum size of hda buffer to reasonable value of 4MB. And last one reverts patch which allowed setting prealloc size on X86 platforms.
Amadeusz Sławiński (3): ALSA: pcm: Add debug print on memory allocation failure ALSA: hda: Change AZX_MAX_BUF_SIZE from 1GB to 4MB ALSA: hda: Revert "ALSA: hda: Allow setting preallocation again for x86"
include/sound/hda_register.h | 8 ++++++-- sound/core/pcm_memory.c | 8 ++++++++ sound/hda/Kconfig | 7 +++---- 3 files changed, 17 insertions(+), 6 deletions(-)

Add debug prints after calls of do_alloc_pages. One simplification would be to move print into do_alloc_pages, however it would cause spam in logs, as preallocate_pcm_pages loops over do_alloc_pages trying lower values in case of failures.
Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com --- sound/core/pcm_memory.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 289dd1fd8fe7..2878c4c23583 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -176,6 +176,10 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return; } substream->buffer_bytes_max = size; @@ -400,6 +404,10 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) substream->dma_buffer.dev.dev, size, dmab) < 0) { kfree(dmab); + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return -ENOMEM; } }

When SND_HDA_PREALLOC_SIZE is set to 0, applications can request as much memory as there is allowed. With value of AZX_MAX_BUF_SIZE it is 1GB per stream, which is not realistic use case. Change it 4MB.
Bug: https://bugzilla.kernel.org/show_bug.cgi?id=201251#c322 Suggested-by: Takashi Iwai tiwai@suse.de Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com ---
Changes:
v2: explain in comment that it is an artificial limit, as HW allows for bigger allocations
--- include/sound/hda_register.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 4f987b1f32f7..ad8b71b1dbb6 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -140,8 +140,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) #define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) +/* + * max buffer size - artificial 4MB limit per stream to avoid big allocations + * In theory it can be really big, but as it is per stream on systems with many streams memory could + * be quickly saturated if userspace requests maximum buffer size for each of them. + */ +#define AZX_MAX_BUF_SIZE (4*1024*1024)
/* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01

This reverts commit f8e4ae10de43 ("ALSA: hda: Allow setting preallocation again for x86").
The reverted commit itself is a revert of c31427d0d21e ("ALSA: hda: No preallocation on x86 platforms"). It was needed because HDA allowed very big allocations, up to 1GB per stream. However as previous commit in this series changes maximum allowed allocation per stream to 4MB, we can safely revert it back.
On systems where there are a lot of FrontEnds, when CONFIG_SND_HDA_PREALLOC_SIZE != 0 ALSA core allocates memory for each FE, which may cause out of memory problems due to per card limit. Force config to 0 on X86, so memory will be allocated on as needed basis.
Bug: https://bugzilla.kernel.org/show_bug.cgi?id=201251#c322 Suggested-by: Takashi Iwai tiwai@suse.de Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com ---
Changes:
v2: improve commit message as requested to explain, why it is safe to revert
--- sound/hda/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 57595f1552c9..741179ccbd4e 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -21,17 +21,16 @@ config SND_HDA_EXT_CORE select SND_HDA_CORE
config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" + int "Pre-allocated buffer size for HD-audio driver" if !SND_DMA_SGBUF range 0 32768 - default 2048 if SND_DMA_SGBUF + default 0 if SND_DMA_SGBUF default 64 if !SND_DMA_SGBUF help Specifies the default pre-allocated buffer-size in kB for the HD-audio driver. A larger buffer (e.g. 2048) is preferred for systems using PulseAudio. The default 64 is chosen just for compatibility reasons. - On x86 systems, the default is 2048 as a reasonable value for - most of modern systems. + On x86 systems, the default is zero as we need no preallocation.
Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.

On Thu, 18 Mar 2021 17:06:15 +0100, Amadeusz Sławiński wrote:
For context it started with user reporting failures when running arecord without any error or warning in dmesg (after fixing some configuration problems thet they had). https://bugzilla.kernel.org/show_bug.cgi?id=201251#c279
After spending time investigating the issue it was narrowed to quite big setting of CONFIG_SND_HDA_PREALLOC_SIZE (4096). When looking at code https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/soun... there is a limit of memory per card: max_alloc_per_card = 32UL * 1024UL * 1024UL
When SND_HDA_PREALLOC_SIZE is set to 4096 it only has memory to alloc for 8 frontends, while Skylake HDA card has 10 of them (6 playback and 4 capture), so preallocated memory is exhausted while probing. In consequence 2 of FEs end without allocated memory.
It can be workarounded on user side with setting SND_HDA_PREALLOC_SIZE to lower value, other is changing memory limit per card.
However in order to not waste user memory, change maximum allocation size on HDA controller to 4MB and force automatical memory allocation insted of preallocated one.
First patch adds prints, so similar issues can be easily identified in the future. Second changes maximum size of hda buffer to reasonable value of 4MB. And last one reverts patch which allowed setting prealloc size on X86 platforms.
Amadeusz Sławiński (3): ALSA: pcm: Add debug print on memory allocation failure ALSA: hda: Change AZX_MAX_BUF_SIZE from 1GB to 4MB ALSA: hda: Revert "ALSA: hda: Allow setting preallocation again for x86"
Applied all three patches now. Thanks.
Takashi
participants (2)
-
Amadeusz Sławiński
-
Takashi Iwai