]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.20/lan743x-fix-rx-kernel-panic.patch
1bdcf9c5bc99c691206b606b9d63d4e6af6bd774
[thirdparty/kernel/stable-queue.git] / queue-4.20 / lan743x-fix-rx-kernel-panic.patch
1 From foo@baz Thu Mar 14 23:20:15 PDT 2019
2 From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
3 Date: Mon, 11 Mar 2019 13:39:39 -0400
4 Subject: lan743x: Fix RX Kernel Panic
5
6 From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
7
8 [ Upstream commit dd9d9f5907bb475f8b1796c47d4ecc7fb9b72136 ]
9
10 It has been noticed that running the speed test at
11 www.speedtest.net occasionally causes a kernel panic.
12
13 Investigation revealed that under this test RX buffer allocation
14 sometimes fails and returns NULL. But the lan743x driver did
15 not handle this case.
16
17 This patch fixes this issue by attempting to allocate a buffer
18 before sending the new rx packet to the OS. If the allocation
19 fails then the new rx packet is dropped and the existing buffer
20 is reused in the DMA ring.
21
22 Updates for v2:
23 Additional 2 locations where allocation was not checked,
24 has been changed to reuse existing buffer.
25
26 Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver")
27 Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
28 Signed-off-by: David S. Miller <davem@davemloft.net>
29 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30 ---
31 drivers/net/ethernet/microchip/lan743x_main.c | 46 ++++++++++++++++++--------
32 1 file changed, 32 insertions(+), 14 deletions(-)
33
34 --- a/drivers/net/ethernet/microchip/lan743x_main.c
35 +++ b/drivers/net/ethernet/microchip/lan743x_main.c
36 @@ -1902,7 +1902,17 @@ static int lan743x_rx_next_index(struct
37 return ((++index) % rx->ring_size);
38 }
39
40 -static int lan743x_rx_allocate_ring_element(struct lan743x_rx *rx, int index)
41 +static struct sk_buff *lan743x_rx_allocate_skb(struct lan743x_rx *rx)
42 +{
43 + int length = 0;
44 +
45 + length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING);
46 + return __netdev_alloc_skb(rx->adapter->netdev,
47 + length, GFP_ATOMIC | GFP_DMA);
48 +}
49 +
50 +static int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index,
51 + struct sk_buff *skb)
52 {
53 struct lan743x_rx_buffer_info *buffer_info;
54 struct lan743x_rx_descriptor *descriptor;
55 @@ -1911,9 +1921,7 @@ static int lan743x_rx_allocate_ring_elem
56 length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING);
57 descriptor = &rx->ring_cpu_ptr[index];
58 buffer_info = &rx->buffer_info[index];
59 - buffer_info->skb = __netdev_alloc_skb(rx->adapter->netdev,
60 - length,
61 - GFP_ATOMIC | GFP_DMA);
62 + buffer_info->skb = skb;
63 if (!(buffer_info->skb))
64 return -ENOMEM;
65 buffer_info->dma_ptr = dma_map_single(&rx->adapter->pdev->dev,
66 @@ -2060,8 +2068,19 @@ static int lan743x_rx_process_packet(str
67 /* packet is available */
68 if (first_index == last_index) {
69 /* single buffer packet */
70 + struct sk_buff *new_skb = NULL;
71 int packet_length;
72
73 + new_skb = lan743x_rx_allocate_skb(rx);
74 + if (!new_skb) {
75 + /* failed to allocate next skb.
76 + * Memory is very low.
77 + * Drop this packet and reuse buffer.
78 + */
79 + lan743x_rx_reuse_ring_element(rx, first_index);
80 + goto process_extension;
81 + }
82 +
83 buffer_info = &rx->buffer_info[first_index];
84 skb = buffer_info->skb;
85 descriptor = &rx->ring_cpu_ptr[first_index];
86 @@ -2081,7 +2100,7 @@ static int lan743x_rx_process_packet(str
87 skb_put(skb, packet_length - 4);
88 skb->protocol = eth_type_trans(skb,
89 rx->adapter->netdev);
90 - lan743x_rx_allocate_ring_element(rx, first_index);
91 + lan743x_rx_init_ring_element(rx, first_index, new_skb);
92 } else {
93 int index = first_index;
94
95 @@ -2094,26 +2113,23 @@ static int lan743x_rx_process_packet(str
96 if (first_index <= last_index) {
97 while ((index >= first_index) &&
98 (index <= last_index)) {
99 - lan743x_rx_release_ring_element(rx,
100 - index);
101 - lan743x_rx_allocate_ring_element(rx,
102 - index);
103 + lan743x_rx_reuse_ring_element(rx,
104 + index);
105 index = lan743x_rx_next_index(rx,
106 index);
107 }
108 } else {
109 while ((index >= first_index) ||
110 (index <= last_index)) {
111 - lan743x_rx_release_ring_element(rx,
112 - index);
113 - lan743x_rx_allocate_ring_element(rx,
114 - index);
115 + lan743x_rx_reuse_ring_element(rx,
116 + index);
117 index = lan743x_rx_next_index(rx,
118 index);
119 }
120 }
121 }
122
123 +process_extension:
124 if (extension_index >= 0) {
125 descriptor = &rx->ring_cpu_ptr[extension_index];
126 buffer_info = &rx->buffer_info[extension_index];
127 @@ -2290,7 +2306,9 @@ static int lan743x_rx_ring_init(struct l
128
129 rx->last_head = 0;
130 for (index = 0; index < rx->ring_size; index++) {
131 - ret = lan743x_rx_allocate_ring_element(rx, index);
132 + struct sk_buff *new_skb = lan743x_rx_allocate_skb(rx);
133 +
134 + ret = lan743x_rx_init_ring_element(rx, index, new_skb);
135 if (ret)
136 goto cleanup;
137 }