]>
Commit | Line | Data |
---|---|---|
3c47877e GKH |
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 | } |