diff mbox series

ALSA: memalloc: Revive x86-specific WC page allocations again

Message ID 20220821082241.23722-1-tiwai@suse.de (mailing list archive)
State Superseded
Headers show
Series ALSA: memalloc: Revive x86-specific WC page allocations again | expand

Commit Message

Takashi Iwai Aug. 21, 2022, 8:22 a.m. UTC
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(-)

Comments

kernel test robot Aug. 21, 2022, 11:48 a.m. UTC | #1
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-Revive-x86-specific-WC-page-allocations-again/20220821-162443
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@intel.com/config)
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/86072b28544f52618e4ce8336ba80be1d67f38d9
        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
kernel test robot Aug. 21, 2022, 2:31 p.m. UTC | #2
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-Revive-x86-specific-WC-page-allocations-again/20220821-162443
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@intel.com/config)
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/86072b28544f52618e4ce8336ba80be1d67f38d9
        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
diff mbox series

Patch

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;