linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [BUG] net: sungem: device driver frees DMA memory with wrong function
@ 2018-12-23 19:38 Corentin Labbe
  2018-12-24 22:39 ` David Miller
  2018-12-28  8:36 ` Christoph Hellwig
  0 siblings, 2 replies; 4+ messages in thread
From: Corentin Labbe @ 2018-12-23 19:38 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel

Hello

During a boot on a qemu machine, I hit the following problem:
[   21.613659] ------------[ cut here ]------------
[   21.614039] DMA-API: gem 0000:00:0f.0: device driver frees DMA memory with wrong function [device address=0x00000000185c5402] [size=408 bytes] [mapped as page] [unmapped as single]
[   21.615960] WARNING: CPU: 0 PID: 206 at /linux-next/kernel/dma/debug.c:1085 check_unmap+0x1b0/0xd10
[   21.616599] Modules linked in:
[   21.617344] CPU: 0 PID: 206 Comm: dhcpcd Not tainted 4.20.0-rc6-next-20181217+ #12
[   21.617735] NIP:  c00ad4e0 LR: c00ad4e0 CTR: c058a710
[   21.618068] REGS: dfff7cb0 TRAP: 0700   Not tainted  (4.20.0-rc6-next-20181217+)
[   21.618404] MSR:  00021032 <ME,IR,DR,RI>  CR: 28008264  XER: 00000000
[   21.618789] 
[   21.618789] GPR00: c00ad4e0 dfff7d60 d85924c0 000000a8 00000102 00000101 000000fe 5d205b6d 
[   21.618789] GPR08: 00000007 00000000 00000000 000000fe 22008864 100581b4 dfff7f1c de019508 
[   21.618789] GPR16: 00000000 de019000 00000001 c0a67f00 00000004 c0b44018 c0a31fc4 c0b43bdc 
[   21.618789] GPR24: 00009032 c0dadedc c0db0000 c0da999c c0b43bdc c0c0b178 dfff7de0 de076ce8 
[   21.620219] NIP [c00ad4e0] check_unmap+0x1b0/0xd10
[   21.620478] LR [c00ad4e0] check_unmap+0x1b0/0xd10
[   21.620703] Call Trace:
[   21.620963] [dfff7d60] [c00ad4e0] check_unmap+0x1b0/0xd10 (unreliable)
[   21.621379] [dfff7dd0] [c00ae128] debug_dma_unmap_page+0xe8/0x120
[   21.621656] [dfff7e40] [c05a865c] gem_poll+0x1000/0x18fc
[   21.621863] [dfff7f00] [c071f044] net_rx_action+0x1b8/0x41c
[   21.622242] [dfff7f80] [c08a287c] __do_softirq+0x17c/0x3b0
[   21.622495] [dfff7ff0] [c0011378] call_do_softirq+0x24/0x3c
[   21.622697] [d86c9c20] [c000724c] do_softirq_own_stack+0x3c/0x7c
[   21.623008] [d86c9c40] [c004e800] do_softirq.part.1+0x64/0x7c
[   21.623292] [d86c9c60] [c004e8d4] __local_bh_enable_ip+0xbc/0x138
[   21.623526] [d86c9c80] [c071c9b4] __dev_queue_xmit+0x28c/0x874
[   21.623776] [d86c9cf0] [c083ebe8] packet_snd+0x4f8/0x988
[   21.624057] [d86c9d80] [c06eddb8] sock_sendmsg+0x20/0x40
[   21.624410] [d86c9d90] [c06ede94] sock_write_iter+0xbc/0x138
[   21.624636] [d86c9df0] [c018f50c] do_iter_readv_writev+0x1dc/0x1f4
[   21.624872] [d86c9e40] [c01925a8] do_iter_write+0xb4/0x350
[   21.625143] [d86c9e80] [c01928f4] vfs_writev+0x88/0x140
[   21.625446] [d86c9f00] [c0192a1c] do_writev+0x70/0x104
[   21.625621] [d86c9f40] [c001912c] ret_from_syscall+0x0/0x38
[   21.626001] --- interrupt: c01 at 0xfedbd08
[   21.626001]     LR = 0xffbc1f8
[   21.626357] Instruction dump:
[   21.626719] 7eb5ba14 7e95a214 2b940014 419d0970 92c10008 7efcba14 3c60c0a1 7e649b78 
[   21.627152] 38637cac 80d7043c 90c1000c 4bf9d36d <0fe00000> 8261003c 82810040 82a10044 
[   21.627665] ---[ end trace fd53714bd2a5fd06 ]---

After some pr_info, I found that the function triggering this is the pci_unmap_page() in gem_tx().
So clearly this WARNING() is strange since it says "unmapped as single".

The qemu is ran with:
qemu-system-ppc -machine mac99,via=pmu -nographic -net nic,model=sungem,macaddr=52:54:00:12:34:58 -net tap -m 512 -monitor none -append "console=ttyPZ0 root=/dev/ram0" -kernel vmlinux -initrd rootfs.cpio.gz -drive format=qcow2,file=lava-guest.qcow2,media=disk,id=test,if=ide

Regards

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [BUG] net: sungem: device driver frees DMA memory with wrong function
  2018-12-23 19:38 [BUG] net: sungem: device driver frees DMA memory with wrong function Corentin Labbe
@ 2018-12-24 22:39 ` David Miller
  2018-12-28  8:36 ` Christoph Hellwig
  1 sibling, 0 replies; 4+ messages in thread
From: David Miller @ 2018-12-24 22:39 UTC (permalink / raw)
  To: clabbe.montjoie; +Cc: netdev, linux-kernel

From: Corentin Labbe <clabbe.montjoie@gmail.com>
Date: Sun, 23 Dec 2018 20:38:21 +0100

> During a boot on a qemu machine, I hit the following problem:
 ...
> After some pr_info, I found that the function triggering this is the pci_unmap_page() in gem_tx().
> So clearly this WARNING() is strange since it says "unmapped as single".

I also went through the code paths and this makes no sense to me either.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [BUG] net: sungem: device driver frees DMA memory with wrong function
  2018-12-23 19:38 [BUG] net: sungem: device driver frees DMA memory with wrong function Corentin Labbe
  2018-12-24 22:39 ` David Miller
@ 2018-12-28  8:36 ` Christoph Hellwig
  2019-01-02 10:31   ` Corentin Labbe
  1 sibling, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2018-12-28  8:36 UTC (permalink / raw)
  To: Corentin Labbe; +Cc: davem, netdev, linux-kernel

Please try this patch:

diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index a52c6409bdc2..f454e0ed1398 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -284,32 +284,25 @@ static inline void dma_direct_sync_sg_for_cpu(struct device *dev,
 }
 #endif
 
-static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
-					      size_t size,
-					      enum dma_data_direction dir,
-					      unsigned long attrs)
+static inline dma_addr_t dma_map_page_attrs(struct device *dev,
+		struct page *page, size_t offset, size_t size,
+		enum dma_data_direction dir, unsigned long attrs)
 {
 	const struct dma_map_ops *ops = get_dma_ops(dev);
 	dma_addr_t addr;
 
 	BUG_ON(!valid_dma_direction(dir));
-	debug_dma_map_single(dev, ptr, size);
 	if (dma_is_direct(ops))
-		addr = dma_direct_map_page(dev, virt_to_page(ptr),
-				offset_in_page(ptr), size, dir, attrs);
+		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
 	else
-		addr = ops->map_page(dev, virt_to_page(ptr),
-				offset_in_page(ptr), size, dir, attrs);
-	debug_dma_map_page(dev, virt_to_page(ptr),
-			   offset_in_page(ptr), size,
-			   dir, addr, true);
+		addr = ops->map_page(dev, page, offset, size, dir, attrs);
+	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
+
 	return addr;
 }
 
-static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
-					  size_t size,
-					  enum dma_data_direction dir,
-					  unsigned long attrs)
+static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
 	const struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -321,12 +314,6 @@ static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
 	debug_dma_unmap_page(dev, addr, size, dir, true);
 }
 
-static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
-		size_t size, enum dma_data_direction dir, unsigned long attrs)
-{
-	return dma_unmap_single_attrs(dev, addr, size, dir, attrs);
-}
-
 /*
  * dma_maps_sg_attrs returns 0 on error and > 0 on success.
  * It should never return a value < 0.
@@ -363,25 +350,6 @@ static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg
 		ops->unmap_sg(dev, sg, nents, dir, attrs);
 }
 
-static inline dma_addr_t dma_map_page_attrs(struct device *dev,
-					    struct page *page,
-					    size_t offset, size_t size,
-					    enum dma_data_direction dir,
-					    unsigned long attrs)
-{
-	const struct dma_map_ops *ops = get_dma_ops(dev);
-	dma_addr_t addr;
-
-	BUG_ON(!valid_dma_direction(dir));
-	if (dma_is_direct(ops))
-		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
-	else
-		addr = ops->map_page(dev, page, offset, size, dir, attrs);
-	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
-
-	return addr;
-}
-
 static inline dma_addr_t dma_map_resource(struct device *dev,
 					  phys_addr_t phys_addr,
 					  size_t size,
@@ -488,6 +456,19 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 
 }
 
+static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	return dma_map_page_attrs(dev, virt_to_page(ptr), offset_in_page(ptr),
+			size, dir, attrs);
+}
+
+static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
+	return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
+}
+
 #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
 #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [BUG] net: sungem: device driver frees DMA memory with wrong function
  2018-12-28  8:36 ` Christoph Hellwig
@ 2019-01-02 10:31   ` Corentin Labbe
  0 siblings, 0 replies; 4+ messages in thread
From: Corentin Labbe @ 2019-01-02 10:31 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: davem, netdev, linux-kernel

On Fri, Dec 28, 2018 at 12:36:21AM -0800, Christoph Hellwig wrote:
> Please try this patch:
> 

The error type change to "DMA-API: gem 0000:00:0f.0: device driver failed to check map error" (I will send patch for fixing this).
Note that I used the patch from your just sent DMA series (since the patch below is included in).

So you can add my
Tested-by: LABBE Corentin <clabbe.montjoie@gmail.com>

Thanks

> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index a52c6409bdc2..f454e0ed1398 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -284,32 +284,25 @@ static inline void dma_direct_sync_sg_for_cpu(struct device *dev,
>  }
>  #endif
>  
> -static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
> -					      size_t size,
> -					      enum dma_data_direction dir,
> -					      unsigned long attrs)
> +static inline dma_addr_t dma_map_page_attrs(struct device *dev,
> +		struct page *page, size_t offset, size_t size,
> +		enum dma_data_direction dir, unsigned long attrs)
>  {
>  	const struct dma_map_ops *ops = get_dma_ops(dev);
>  	dma_addr_t addr;
>  
>  	BUG_ON(!valid_dma_direction(dir));
> -	debug_dma_map_single(dev, ptr, size);
>  	if (dma_is_direct(ops))
> -		addr = dma_direct_map_page(dev, virt_to_page(ptr),
> -				offset_in_page(ptr), size, dir, attrs);
> +		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
>  	else
> -		addr = ops->map_page(dev, virt_to_page(ptr),
> -				offset_in_page(ptr), size, dir, attrs);
> -	debug_dma_map_page(dev, virt_to_page(ptr),
> -			   offset_in_page(ptr), size,
> -			   dir, addr, true);
> +		addr = ops->map_page(dev, page, offset, size, dir, attrs);
> +	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
> +
>  	return addr;
>  }
>  
> -static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
> -					  size_t size,
> -					  enum dma_data_direction dir,
> -					  unsigned long attrs)
> +static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
> +		size_t size, enum dma_data_direction dir, unsigned long attrs)
>  {
>  	const struct dma_map_ops *ops = get_dma_ops(dev);
>  
> @@ -321,12 +314,6 @@ static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
>  	debug_dma_unmap_page(dev, addr, size, dir, true);
>  }
>  
> -static inline void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr,
> -		size_t size, enum dma_data_direction dir, unsigned long attrs)
> -{
> -	return dma_unmap_single_attrs(dev, addr, size, dir, attrs);
> -}
> -
>  /*
>   * dma_maps_sg_attrs returns 0 on error and > 0 on success.
>   * It should never return a value < 0.
> @@ -363,25 +350,6 @@ static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg
>  		ops->unmap_sg(dev, sg, nents, dir, attrs);
>  }
>  
> -static inline dma_addr_t dma_map_page_attrs(struct device *dev,
> -					    struct page *page,
> -					    size_t offset, size_t size,
> -					    enum dma_data_direction dir,
> -					    unsigned long attrs)
> -{
> -	const struct dma_map_ops *ops = get_dma_ops(dev);
> -	dma_addr_t addr;
> -
> -	BUG_ON(!valid_dma_direction(dir));
> -	if (dma_is_direct(ops))
> -		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
> -	else
> -		addr = ops->map_page(dev, page, offset, size, dir, attrs);
> -	debug_dma_map_page(dev, page, offset, size, dir, addr, false);
> -
> -	return addr;
> -}
> -
>  static inline dma_addr_t dma_map_resource(struct device *dev,
>  					  phys_addr_t phys_addr,
>  					  size_t size,
> @@ -488,6 +456,19 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
>  
>  }
>  
> +static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
> +		size_t size, enum dma_data_direction dir, unsigned long attrs)
> +{
> +	return dma_map_page_attrs(dev, virt_to_page(ptr), offset_in_page(ptr),
> +			size, dir, attrs);
> +}
> +
> +static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
> +		size_t size, enum dma_data_direction dir, unsigned long attrs)
> +{
> +	return dma_unmap_page_attrs(dev, addr, size, dir, attrs);
> +}
> +
>  #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
>  #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
>  #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-01-02 10:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-23 19:38 [BUG] net: sungem: device driver frees DMA memory with wrong function Corentin Labbe
2018-12-24 22:39 ` David Miller
2018-12-28  8:36 ` Christoph Hellwig
2019-01-02 10:31   ` Corentin Labbe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).