]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.4.73/gianfar-synchronize-dma-api-usage-by-free_skb_rx_queue-w-gfar_new_page.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.73 / gianfar-synchronize-dma-api-usage-by-free_skb_rx_queue-w-gfar_new_page.patch
1 From foo@baz Thu Jun 15 13:08:00 CEST 2017
2 From: Arseny Solokha <asolokha@kb.kras.ru>
3 Date: Sun, 29 Jan 2017 19:52:20 +0700
4 Subject: gianfar: synchronize DMA API usage by free_skb_rx_queue w/ gfar_new_page
5
6 From: Arseny Solokha <asolokha@kb.kras.ru>
7
8
9 [ Upstream commit 4af0e5bb95ee3ba5ea4bd7dbb94e1648a5279cc9 ]
10
11 In spite of switching to paged allocation of Rx buffers, the driver still
12 called dma_unmap_single() in the Rx queues tear-down path.
13
14 The DMA region unmapping code in free_skb_rx_queue() basically predates
15 the introduction of paged allocation to the driver. While being refactored,
16 it apparently hasn't reflected the change in the DMA API usage by its
17 counterpart gfar_new_page().
18
19 As a result, setting an interface to the DOWN state now yields the following:
20
21 # ip link set eth2 down
22 fsl-gianfar ffe24000.ethernet: DMA-API: device driver frees DMA memory with wrong function [device address=0x000000001ecd0000] [size=40]
23 ------------[ cut here ]------------
24 WARNING: CPU: 1 PID: 189 at lib/dma-debug.c:1123 check_unmap+0x8e0/0xa28
25 CPU: 1 PID: 189 Comm: ip Tainted: G O 4.9.5 #1
26 task: dee73400 task.stack: dede2000
27 NIP: c02101e8 LR: c02101e8 CTR: c0260d74
28 REGS: dede3bb0 TRAP: 0700 Tainted: G O (4.9.5)
29 MSR: 00021000 <CE,ME> CR: 28002222 XER: 00000000
30
31 GPR00: c02101e8 dede3c60 dee73400 000000b6 dfbd033c dfbd36c4 1f622000 dede2000
32 GPR08: 00000007 c05b1634 1f622000 00000000 22002484 100a9904 00000000 00000000
33 GPR16: 00000000 db4c849c 00000002 db4c8480 00000001 df142240 db4c84bc 00000000
34 GPR24: c0706148 c0700000 00029000 c07552e8 c07323b4 dede3cb8 c07605e0 db535540
35 NIP [c02101e8] check_unmap+0x8e0/0xa28
36 LR [c02101e8] check_unmap+0x8e0/0xa28
37 Call Trace:
38 [dede3c60] [c02101e8] check_unmap+0x8e0/0xa28 (unreliable)
39 [dede3cb0] [c02103b8] debug_dma_unmap_page+0x88/0x9c
40 [dede3d30] [c02dffbc] free_skb_resources+0x2c4/0x404
41 [dede3d80] [c02e39b4] gfar_close+0x24/0xc8
42 [dede3da0] [c0361550] __dev_close_many+0xa0/0xf8
43 [dede3dd0] [c03616f0] __dev_close+0x2c/0x4c
44 [dede3df0] [c036b1b8] __dev_change_flags+0xa0/0x174
45 [dede3e10] [c036b2ac] dev_change_flags+0x20/0x60
46 [dede3e30] [c03e130c] devinet_ioctl+0x540/0x824
47 [dede3e90] [c0347dcc] sock_ioctl+0x134/0x298
48 [dede3eb0] [c0111814] do_vfs_ioctl+0xac/0x854
49 [dede3f20] [c0111ffc] SyS_ioctl+0x40/0x74
50 [dede3f40] [c000f290] ret_from_syscall+0x0/0x3c
51 --- interrupt: c01 at 0xff45da0
52 LR = 0xff45cd0
53 Instruction dump:
54 811d001c 7c66482e 813d0020 9061000c 807f000c 5463103a 7cc6182e 3c60c052
55 386309ac 90c10008 4cc63182 4826b845 <0fe00000> 4bfffa60 3c80c052 388402c4
56 ---[ end trace 695ae6d7ac1d0c47 ]---
57 Mapped at:
58 [<c02e22a8>] gfar_alloc_rx_buffs+0x178/0x248
59 [<c02e3ef0>] startup_gfar+0x368/0x570
60 [<c036aeb4>] __dev_open+0xdc/0x150
61 [<c036b1b8>] __dev_change_flags+0xa0/0x174
62 [<c036b2ac>] dev_change_flags+0x20/0x60
63
64 Even though the issue was discovered in 4.9 kernel, the code in question
65 is identical in the current net and net-next trees.
66
67 Fixes: 75354148ce69 ("gianfar: Add paged allocation and Rx S/G")
68 Signed-off-by: Arseny Solokha <asolokha@kb.kras.ru>
69 Acked-by: Claudiu Manoil <claudiu.manoil@nxp.com>
70 Signed-off-by: David S. Miller <davem@davemloft.net>
71 Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
72 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
73 ---
74 drivers/net/ethernet/freescale/gianfar.c | 4 ++--
75 1 file changed, 2 insertions(+), 2 deletions(-)
76
77 --- a/drivers/net/ethernet/freescale/gianfar.c
78 +++ b/drivers/net/ethernet/freescale/gianfar.c
79 @@ -1999,8 +1999,8 @@ static void free_skb_rx_queue(struct gfa
80 if (!rxb->page)
81 continue;
82
83 - dma_unmap_single(rx_queue->dev, rxb->dma,
84 - PAGE_SIZE, DMA_FROM_DEVICE);
85 + dma_unmap_page(rx_queue->dev, rxb->dma,
86 + PAGE_SIZE, DMA_FROM_DEVICE);
87 __free_page(rxb->page);
88
89 rxb->page = NULL;