diff options
Diffstat (limited to 'drivers/net/ixgb/ixgb_ethtool.c')
-rw-r--r-- | drivers/net/ixgb/ixgb_ethtool.c | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c new file mode 100644 index 000000000000..aea10e8aaa72 --- /dev/null +++ b/drivers/net/ixgb/ixgb_ethtool.c | |||
@@ -0,0 +1,704 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | |||
4 | Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms of the GNU General Public License as published by the Free | ||
8 | Software Foundation; either version 2 of the License, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along with | ||
17 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
18 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | |||
20 | The full GNU General Public License is included in this distribution in the | ||
21 | file called LICENSE. | ||
22 | |||
23 | Contact Information: | ||
24 | Linux NICS <linux.nics@intel.com> | ||
25 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
26 | |||
27 | *******************************************************************************/ | ||
28 | |||
29 | /* ethtool support for ixgb */ | ||
30 | |||
31 | #include "ixgb.h" | ||
32 | |||
33 | #include <asm/uaccess.h> | ||
34 | |||
35 | extern char ixgb_driver_name[]; | ||
36 | extern char ixgb_driver_version[]; | ||
37 | |||
38 | extern int ixgb_up(struct ixgb_adapter *adapter); | ||
39 | extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog); | ||
40 | extern void ixgb_reset(struct ixgb_adapter *adapter); | ||
41 | extern int ixgb_setup_rx_resources(struct ixgb_adapter *adapter); | ||
42 | extern int ixgb_setup_tx_resources(struct ixgb_adapter *adapter); | ||
43 | extern void ixgb_free_rx_resources(struct ixgb_adapter *adapter); | ||
44 | extern void ixgb_free_tx_resources(struct ixgb_adapter *adapter); | ||
45 | extern void ixgb_update_stats(struct ixgb_adapter *adapter); | ||
46 | |||
47 | struct ixgb_stats { | ||
48 | char stat_string[ETH_GSTRING_LEN]; | ||
49 | int sizeof_stat; | ||
50 | int stat_offset; | ||
51 | }; | ||
52 | |||
53 | #define IXGB_STAT(m) sizeof(((struct ixgb_adapter *)0)->m), \ | ||
54 | offsetof(struct ixgb_adapter, m) | ||
55 | static struct ixgb_stats ixgb_gstrings_stats[] = { | ||
56 | {"rx_packets", IXGB_STAT(net_stats.rx_packets)}, | ||
57 | {"tx_packets", IXGB_STAT(net_stats.tx_packets)}, | ||
58 | {"rx_bytes", IXGB_STAT(net_stats.rx_bytes)}, | ||
59 | {"tx_bytes", IXGB_STAT(net_stats.tx_bytes)}, | ||
60 | {"rx_errors", IXGB_STAT(net_stats.rx_errors)}, | ||
61 | {"tx_errors", IXGB_STAT(net_stats.tx_errors)}, | ||
62 | {"rx_dropped", IXGB_STAT(net_stats.rx_dropped)}, | ||
63 | {"tx_dropped", IXGB_STAT(net_stats.tx_dropped)}, | ||
64 | {"multicast", IXGB_STAT(net_stats.multicast)}, | ||
65 | {"collisions", IXGB_STAT(net_stats.collisions)}, | ||
66 | |||
67 | /* { "rx_length_errors", IXGB_STAT(net_stats.rx_length_errors) }, */ | ||
68 | {"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)}, | ||
69 | {"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)}, | ||
70 | {"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)}, | ||
71 | {"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)}, | ||
72 | {"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)}, | ||
73 | {"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)}, | ||
74 | {"tx_carrier_errors", IXGB_STAT(net_stats.tx_carrier_errors)}, | ||
75 | {"tx_fifo_errors", IXGB_STAT(net_stats.tx_fifo_errors)}, | ||
76 | {"tx_heartbeat_errors", IXGB_STAT(net_stats.tx_heartbeat_errors)}, | ||
77 | {"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)}, | ||
78 | {"tx_deferred_ok", IXGB_STAT(stats.dc)}, | ||
79 | {"rx_long_length_errors", IXGB_STAT(stats.roc)}, | ||
80 | {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, | ||
81 | #ifdef NETIF_F_TSO | ||
82 | {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)}, | ||
83 | {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)}, | ||
84 | #endif | ||
85 | {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)}, | ||
86 | {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)}, | ||
87 | {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)}, | ||
88 | {"tx_flow_control_xoff", IXGB_STAT(stats.xofftxc)}, | ||
89 | {"rx_csum_offload_good", IXGB_STAT(hw_csum_rx_good)}, | ||
90 | {"rx_csum_offload_errors", IXGB_STAT(hw_csum_rx_error)}, | ||
91 | {"tx_csum_offload_good", IXGB_STAT(hw_csum_tx_good)}, | ||
92 | {"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)} | ||
93 | }; | ||
94 | |||
95 | #define IXGB_STATS_LEN \ | ||
96 | sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats) | ||
97 | |||
98 | static int | ||
99 | ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | ||
100 | { | ||
101 | struct ixgb_adapter *adapter = netdev->priv; | ||
102 | |||
103 | ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); | ||
104 | ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); | ||
105 | ecmd->port = PORT_FIBRE; | ||
106 | ecmd->transceiver = XCVR_EXTERNAL; | ||
107 | |||
108 | if(netif_carrier_ok(adapter->netdev)) { | ||
109 | ecmd->speed = SPEED_10000; | ||
110 | ecmd->duplex = DUPLEX_FULL; | ||
111 | } else { | ||
112 | ecmd->speed = -1; | ||
113 | ecmd->duplex = -1; | ||
114 | } | ||
115 | |||
116 | ecmd->autoneg = AUTONEG_DISABLE; | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | ||
122 | { | ||
123 | struct ixgb_adapter *adapter = netdev->priv; | ||
124 | |||
125 | if(ecmd->autoneg == AUTONEG_ENABLE || | ||
126 | ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) | ||
127 | return -EINVAL; | ||
128 | |||
129 | if(netif_running(adapter->netdev)) { | ||
130 | ixgb_down(adapter, TRUE); | ||
131 | ixgb_reset(adapter); | ||
132 | ixgb_up(adapter); | ||
133 | } else | ||
134 | ixgb_reset(adapter); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | ixgb_get_pauseparam(struct net_device *netdev, | ||
141 | struct ethtool_pauseparam *pause) | ||
142 | { | ||
143 | struct ixgb_adapter *adapter = netdev->priv; | ||
144 | struct ixgb_hw *hw = &adapter->hw; | ||
145 | |||
146 | pause->autoneg = AUTONEG_DISABLE; | ||
147 | |||
148 | if(hw->fc.type == ixgb_fc_rx_pause) | ||
149 | pause->rx_pause = 1; | ||
150 | else if(hw->fc.type == ixgb_fc_tx_pause) | ||
151 | pause->tx_pause = 1; | ||
152 | else if(hw->fc.type == ixgb_fc_full) { | ||
153 | pause->rx_pause = 1; | ||
154 | pause->tx_pause = 1; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | static int | ||
159 | ixgb_set_pauseparam(struct net_device *netdev, | ||
160 | struct ethtool_pauseparam *pause) | ||
161 | { | ||
162 | struct ixgb_adapter *adapter = netdev->priv; | ||
163 | struct ixgb_hw *hw = &adapter->hw; | ||
164 | |||
165 | if(pause->autoneg == AUTONEG_ENABLE) | ||
166 | return -EINVAL; | ||
167 | |||
168 | if(pause->rx_pause && pause->tx_pause) | ||
169 | hw->fc.type = ixgb_fc_full; | ||
170 | else if(pause->rx_pause && !pause->tx_pause) | ||
171 | hw->fc.type = ixgb_fc_rx_pause; | ||
172 | else if(!pause->rx_pause && pause->tx_pause) | ||
173 | hw->fc.type = ixgb_fc_tx_pause; | ||
174 | else if(!pause->rx_pause && !pause->tx_pause) | ||
175 | hw->fc.type = ixgb_fc_none; | ||
176 | |||
177 | if(netif_running(adapter->netdev)) { | ||
178 | ixgb_down(adapter, TRUE); | ||
179 | ixgb_up(adapter); | ||
180 | } else | ||
181 | ixgb_reset(adapter); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static uint32_t | ||
187 | ixgb_get_rx_csum(struct net_device *netdev) | ||
188 | { | ||
189 | struct ixgb_adapter *adapter = netdev->priv; | ||
190 | return adapter->rx_csum; | ||
191 | } | ||
192 | |||
193 | static int | ||
194 | ixgb_set_rx_csum(struct net_device *netdev, uint32_t data) | ||
195 | { | ||
196 | struct ixgb_adapter *adapter = netdev->priv; | ||
197 | adapter->rx_csum = data; | ||
198 | |||
199 | if(netif_running(netdev)) { | ||
200 | ixgb_down(adapter,TRUE); | ||
201 | ixgb_up(adapter); | ||
202 | } else | ||
203 | ixgb_reset(adapter); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static uint32_t | ||
208 | ixgb_get_tx_csum(struct net_device *netdev) | ||
209 | { | ||
210 | return (netdev->features & NETIF_F_HW_CSUM) != 0; | ||
211 | } | ||
212 | |||
213 | static int | ||
214 | ixgb_set_tx_csum(struct net_device *netdev, uint32_t data) | ||
215 | { | ||
216 | if (data) | ||
217 | netdev->features |= NETIF_F_HW_CSUM; | ||
218 | else | ||
219 | netdev->features &= ~NETIF_F_HW_CSUM; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | #ifdef NETIF_F_TSO | ||
225 | static int | ||
226 | ixgb_set_tso(struct net_device *netdev, uint32_t data) | ||
227 | { | ||
228 | if(data) | ||
229 | netdev->features |= NETIF_F_TSO; | ||
230 | else | ||
231 | netdev->features &= ~NETIF_F_TSO; | ||
232 | return 0; | ||
233 | } | ||
234 | #endif /* NETIF_F_TSO */ | ||
235 | |||
236 | #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_ | ||
237 | |||
238 | static int | ||
239 | ixgb_get_regs_len(struct net_device *netdev) | ||
240 | { | ||
241 | #define IXGB_REG_DUMP_LEN 136*sizeof(uint32_t) | ||
242 | return IXGB_REG_DUMP_LEN; | ||
243 | } | ||
244 | |||
245 | static void | ||
246 | ixgb_get_regs(struct net_device *netdev, | ||
247 | struct ethtool_regs *regs, void *p) | ||
248 | { | ||
249 | struct ixgb_adapter *adapter = netdev->priv; | ||
250 | struct ixgb_hw *hw = &adapter->hw; | ||
251 | uint32_t *reg = p; | ||
252 | uint32_t *reg_start = reg; | ||
253 | uint8_t i; | ||
254 | |||
255 | regs->version = (adapter->hw.device_id << 16) | adapter->hw.subsystem_id; | ||
256 | |||
257 | /* General Registers */ | ||
258 | *reg++ = IXGB_READ_REG(hw, CTRL0); /* 0 */ | ||
259 | *reg++ = IXGB_READ_REG(hw, CTRL1); /* 1 */ | ||
260 | *reg++ = IXGB_READ_REG(hw, STATUS); /* 2 */ | ||
261 | *reg++ = IXGB_READ_REG(hw, EECD); /* 3 */ | ||
262 | *reg++ = IXGB_READ_REG(hw, MFS); /* 4 */ | ||
263 | |||
264 | /* Interrupt */ | ||
265 | *reg++ = IXGB_READ_REG(hw, ICR); /* 5 */ | ||
266 | *reg++ = IXGB_READ_REG(hw, ICS); /* 6 */ | ||
267 | *reg++ = IXGB_READ_REG(hw, IMS); /* 7 */ | ||
268 | *reg++ = IXGB_READ_REG(hw, IMC); /* 8 */ | ||
269 | |||
270 | /* Receive */ | ||
271 | *reg++ = IXGB_READ_REG(hw, RCTL); /* 9 */ | ||
272 | *reg++ = IXGB_READ_REG(hw, FCRTL); /* 10 */ | ||
273 | *reg++ = IXGB_READ_REG(hw, FCRTH); /* 11 */ | ||
274 | *reg++ = IXGB_READ_REG(hw, RDBAL); /* 12 */ | ||
275 | *reg++ = IXGB_READ_REG(hw, RDBAH); /* 13 */ | ||
276 | *reg++ = IXGB_READ_REG(hw, RDLEN); /* 14 */ | ||
277 | *reg++ = IXGB_READ_REG(hw, RDH); /* 15 */ | ||
278 | *reg++ = IXGB_READ_REG(hw, RDT); /* 16 */ | ||
279 | *reg++ = IXGB_READ_REG(hw, RDTR); /* 17 */ | ||
280 | *reg++ = IXGB_READ_REG(hw, RXDCTL); /* 18 */ | ||
281 | *reg++ = IXGB_READ_REG(hw, RAIDC); /* 19 */ | ||
282 | *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ | ||
283 | |||
284 | for (i = 0; i < IXGB_RAR_ENTRIES; i++) { | ||
285 | *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ | ||
286 | *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ | ||
287 | } | ||
288 | |||
289 | /* Transmit */ | ||
290 | *reg++ = IXGB_READ_REG(hw, TCTL); /* 53 */ | ||
291 | *reg++ = IXGB_READ_REG(hw, TDBAL); /* 54 */ | ||
292 | *reg++ = IXGB_READ_REG(hw, TDBAH); /* 55 */ | ||
293 | *reg++ = IXGB_READ_REG(hw, TDLEN); /* 56 */ | ||
294 | *reg++ = IXGB_READ_REG(hw, TDH); /* 57 */ | ||
295 | *reg++ = IXGB_READ_REG(hw, TDT); /* 58 */ | ||
296 | *reg++ = IXGB_READ_REG(hw, TIDV); /* 59 */ | ||
297 | *reg++ = IXGB_READ_REG(hw, TXDCTL); /* 60 */ | ||
298 | *reg++ = IXGB_READ_REG(hw, TSPMT); /* 61 */ | ||
299 | *reg++ = IXGB_READ_REG(hw, PAP); /* 62 */ | ||
300 | |||
301 | /* Physical */ | ||
302 | *reg++ = IXGB_READ_REG(hw, PCSC1); /* 63 */ | ||
303 | *reg++ = IXGB_READ_REG(hw, PCSC2); /* 64 */ | ||
304 | *reg++ = IXGB_READ_REG(hw, PCSS1); /* 65 */ | ||
305 | *reg++ = IXGB_READ_REG(hw, PCSS2); /* 66 */ | ||
306 | *reg++ = IXGB_READ_REG(hw, XPCSS); /* 67 */ | ||
307 | *reg++ = IXGB_READ_REG(hw, UCCR); /* 68 */ | ||
308 | *reg++ = IXGB_READ_REG(hw, XPCSTC); /* 69 */ | ||
309 | *reg++ = IXGB_READ_REG(hw, MACA); /* 70 */ | ||
310 | *reg++ = IXGB_READ_REG(hw, APAE); /* 71 */ | ||
311 | *reg++ = IXGB_READ_REG(hw, ARD); /* 72 */ | ||
312 | *reg++ = IXGB_READ_REG(hw, AIS); /* 73 */ | ||
313 | *reg++ = IXGB_READ_REG(hw, MSCA); /* 74 */ | ||
314 | *reg++ = IXGB_READ_REG(hw, MSRWD); /* 75 */ | ||
315 | |||
316 | /* Statistics */ | ||
317 | *reg++ = IXGB_GET_STAT(adapter, tprl); /* 76 */ | ||
318 | *reg++ = IXGB_GET_STAT(adapter, tprh); /* 77 */ | ||
319 | *reg++ = IXGB_GET_STAT(adapter, gprcl); /* 78 */ | ||
320 | *reg++ = IXGB_GET_STAT(adapter, gprch); /* 79 */ | ||
321 | *reg++ = IXGB_GET_STAT(adapter, bprcl); /* 80 */ | ||
322 | *reg++ = IXGB_GET_STAT(adapter, bprch); /* 81 */ | ||
323 | *reg++ = IXGB_GET_STAT(adapter, mprcl); /* 82 */ | ||
324 | *reg++ = IXGB_GET_STAT(adapter, mprch); /* 83 */ | ||
325 | *reg++ = IXGB_GET_STAT(adapter, uprcl); /* 84 */ | ||
326 | *reg++ = IXGB_GET_STAT(adapter, uprch); /* 85 */ | ||
327 | *reg++ = IXGB_GET_STAT(adapter, vprcl); /* 86 */ | ||
328 | *reg++ = IXGB_GET_STAT(adapter, vprch); /* 87 */ | ||
329 | *reg++ = IXGB_GET_STAT(adapter, jprcl); /* 88 */ | ||
330 | *reg++ = IXGB_GET_STAT(adapter, jprch); /* 89 */ | ||
331 | *reg++ = IXGB_GET_STAT(adapter, gorcl); /* 90 */ | ||
332 | *reg++ = IXGB_GET_STAT(adapter, gorch); /* 91 */ | ||
333 | *reg++ = IXGB_GET_STAT(adapter, torl); /* 92 */ | ||
334 | *reg++ = IXGB_GET_STAT(adapter, torh); /* 93 */ | ||
335 | *reg++ = IXGB_GET_STAT(adapter, rnbc); /* 94 */ | ||
336 | *reg++ = IXGB_GET_STAT(adapter, ruc); /* 95 */ | ||
337 | *reg++ = IXGB_GET_STAT(adapter, roc); /* 96 */ | ||
338 | *reg++ = IXGB_GET_STAT(adapter, rlec); /* 97 */ | ||
339 | *reg++ = IXGB_GET_STAT(adapter, crcerrs); /* 98 */ | ||
340 | *reg++ = IXGB_GET_STAT(adapter, icbc); /* 99 */ | ||
341 | *reg++ = IXGB_GET_STAT(adapter, ecbc); /* 100 */ | ||
342 | *reg++ = IXGB_GET_STAT(adapter, mpc); /* 101 */ | ||
343 | *reg++ = IXGB_GET_STAT(adapter, tptl); /* 102 */ | ||
344 | *reg++ = IXGB_GET_STAT(adapter, tpth); /* 103 */ | ||
345 | *reg++ = IXGB_GET_STAT(adapter, gptcl); /* 104 */ | ||
346 | *reg++ = IXGB_GET_STAT(adapter, gptch); /* 105 */ | ||
347 | *reg++ = IXGB_GET_STAT(adapter, bptcl); /* 106 */ | ||
348 | *reg++ = IXGB_GET_STAT(adapter, bptch); /* 107 */ | ||
349 | *reg++ = IXGB_GET_STAT(adapter, mptcl); /* 108 */ | ||
350 | *reg++ = IXGB_GET_STAT(adapter, mptch); /* 109 */ | ||
351 | *reg++ = IXGB_GET_STAT(adapter, uptcl); /* 110 */ | ||
352 | *reg++ = IXGB_GET_STAT(adapter, uptch); /* 111 */ | ||
353 | *reg++ = IXGB_GET_STAT(adapter, vptcl); /* 112 */ | ||
354 | *reg++ = IXGB_GET_STAT(adapter, vptch); /* 113 */ | ||
355 | *reg++ = IXGB_GET_STAT(adapter, jptcl); /* 114 */ | ||
356 | *reg++ = IXGB_GET_STAT(adapter, jptch); /* 115 */ | ||
357 | *reg++ = IXGB_GET_STAT(adapter, gotcl); /* 116 */ | ||
358 | *reg++ = IXGB_GET_STAT(adapter, gotch); /* 117 */ | ||
359 | *reg++ = IXGB_GET_STAT(adapter, totl); /* 118 */ | ||
360 | *reg++ = IXGB_GET_STAT(adapter, toth); /* 119 */ | ||
361 | *reg++ = IXGB_GET_STAT(adapter, dc); /* 120 */ | ||
362 | *reg++ = IXGB_GET_STAT(adapter, plt64c); /* 121 */ | ||
363 | *reg++ = IXGB_GET_STAT(adapter, tsctc); /* 122 */ | ||
364 | *reg++ = IXGB_GET_STAT(adapter, tsctfc); /* 123 */ | ||
365 | *reg++ = IXGB_GET_STAT(adapter, ibic); /* 124 */ | ||
366 | *reg++ = IXGB_GET_STAT(adapter, rfc); /* 125 */ | ||
367 | *reg++ = IXGB_GET_STAT(adapter, lfc); /* 126 */ | ||
368 | *reg++ = IXGB_GET_STAT(adapter, pfrc); /* 127 */ | ||
369 | *reg++ = IXGB_GET_STAT(adapter, pftc); /* 128 */ | ||
370 | *reg++ = IXGB_GET_STAT(adapter, mcfrc); /* 129 */ | ||
371 | *reg++ = IXGB_GET_STAT(adapter, mcftc); /* 130 */ | ||
372 | *reg++ = IXGB_GET_STAT(adapter, xonrxc); /* 131 */ | ||
373 | *reg++ = IXGB_GET_STAT(adapter, xontxc); /* 132 */ | ||
374 | *reg++ = IXGB_GET_STAT(adapter, xoffrxc); /* 133 */ | ||
375 | *reg++ = IXGB_GET_STAT(adapter, xofftxc); /* 134 */ | ||
376 | *reg++ = IXGB_GET_STAT(adapter, rjc); /* 135 */ | ||
377 | |||
378 | regs->len = (reg - reg_start) * sizeof(uint32_t); | ||
379 | } | ||
380 | |||
381 | static int | ||
382 | ixgb_get_eeprom_len(struct net_device *netdev) | ||
383 | { | ||
384 | /* return size in bytes */ | ||
385 | return (IXGB_EEPROM_SIZE << 1); | ||
386 | } | ||
387 | |||
388 | static int | ||
389 | ixgb_get_eeprom(struct net_device *netdev, | ||
390 | struct ethtool_eeprom *eeprom, uint8_t *bytes) | ||
391 | { | ||
392 | struct ixgb_adapter *adapter = netdev->priv; | ||
393 | struct ixgb_hw *hw = &adapter->hw; | ||
394 | uint16_t *eeprom_buff; | ||
395 | int i, max_len, first_word, last_word; | ||
396 | int ret_val = 0; | ||
397 | |||
398 | if(eeprom->len == 0) { | ||
399 | ret_val = -EINVAL; | ||
400 | goto geeprom_error; | ||
401 | } | ||
402 | |||
403 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); | ||
404 | |||
405 | max_len = ixgb_get_eeprom_len(netdev); | ||
406 | |||
407 | if(eeprom->offset > eeprom->offset + eeprom->len) { | ||
408 | ret_val = -EINVAL; | ||
409 | goto geeprom_error; | ||
410 | } | ||
411 | |||
412 | if((eeprom->offset + eeprom->len) > max_len) | ||
413 | eeprom->len = (max_len - eeprom->offset); | ||
414 | |||
415 | first_word = eeprom->offset >> 1; | ||
416 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | ||
417 | |||
418 | eeprom_buff = kmalloc(sizeof(uint16_t) * | ||
419 | (last_word - first_word + 1), GFP_KERNEL); | ||
420 | if(!eeprom_buff) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | /* note the eeprom was good because the driver loaded */ | ||
424 | for(i = 0; i <= (last_word - first_word); i++) { | ||
425 | eeprom_buff[i] = ixgb_get_eeprom_word(hw, (first_word + i)); | ||
426 | } | ||
427 | |||
428 | memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1), | ||
429 | eeprom->len); | ||
430 | kfree(eeprom_buff); | ||
431 | |||
432 | geeprom_error: | ||
433 | return ret_val; | ||
434 | } | ||
435 | |||
436 | static int | ||
437 | ixgb_set_eeprom(struct net_device *netdev, | ||
438 | struct ethtool_eeprom *eeprom, uint8_t *bytes) | ||
439 | { | ||
440 | struct ixgb_adapter *adapter = netdev->priv; | ||
441 | struct ixgb_hw *hw = &adapter->hw; | ||
442 | uint16_t *eeprom_buff; | ||
443 | void *ptr; | ||
444 | int max_len, first_word, last_word; | ||
445 | uint16_t i; | ||
446 | |||
447 | if(eeprom->len == 0) | ||
448 | return -EINVAL; | ||
449 | |||
450 | if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) | ||
451 | return -EFAULT; | ||
452 | |||
453 | max_len = ixgb_get_eeprom_len(netdev); | ||
454 | |||
455 | if(eeprom->offset > eeprom->offset + eeprom->len) | ||
456 | return -EINVAL; | ||
457 | |||
458 | if((eeprom->offset + eeprom->len) > max_len) | ||
459 | eeprom->len = (max_len - eeprom->offset); | ||
460 | |||
461 | first_word = eeprom->offset >> 1; | ||
462 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | ||
463 | eeprom_buff = kmalloc(max_len, GFP_KERNEL); | ||
464 | if(!eeprom_buff) | ||
465 | return -ENOMEM; | ||
466 | |||
467 | ptr = (void *)eeprom_buff; | ||
468 | |||
469 | if(eeprom->offset & 1) { | ||
470 | /* need read/modify/write of first changed EEPROM word */ | ||
471 | /* only the second byte of the word is being modified */ | ||
472 | eeprom_buff[0] = ixgb_read_eeprom(hw, first_word); | ||
473 | ptr++; | ||
474 | } | ||
475 | if((eeprom->offset + eeprom->len) & 1) { | ||
476 | /* need read/modify/write of last changed EEPROM word */ | ||
477 | /* only the first byte of the word is being modified */ | ||
478 | eeprom_buff[last_word - first_word] | ||
479 | = ixgb_read_eeprom(hw, last_word); | ||
480 | } | ||
481 | |||
482 | memcpy(ptr, bytes, eeprom->len); | ||
483 | for(i = 0; i <= (last_word - first_word); i++) | ||
484 | ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]); | ||
485 | |||
486 | /* Update the checksum over the first part of the EEPROM if needed */ | ||
487 | if(first_word <= EEPROM_CHECKSUM_REG) | ||
488 | ixgb_update_eeprom_checksum(hw); | ||
489 | |||
490 | kfree(eeprom_buff); | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | ixgb_get_drvinfo(struct net_device *netdev, | ||
496 | struct ethtool_drvinfo *drvinfo) | ||
497 | { | ||
498 | struct ixgb_adapter *adapter = netdev->priv; | ||
499 | |||
500 | strncpy(drvinfo->driver, ixgb_driver_name, 32); | ||
501 | strncpy(drvinfo->version, ixgb_driver_version, 32); | ||
502 | strncpy(drvinfo->fw_version, "N/A", 32); | ||
503 | strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); | ||
504 | drvinfo->n_stats = IXGB_STATS_LEN; | ||
505 | drvinfo->regdump_len = ixgb_get_regs_len(netdev); | ||
506 | drvinfo->eedump_len = ixgb_get_eeprom_len(netdev); | ||
507 | } | ||
508 | |||
509 | static void | ||
510 | ixgb_get_ringparam(struct net_device *netdev, | ||
511 | struct ethtool_ringparam *ring) | ||
512 | { | ||
513 | struct ixgb_adapter *adapter = netdev->priv; | ||
514 | struct ixgb_desc_ring *txdr = &adapter->tx_ring; | ||
515 | struct ixgb_desc_ring *rxdr = &adapter->rx_ring; | ||
516 | |||
517 | ring->rx_max_pending = MAX_RXD; | ||
518 | ring->tx_max_pending = MAX_TXD; | ||
519 | ring->rx_mini_max_pending = 0; | ||
520 | ring->rx_jumbo_max_pending = 0; | ||
521 | ring->rx_pending = rxdr->count; | ||
522 | ring->tx_pending = txdr->count; | ||
523 | ring->rx_mini_pending = 0; | ||
524 | ring->rx_jumbo_pending = 0; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | ixgb_set_ringparam(struct net_device *netdev, | ||
529 | struct ethtool_ringparam *ring) | ||
530 | { | ||
531 | struct ixgb_adapter *adapter = netdev->priv; | ||
532 | struct ixgb_desc_ring *txdr = &adapter->tx_ring; | ||
533 | struct ixgb_desc_ring *rxdr = &adapter->rx_ring; | ||
534 | struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new; | ||
535 | int err; | ||
536 | |||
537 | tx_old = adapter->tx_ring; | ||
538 | rx_old = adapter->rx_ring; | ||
539 | |||
540 | if((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | ||
541 | return -EINVAL; | ||
542 | |||
543 | if(netif_running(adapter->netdev)) | ||
544 | ixgb_down(adapter,TRUE); | ||
545 | |||
546 | rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD); | ||
547 | rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD); | ||
548 | IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); | ||
549 | |||
550 | txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD); | ||
551 | txdr->count = min(txdr->count,(uint32_t)MAX_TXD); | ||
552 | IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); | ||
553 | |||
554 | if(netif_running(adapter->netdev)) { | ||
555 | /* Try to get new resources before deleting old */ | ||
556 | if((err = ixgb_setup_rx_resources(adapter))) | ||
557 | goto err_setup_rx; | ||
558 | if((err = ixgb_setup_tx_resources(adapter))) | ||
559 | goto err_setup_tx; | ||
560 | |||
561 | /* save the new, restore the old in order to free it, | ||
562 | * then restore the new back again */ | ||
563 | |||
564 | rx_new = adapter->rx_ring; | ||
565 | tx_new = adapter->tx_ring; | ||
566 | adapter->rx_ring = rx_old; | ||
567 | adapter->tx_ring = tx_old; | ||
568 | ixgb_free_rx_resources(adapter); | ||
569 | ixgb_free_tx_resources(adapter); | ||
570 | adapter->rx_ring = rx_new; | ||
571 | adapter->tx_ring = tx_new; | ||
572 | if((err = ixgb_up(adapter))) | ||
573 | return err; | ||
574 | } | ||
575 | |||
576 | return 0; | ||
577 | err_setup_tx: | ||
578 | ixgb_free_rx_resources(adapter); | ||
579 | err_setup_rx: | ||
580 | adapter->rx_ring = rx_old; | ||
581 | adapter->tx_ring = tx_old; | ||
582 | ixgb_up(adapter); | ||
583 | return err; | ||
584 | } | ||
585 | |||
586 | /* toggle LED 4 times per second = 2 "blinks" per second */ | ||
587 | #define IXGB_ID_INTERVAL (HZ/4) | ||
588 | |||
589 | /* bit defines for adapter->led_status */ | ||
590 | #define IXGB_LED_ON 0 | ||
591 | |||
592 | static void | ||
593 | ixgb_led_blink_callback(unsigned long data) | ||
594 | { | ||
595 | struct ixgb_adapter *adapter = (struct ixgb_adapter *)data; | ||
596 | |||
597 | if(test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) | ||
598 | ixgb_led_off(&adapter->hw); | ||
599 | else | ||
600 | ixgb_led_on(&adapter->hw); | ||
601 | |||
602 | mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL); | ||
603 | } | ||
604 | |||
605 | static int | ||
606 | ixgb_phys_id(struct net_device *netdev, uint32_t data) | ||
607 | { | ||
608 | struct ixgb_adapter *adapter = netdev->priv; | ||
609 | |||
610 | if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) | ||
611 | data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); | ||
612 | |||
613 | if(!adapter->blink_timer.function) { | ||
614 | init_timer(&adapter->blink_timer); | ||
615 | adapter->blink_timer.function = ixgb_led_blink_callback; | ||
616 | adapter->blink_timer.data = (unsigned long)adapter; | ||
617 | } | ||
618 | |||
619 | mod_timer(&adapter->blink_timer, jiffies); | ||
620 | |||
621 | set_current_state(TASK_INTERRUPTIBLE); | ||
622 | if(data) | ||
623 | schedule_timeout(data * HZ); | ||
624 | else | ||
625 | schedule_timeout(MAX_SCHEDULE_TIMEOUT); | ||
626 | |||
627 | del_timer_sync(&adapter->blink_timer); | ||
628 | ixgb_led_off(&adapter->hw); | ||
629 | clear_bit(IXGB_LED_ON, &adapter->led_status); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int | ||
635 | ixgb_get_stats_count(struct net_device *netdev) | ||
636 | { | ||
637 | return IXGB_STATS_LEN; | ||
638 | } | ||
639 | |||
640 | static void | ||
641 | ixgb_get_ethtool_stats(struct net_device *netdev, | ||
642 | struct ethtool_stats *stats, uint64_t *data) | ||
643 | { | ||
644 | struct ixgb_adapter *adapter = netdev->priv; | ||
645 | int i; | ||
646 | |||
647 | ixgb_update_stats(adapter); | ||
648 | for(i = 0; i < IXGB_STATS_LEN; i++) { | ||
649 | char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset; | ||
650 | data[i] = (ixgb_gstrings_stats[i].sizeof_stat == | ||
651 | sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | static void | ||
656 | ixgb_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) | ||
657 | { | ||
658 | int i; | ||
659 | |||
660 | switch(stringset) { | ||
661 | case ETH_SS_STATS: | ||
662 | for(i=0; i < IXGB_STATS_LEN; i++) { | ||
663 | memcpy(data + i * ETH_GSTRING_LEN, | ||
664 | ixgb_gstrings_stats[i].stat_string, | ||
665 | ETH_GSTRING_LEN); | ||
666 | } | ||
667 | break; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | struct ethtool_ops ixgb_ethtool_ops = { | ||
672 | .get_settings = ixgb_get_settings, | ||
673 | .set_settings = ixgb_set_settings, | ||
674 | .get_drvinfo = ixgb_get_drvinfo, | ||
675 | .get_regs_len = ixgb_get_regs_len, | ||
676 | .get_regs = ixgb_get_regs, | ||
677 | .get_link = ethtool_op_get_link, | ||
678 | .get_eeprom_len = ixgb_get_eeprom_len, | ||
679 | .get_eeprom = ixgb_get_eeprom, | ||
680 | .set_eeprom = ixgb_set_eeprom, | ||
681 | .get_ringparam = ixgb_get_ringparam, | ||
682 | .set_ringparam = ixgb_set_ringparam, | ||
683 | .get_pauseparam = ixgb_get_pauseparam, | ||
684 | .set_pauseparam = ixgb_set_pauseparam, | ||
685 | .get_rx_csum = ixgb_get_rx_csum, | ||
686 | .set_rx_csum = ixgb_set_rx_csum, | ||
687 | .get_tx_csum = ixgb_get_tx_csum, | ||
688 | .set_tx_csum = ixgb_set_tx_csum, | ||
689 | .get_sg = ethtool_op_get_sg, | ||
690 | .set_sg = ethtool_op_set_sg, | ||
691 | #ifdef NETIF_F_TSO | ||
692 | .get_tso = ethtool_op_get_tso, | ||
693 | .set_tso = ixgb_set_tso, | ||
694 | #endif | ||
695 | .get_strings = ixgb_get_strings, | ||
696 | .phys_id = ixgb_phys_id, | ||
697 | .get_stats_count = ixgb_get_stats_count, | ||
698 | .get_ethtool_stats = ixgb_get_ethtool_stats, | ||
699 | }; | ||
700 | |||
701 | void ixgb_set_ethtool_ops(struct net_device *netdev) | ||
702 | { | ||
703 | SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops); | ||
704 | } | ||