]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Subject: Fix tx/rx_ring_count parameters for igb on suspend/resume/ring resize |
2 | Patch-mainline: 2.6.29-rc3 | |
3 | References: bnc#465049 | |
4 | From: Alexander Duyck <alexander.h.duyck@intel.com> | |
5 | ||
6 | When suspending the device the ring structure is freed which causes it to | |
7 | loose track of the count. To resolve this we need to move the ring count | |
8 | outside of the ring structure and store it in the adapter struct. | |
9 | ||
10 | In addition to resolving the suspend/resume issue this patch also addresses | |
11 | issues seen in the event of memory allocation errors causing uneven ring | |
12 | sizes on multiple queues. | |
13 | ||
14 | Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> | |
15 | Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> | |
16 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
17 | Signed-off-by: Pavel Machek <pavel@suse.cz> | |
18 | ||
19 | ||
20 | ||
21 | --- | |
22 | drivers/net/igb/igb.h | 4 + | |
23 | drivers/net/igb/igb_ethtool.c | 102 ++++++++++++++++++++---------------------- | |
24 | drivers/net/igb/igb_main.c | 10 ++-- | |
25 | 3 files changed, 59 insertions(+), 57 deletions(-) | |
26 | ||
27 | --- a/drivers/net/igb/igb_ethtool.c | |
28 | +++ b/drivers/net/igb/igb_ethtool.c | |
29 | @@ -714,15 +714,13 @@ static void igb_get_ringparam(struct net | |
30 | struct ethtool_ringparam *ring) | |
31 | { | |
32 | struct igb_adapter *adapter = netdev_priv(netdev); | |
33 | - struct igb_ring *tx_ring = adapter->tx_ring; | |
34 | - struct igb_ring *rx_ring = adapter->rx_ring; | |
35 | ||
36 | ring->rx_max_pending = IGB_MAX_RXD; | |
37 | ring->tx_max_pending = IGB_MAX_TXD; | |
38 | ring->rx_mini_max_pending = 0; | |
39 | ring->rx_jumbo_max_pending = 0; | |
40 | - ring->rx_pending = rx_ring->count; | |
41 | - ring->tx_pending = tx_ring->count; | |
42 | + ring->rx_pending = adapter->rx_ring_count; | |
43 | + ring->tx_pending = adapter->tx_ring_count; | |
44 | ring->rx_mini_pending = 0; | |
45 | ring->rx_jumbo_pending = 0; | |
46 | } | |
47 | @@ -731,12 +729,9 @@ static int igb_set_ringparam(struct net_ | |
48 | struct ethtool_ringparam *ring) | |
49 | { | |
50 | struct igb_adapter *adapter = netdev_priv(netdev); | |
51 | - struct igb_buffer *old_buf; | |
52 | - struct igb_buffer *old_rx_buf; | |
53 | - void *old_desc; | |
54 | + struct igb_ring *temp_ring; | |
55 | int i, err; | |
56 | - u32 new_rx_count, new_tx_count, old_size; | |
57 | - dma_addr_t old_dma; | |
58 | + u32 new_rx_count, new_tx_count; | |
59 | ||
60 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | |
61 | return -EINVAL; | |
62 | @@ -749,12 +744,19 @@ static int igb_set_ringparam(struct net_ | |
63 | new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); | |
64 | new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); | |
65 | ||
66 | - if ((new_tx_count == adapter->tx_ring->count) && | |
67 | - (new_rx_count == adapter->rx_ring->count)) { | |
68 | + if ((new_tx_count == adapter->tx_ring_count) && | |
69 | + (new_rx_count == adapter->rx_ring_count)) { | |
70 | /* nothing to do */ | |
71 | return 0; | |
72 | } | |
73 | ||
74 | + if (adapter->num_tx_queues > adapter->num_rx_queues) | |
75 | + temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring)); | |
76 | + else | |
77 | + temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring)); | |
78 | + if (!temp_ring) | |
79 | + return -ENOMEM; | |
80 | + | |
81 | while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) | |
82 | msleep(1); | |
83 | ||
84 | @@ -766,62 +768,55 @@ static int igb_set_ringparam(struct net_ | |
85 | * because the ISRs in MSI-X mode get passed pointers | |
86 | * to the tx and rx ring structs. | |
87 | */ | |
88 | - if (new_tx_count != adapter->tx_ring->count) { | |
89 | + if (new_tx_count != adapter->tx_ring_count) { | |
90 | + memcpy(temp_ring, adapter->tx_ring, | |
91 | + adapter->num_tx_queues * sizeof(struct igb_ring)); | |
92 | + | |
93 | for (i = 0; i < adapter->num_tx_queues; i++) { | |
94 | - /* Save existing descriptor ring */ | |
95 | - old_buf = adapter->tx_ring[i].buffer_info; | |
96 | - old_desc = adapter->tx_ring[i].desc; | |
97 | - old_size = adapter->tx_ring[i].size; | |
98 | - old_dma = adapter->tx_ring[i].dma; | |
99 | - /* Try to allocate a new one */ | |
100 | - adapter->tx_ring[i].buffer_info = NULL; | |
101 | - adapter->tx_ring[i].desc = NULL; | |
102 | - adapter->tx_ring[i].count = new_tx_count; | |
103 | - err = igb_setup_tx_resources(adapter, | |
104 | - &adapter->tx_ring[i]); | |
105 | + temp_ring[i].count = new_tx_count; | |
106 | + err = igb_setup_tx_resources(adapter, &temp_ring[i]); | |
107 | if (err) { | |
108 | - /* Restore the old one so at least | |
109 | - the adapter still works, even if | |
110 | - we failed the request */ | |
111 | - adapter->tx_ring[i].buffer_info = old_buf; | |
112 | - adapter->tx_ring[i].desc = old_desc; | |
113 | - adapter->tx_ring[i].size = old_size; | |
114 | - adapter->tx_ring[i].dma = old_dma; | |
115 | + while (i) { | |
116 | + i--; | |
117 | + igb_free_tx_resources(&temp_ring[i]); | |
118 | + } | |
119 | goto err_setup; | |
120 | } | |
121 | - /* Free the old buffer manually */ | |
122 | - vfree(old_buf); | |
123 | - pci_free_consistent(adapter->pdev, old_size, | |
124 | - old_desc, old_dma); | |
125 | } | |
126 | + | |
127 | + for (i = 0; i < adapter->num_tx_queues; i++) | |
128 | + igb_free_tx_resources(&adapter->tx_ring[i]); | |
129 | + | |
130 | + memcpy(adapter->tx_ring, temp_ring, | |
131 | + adapter->num_tx_queues * sizeof(struct igb_ring)); | |
132 | + | |
133 | + adapter->tx_ring_count = new_tx_count; | |
134 | } | |
135 | ||
136 | if (new_rx_count != adapter->rx_ring->count) { | |
137 | - for (i = 0; i < adapter->num_rx_queues; i++) { | |
138 | + memcpy(temp_ring, adapter->rx_ring, | |
139 | + adapter->num_rx_queues * sizeof(struct igb_ring)); | |
140 | ||
141 | - old_rx_buf = adapter->rx_ring[i].buffer_info; | |
142 | - old_desc = adapter->rx_ring[i].desc; | |
143 | - old_size = adapter->rx_ring[i].size; | |
144 | - old_dma = adapter->rx_ring[i].dma; | |
145 | - | |
146 | - adapter->rx_ring[i].buffer_info = NULL; | |
147 | - adapter->rx_ring[i].desc = NULL; | |
148 | - adapter->rx_ring[i].dma = 0; | |
149 | - adapter->rx_ring[i].count = new_rx_count; | |
150 | - err = igb_setup_rx_resources(adapter, | |
151 | - &adapter->rx_ring[i]); | |
152 | + for (i = 0; i < adapter->num_rx_queues; i++) { | |
153 | + temp_ring[i].count = new_rx_count; | |
154 | + err = igb_setup_rx_resources(adapter, &temp_ring[i]); | |
155 | if (err) { | |
156 | - adapter->rx_ring[i].buffer_info = old_rx_buf; | |
157 | - adapter->rx_ring[i].desc = old_desc; | |
158 | - adapter->rx_ring[i].size = old_size; | |
159 | - adapter->rx_ring[i].dma = old_dma; | |
160 | + while (i) { | |
161 | + i--; | |
162 | + igb_free_rx_resources(&temp_ring[i]); | |
163 | + } | |
164 | goto err_setup; | |
165 | } | |
166 | ||
167 | - vfree(old_rx_buf); | |
168 | - pci_free_consistent(adapter->pdev, old_size, old_desc, | |
169 | - old_dma); | |
170 | } | |
171 | + | |
172 | + for (i = 0; i < adapter->num_rx_queues; i++) | |
173 | + igb_free_rx_resources(&adapter->rx_ring[i]); | |
174 | + | |
175 | + memcpy(adapter->rx_ring, temp_ring, | |
176 | + adapter->num_rx_queues * sizeof(struct igb_ring)); | |
177 | + | |
178 | + adapter->rx_ring_count = new_rx_count; | |
179 | } | |
180 | ||
181 | err = 0; | |
182 | @@ -830,6 +825,7 @@ err_setup: | |
183 | igb_up(adapter); | |
184 | ||
185 | clear_bit(__IGB_RESETTING, &adapter->state); | |
186 | + vfree(temp_ring); | |
187 | return err; | |
188 | } | |
189 | ||
190 | --- a/drivers/net/igb/igb.h | |
191 | +++ b/drivers/net/igb/igb.h | |
192 | @@ -294,6 +294,8 @@ struct igb_adapter { | |
193 | unsigned int lro_flushed; | |
194 | unsigned int lro_no_desc; | |
195 | #endif | |
196 | + unsigned int tx_ring_count; | |
197 | + unsigned int rx_ring_count; | |
198 | }; | |
199 | ||
200 | #define IGB_FLAG_HAS_MSI (1 << 0) | |
201 | @@ -325,6 +327,8 @@ extern void igb_reset(struct igb_adapter | |
202 | extern int igb_set_spd_dplx(struct igb_adapter *, u16); | |
203 | extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *); | |
204 | extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *); | |
205 | +extern void igb_free_tx_resources(struct igb_ring *); | |
206 | +extern void igb_free_rx_resources(struct igb_ring *); | |
207 | extern void igb_update_stats(struct igb_adapter *); | |
208 | extern void igb_set_ethtool_ops(struct net_device *); | |
209 | ||
210 | --- a/drivers/net/igb/igb_main.c | |
211 | +++ b/drivers/net/igb/igb_main.c | |
212 | @@ -75,8 +75,6 @@ static int igb_setup_all_tx_resources(st | |
213 | static int igb_setup_all_rx_resources(struct igb_adapter *); | |
214 | static void igb_free_all_tx_resources(struct igb_adapter *); | |
215 | static void igb_free_all_rx_resources(struct igb_adapter *); | |
216 | -static void igb_free_tx_resources(struct igb_ring *); | |
217 | -static void igb_free_rx_resources(struct igb_ring *); | |
218 | void igb_update_stats(struct igb_adapter *); | |
219 | static int igb_probe(struct pci_dev *, const struct pci_device_id *); | |
220 | static void __devexit igb_remove(struct pci_dev *pdev); | |
221 | @@ -258,11 +256,13 @@ static int igb_alloc_queues(struct igb_a | |
222 | ||
223 | for (i = 0; i < adapter->num_tx_queues; i++) { | |
224 | struct igb_ring *ring = &(adapter->tx_ring[i]); | |
225 | + ring->count = adapter->tx_ring_count; | |
226 | ring->adapter = adapter; | |
227 | ring->queue_index = i; | |
228 | } | |
229 | for (i = 0; i < adapter->num_rx_queues; i++) { | |
230 | struct igb_ring *ring = &(adapter->rx_ring[i]); | |
231 | + ring->count = adapter->rx_ring_count; | |
232 | ring->adapter = adapter; | |
233 | ring->queue_index = i; | |
234 | ring->itr_register = E1000_ITR; | |
235 | @@ -1374,6 +1374,8 @@ static int __devinit igb_sw_init(struct | |
236 | ||
237 | pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); | |
238 | ||
239 | + adapter->tx_ring_count = IGB_DEFAULT_TXD; | |
240 | + adapter->rx_ring_count = IGB_DEFAULT_RXD; | |
241 | adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; | |
242 | adapter->rx_ps_hdr_size = 0; /* disable packet split */ | |
243 | adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; | |
244 | @@ -1962,7 +1964,7 @@ static void igb_configure_rx(struct igb_ | |
245 | * | |
246 | * Free all transmit software resources | |
247 | **/ | |
248 | -static void igb_free_tx_resources(struct igb_ring *tx_ring) | |
249 | +void igb_free_tx_resources(struct igb_ring *tx_ring) | |
250 | { | |
251 | struct pci_dev *pdev = tx_ring->adapter->pdev; | |
252 | ||
253 | @@ -2062,7 +2064,7 @@ static void igb_clean_all_tx_rings(struc | |
254 | * | |
255 | * Free all receive software resources | |
256 | **/ | |
257 | -static void igb_free_rx_resources(struct igb_ring *rx_ring) | |
258 | +void igb_free_rx_resources(struct igb_ring *rx_ring) | |
259 | { | |
260 | struct pci_dev *pdev = rx_ring->adapter->pdev; | |
261 |