[PATCH] ALSA: memalloc: Revive x86-specific WC page allocations again
We dropped the x86-specific hack for WC-page allocations with a hope that the standard dma_alloc_wc() works nowadays. Alas, it doesn't, and we need to take back some workaround again, but in a different form, as the previous one was broken for some platforms.
This patch re-introduces the x86-specific WC-page allocations, but it uses rather the manual page allocations instead of dma_alloc_coherent(). The use of dma_alloc_coherent() was also a potential problem in the recent addition of the fallback allocation for noncontig pages, and this patch eliminates both at once.
Fixes: 9882d63bea14 ("ALSA: memalloc: Drop x86-specific hack for WC allocations") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=216363 Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/memalloc.c | 87 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 16 deletions(-)
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index d3885cb02270..90d74855d988 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -20,6 +20,13 @@
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
+#ifdef CONFIG_SND_DMA_SGBUF +static void *do_alloc_fallback_pages(struct device *dev, size_t size, + dma_addr_t *addr, bool wc); +static void do_free_fallback_pages(void *p, size_t size, bool wc); +static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size); +#endif + /* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */ static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab, gfp_t default_gfp) @@ -277,16 +284,21 @@ EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); /* * Continuous pages allocator */ -static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +static void *do_alloc_pages(size_t size, dma_addr_t *addr, unsigned long gfp) { - gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL); void *p = alloc_pages_exact(size, gfp);
if (p) - dmab->addr = page_to_phys(virt_to_page(p)); + *addr = page_to_phys(virt_to_page(p)); return p; }
+static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + return do_alloc_pages(size, &dmab->addr, + snd_mem_get_gfp_flags(dmab, GFP_KERNEL)); +} + static void snd_dma_continuous_free(struct snd_dma_buffer *dmab) { free_pages_exact(dmab->area, dmab->bytes); @@ -463,6 +475,25 @@ static const struct snd_malloc_ops snd_dma_dev_ops = { /* * Write-combined pages */ +/* x86-specific allocations */ +#ifdef CONFIG_SND_DMA_SGBUF +static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) +{ + return do_alloc_fallback_pages(dmab->dev.dev, size, &dmab->addr, true); +} + +static void snd_dma_wc_free(struct snd_dma_buffer *dmab) +{ + do_free_fallback_pages(dmab->area, dmab->bytes, true); +} + +static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); + return snd_dma_continuous_mmap(dmab, area); +} +#else static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) { return dma_alloc_wc(dmab->dev.dev, size, &dmab->addr, DEFAULT_GFP); @@ -479,6 +510,7 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab, return dma_mmap_wc(dmab->dev.dev, area, dmab->area, dmab->addr, dmab->bytes); } +#endif /* CONFIG_SND_DMA_SGBUF */
static const struct snd_malloc_ops snd_dma_wc_ops = { .alloc = snd_dma_wc_alloc, @@ -486,10 +518,6 @@ static const struct snd_malloc_ops snd_dma_wc_ops = { .mmap = snd_dma_wc_mmap, };
-#ifdef CONFIG_SND_DMA_SGBUF -static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size); -#endif - /* * Non-contiguous pages allocator */ @@ -669,6 +697,37 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = { .get_chunk_size = snd_dma_noncontig_get_chunk_size, };
+/* manual page allocations with wc setup */ +static void *do_alloc_fallback_pages(struct device *dev, size_t size, + dma_addr_t *addr, bool wc) +{ + void *p; + unsigned long gfp = DEFAULT_GFP & ~__GFP_COMP; + + again: + p = do_alloc_pages(size, addr, gfp); + if (!p || (*addr + size - 1) & ~dev->coherent_dma_mask) { + if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) { + gfp |= GFP_DMA32; + goto again; + } + if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { + gfp = (gfp & ~GFP_DMA32) | GFP_DMA; + goto again; + } + } + if (p && wc) + set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT); + return p; +} + +static void do_free_fallback_pages(void *p, size_t size, bool wc) +{ + if (wc) + set_memory_wb((unsigned long)(p), size >> PAGE_SHIFT); + free_pages_exact(p, size); +} + /* Fallback SG-buffer allocations for x86 */ struct snd_dma_sg_fallback { size_t count; @@ -679,14 +738,11 @@ struct snd_dma_sg_fallback { static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab, struct snd_dma_sg_fallback *sgbuf) { + bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK; size_t i;
- if (sgbuf->count && dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK) - set_pages_array_wb(sgbuf->pages, sgbuf->count); for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++) - dma_free_coherent(dmab->dev.dev, PAGE_SIZE, - page_address(sgbuf->pages[i]), - sgbuf->addrs[i]); + do_free_fallback_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc); kvfree(sgbuf->pages); kvfree(sgbuf->addrs); kfree(sgbuf); @@ -698,6 +754,7 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) struct page **pages; size_t i, count; void *p; + bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (!sgbuf) @@ -712,15 +769,13 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) goto error;
for (i = 0; i < count; sgbuf->count++, i++) { - p = dma_alloc_coherent(dmab->dev.dev, PAGE_SIZE, - &sgbuf->addrs[i], DEFAULT_GFP); + p = do_alloc_fallback_pages(dmab->dev.dev, PAGE_SIZE, + &sgbuf->addrs[i], wc); if (!p) goto error; sgbuf->pages[i] = virt_to_page(p); }
- if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK) - set_pages_array_wc(pages, count); p = vmap(pages, count, VM_MAP, PAGE_KERNEL); if (!p) goto error;
Hi Takashi,
I love your patch! Perhaps something to improve:
[auto build test WARNING on tiwai-sound/for-next] [also build test WARNING on linus/master v6.0-rc1 next-20220819] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Takashi-Iwai/ALSA-memalloc-Re... base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next config: openrisc-randconfig-s052-20220821 (https://download.01.org/0day-ci/archive/20220821/202208211945.6Lmqeudy-lkp@i...) compiler: or1k-linux-gcc (GCC) 12.1.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-39-gce1a6720-dirty # https://github.com/intel-lab-lkp/linux/commit/86072b28544f52618e4ce8336ba80b... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Takashi-Iwai/ALSA-memalloc-Revive-x86-specific-WC-page-allocations-again/20220821-162443 git checkout 86072b28544f52618e4ce8336ba80be1d67f38d9 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=openrisc SHELL=/bin/bash sound/core/
If you fix the issue, kindly add following tag where applicable Reported-by: kernel test robot lkp@intel.com
sparse warnings: (new ones prefixed by >>)
sound/core/memalloc.c:289:43: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted gfp_t [usertype] gfp_mask @@ got unsigned long gfp @@
sound/core/memalloc.c:289:43: sparse: expected restricted gfp_t [usertype] gfp_mask sound/core/memalloc.c:289:43: sparse: got unsigned long gfp
sound/core/memalloc.c:299:52: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned long gfp @@ got restricted gfp_t @@
sound/core/memalloc.c:299:52: sparse: expected unsigned long gfp sound/core/memalloc.c:299:52: sparse: got restricted gfp_t
vim +289 sound/core/memalloc.c
37af81c5998f4b Takashi Iwai 2021-06-09 283 37af81c5998f4b Takashi Iwai 2021-06-09 284 /* 37af81c5998f4b Takashi Iwai 2021-06-09 285 * Continuous pages allocator 37af81c5998f4b Takashi Iwai 2021-06-09 286 */ 86072b28544f52 Takashi Iwai 2022-08-21 287 static void *do_alloc_pages(size_t size, dma_addr_t *addr, unsigned long gfp) 37af81c5998f4b Takashi Iwai 2021-06-09 288 { f84ba106a0185b Takashi Iwai 2021-08-04 @289 void *p = alloc_pages_exact(size, gfp); 37af81c5998f4b Takashi Iwai 2021-06-09 290 f84ba106a0185b Takashi Iwai 2021-08-04 291 if (p) 86072b28544f52 Takashi Iwai 2022-08-21 292 *addr = page_to_phys(virt_to_page(p)); f84ba106a0185b Takashi Iwai 2021-08-04 293 return p; 37af81c5998f4b Takashi Iwai 2021-06-09 294 } 37af81c5998f4b Takashi Iwai 2021-06-09 295 86072b28544f52 Takashi Iwai 2022-08-21 296 static void *snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size) 86072b28544f52 Takashi Iwai 2022-08-21 297 { 86072b28544f52 Takashi Iwai 2022-08-21 298 return do_alloc_pages(size, &dmab->addr, 86072b28544f52 Takashi Iwai 2022-08-21 @299 snd_mem_get_gfp_flags(dmab, GFP_KERNEL)); 86072b28544f52 Takashi Iwai 2022-08-21 300 } 86072b28544f52 Takashi Iwai 2022-08-21 301
Hi Takashi,
I love your patch! Perhaps something to improve:
[auto build test WARNING on tiwai-sound/for-next] [also build test WARNING on linus/master v6.0-rc1 next-20220819] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Takashi-Iwai/ALSA-memalloc-Re... base: https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next config: i386-randconfig-s001 (https://download.01.org/0day-ci/archive/20220821/202208212226.7Ji4ZW8k-lkp@i...) compiler: gcc-11 (Debian 11.3.0-5) 11.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.4-39-gce1a6720-dirty # https://github.com/intel-lab-lkp/linux/commit/86072b28544f52618e4ce8336ba80b... git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Takashi-Iwai/ALSA-memalloc-Revive-x86-specific-WC-page-allocations-again/20220821-162443 git checkout 86072b28544f52618e4ce8336ba80be1d67f38d9 # save the config file mkdir build_dir && cp config build_dir/.config make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=i386 SHELL=/bin/bash sound/core/
If you fix the issue, kindly add following tag where applicable Reported-by: kernel test robot lkp@intel.com
sparse warnings: (new ones prefixed by >>)
sound/core/memalloc.c:705:41: sparse: sparse: incorrect type in initializer (different base types) @@ expected unsigned long gfp @@ got restricted gfp_t @@
sound/core/memalloc.c:705:41: sparse: expected unsigned long gfp sound/core/memalloc.c:705:41: sparse: got restricted gfp_t
sound/core/memalloc.c:710:62: sparse: sparse: restricted gfp_t degrades to integer sound/core/memalloc.c:711:29: sparse: sparse: invalid assignment: |= sound/core/memalloc.c:711:29: sparse: left side has type unsigned long sound/core/memalloc.c:711:29: sparse: right side has type restricted gfp_t
sound/core/memalloc.c:714:60: sparse: sparse: restricted gfp_t degrades to integer sound/core/memalloc.c:715:38: sparse: sparse: restricted gfp_t degrades to integer sound/core/memalloc.c:715:52: sparse: sparse: restricted gfp_t degrades to integer sound/core/memalloc.c:289:43: sparse: sparse: incorrect type in argument 2 (different base types) @@ expected restricted gfp_t [usertype] gfp_mask @@ got unsigned long gfp @@ sound/core/memalloc.c:289:43: sparse: expected restricted gfp_t [usertype] gfp_mask sound/core/memalloc.c:289:43: sparse: got unsigned long gfp sound/core/memalloc.c:299:52: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned long gfp @@ got restricted gfp_t @@ sound/core/memalloc.c:299:52: sparse: expected unsigned long gfp sound/core/memalloc.c:299:52: sparse: got restricted gfp_t
vim +705 sound/core/memalloc.c
699 700 /* manual page allocations with wc setup */ 701 static void *do_alloc_fallback_pages(struct device *dev, size_t size, 702 dma_addr_t *addr, bool wc) 703 { 704 void *p;
705 unsigned long gfp = DEFAULT_GFP & ~__GFP_COMP;
706 707 again: 708 p = do_alloc_pages(size, addr, gfp); 709 if (!p || (*addr + size - 1) & ~dev->coherent_dma_mask) {
710 if (IS_ENABLED(CONFIG_ZONE_DMA32) && !(gfp & GFP_DMA32)) { 711 gfp |= GFP_DMA32;
712 goto again; 713 } 714 if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { 715 gfp = (gfp & ~GFP_DMA32) | GFP_DMA; 716 goto again; 717 } 718 } 719 if (p && wc) 720 set_memory_wc((unsigned long)(p), size >> PAGE_SHIFT); 721 return p; 722 } 723
participants (2)
-
kernel test robot
-
Takashi Iwai