]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /******************************************************************************* |
2 | ||
0abb6eb1 | 3 | Intel PRO/10GbE Linux driver |
f731a9ef | 4 | Copyright(c) 1999 - 2008 Intel Corporation. |
0abb6eb1 AK |
5 | |
6 | This program is free software; you can redistribute it and/or modify it | |
7 | under the terms and conditions of the GNU General Public License, | |
8 | version 2, as published by the Free Software Foundation. | |
9 | ||
10 | This program is distributed in the hope it will be useful, but WITHOUT | |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1da177e4 | 13 | more details. |
0abb6eb1 | 14 | |
1da177e4 | 15 | You should have received a copy of the GNU General Public License along with |
0abb6eb1 AK |
16 | this program; if not, write to the Free Software Foundation, Inc., |
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | ||
19 | The full GNU General Public License is included in this distribution in | |
20 | the file called "COPYING". | |
21 | ||
1da177e4 LT |
22 | Contact Information: |
23 | Linux NICS <linux.nics@intel.com> | |
0abb6eb1 | 24 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> |
1da177e4 LT |
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 | ||
7c0f6ba6 | 33 | #include <linux/uaccess.h> |
1da177e4 | 34 | |
c85fd6f0 AK |
35 | #define IXGB_ALL_RAR_ENTRIES 16 |
36 | ||
d189a7e8 AK |
37 | enum {NETDEV_STATS, IXGB_STATS}; |
38 | ||
1da177e4 LT |
39 | struct ixgb_stats { |
40 | char stat_string[ETH_GSTRING_LEN]; | |
d189a7e8 | 41 | int type; |
1da177e4 LT |
42 | int sizeof_stat; |
43 | int stat_offset; | |
44 | }; | |
45 | ||
d189a7e8 AK |
46 | #define IXGB_STAT(m) IXGB_STATS, \ |
47 | FIELD_SIZEOF(struct ixgb_adapter, m), \ | |
48 | offsetof(struct ixgb_adapter, m) | |
49 | #define IXGB_NETDEV_STAT(m) NETDEV_STATS, \ | |
50 | FIELD_SIZEOF(struct net_device, m), \ | |
51 | offsetof(struct net_device, m) | |
52 | ||
1da177e4 | 53 | static struct ixgb_stats ixgb_gstrings_stats[] = { |
0cdc0369 AK |
54 | {"rx_packets", IXGB_NETDEV_STAT(stats.rx_packets)}, |
55 | {"tx_packets", IXGB_NETDEV_STAT(stats.tx_packets)}, | |
56 | {"rx_bytes", IXGB_NETDEV_STAT(stats.rx_bytes)}, | |
57 | {"tx_bytes", IXGB_NETDEV_STAT(stats.tx_bytes)}, | |
58 | {"rx_errors", IXGB_NETDEV_STAT(stats.rx_errors)}, | |
59 | {"tx_errors", IXGB_NETDEV_STAT(stats.tx_errors)}, | |
60 | {"rx_dropped", IXGB_NETDEV_STAT(stats.rx_dropped)}, | |
61 | {"tx_dropped", IXGB_NETDEV_STAT(stats.tx_dropped)}, | |
62 | {"multicast", IXGB_NETDEV_STAT(stats.multicast)}, | |
63 | {"collisions", IXGB_NETDEV_STAT(stats.collisions)}, | |
1da177e4 | 64 | |
0cdc0369 AK |
65 | /* { "rx_length_errors", IXGB_NETDEV_STAT(stats.rx_length_errors) }, */ |
66 | {"rx_over_errors", IXGB_NETDEV_STAT(stats.rx_over_errors)}, | |
67 | {"rx_crc_errors", IXGB_NETDEV_STAT(stats.rx_crc_errors)}, | |
68 | {"rx_frame_errors", IXGB_NETDEV_STAT(stats.rx_frame_errors)}, | |
ac0b3509 | 69 | {"rx_no_buffer_count", IXGB_STAT(stats.rnbc)}, |
0cdc0369 AK |
70 | {"rx_fifo_errors", IXGB_NETDEV_STAT(stats.rx_fifo_errors)}, |
71 | {"rx_missed_errors", IXGB_NETDEV_STAT(stats.rx_missed_errors)}, | |
72 | {"tx_aborted_errors", IXGB_NETDEV_STAT(stats.tx_aborted_errors)}, | |
73 | {"tx_carrier_errors", IXGB_NETDEV_STAT(stats.tx_carrier_errors)}, | |
74 | {"tx_fifo_errors", IXGB_NETDEV_STAT(stats.tx_fifo_errors)}, | |
75 | {"tx_heartbeat_errors", IXGB_NETDEV_STAT(stats.tx_heartbeat_errors)}, | |
76 | {"tx_window_errors", IXGB_NETDEV_STAT(stats.tx_window_errors)}, | |
1da177e4 | 77 | {"tx_deferred_ok", IXGB_STAT(stats.dc)}, |
9b8118df | 78 | {"tx_timeout_count", IXGB_STAT(tx_timeout_count) }, |
dfd341e4 | 79 | {"tx_restart_queue", IXGB_STAT(restart_queue) }, |
1da177e4 LT |
80 | {"rx_long_length_errors", IXGB_STAT(stats.roc)}, |
81 | {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, | |
1da177e4 LT |
82 | {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)}, |
83 | {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)}, | |
1da177e4 LT |
84 | {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)}, |
85 | {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)}, | |
86 | {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)}, | |
87 | {"tx_flow_control_xoff", IXGB_STAT(stats.xofftxc)}, | |
88 | {"rx_csum_offload_good", IXGB_STAT(hw_csum_rx_good)}, | |
89 | {"rx_csum_offload_errors", IXGB_STAT(hw_csum_rx_error)}, | |
90 | {"tx_csum_offload_good", IXGB_STAT(hw_csum_tx_good)}, | |
91 | {"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)} | |
92 | }; | |
93 | ||
ff8ac609 | 94 | #define IXGB_STATS_LEN ARRAY_SIZE(ixgb_gstrings_stats) |
1da177e4 LT |
95 | |
96 | static int | |
97 | ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |
98 | { | |
8908c6cd | 99 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 LT |
100 | |
101 | ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); | |
db0bacaa | 102 | ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); |
1da177e4 LT |
103 | ecmd->port = PORT_FIBRE; |
104 | ecmd->transceiver = XCVR_EXTERNAL; | |
105 | ||
03f83041 | 106 | if (netif_carrier_ok(adapter->netdev)) { |
70739497 | 107 | ethtool_cmd_speed_set(ecmd, SPEED_10000); |
1da177e4 LT |
108 | ecmd->duplex = DUPLEX_FULL; |
109 | } else { | |
537fae01 JP |
110 | ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); |
111 | ecmd->duplex = DUPLEX_UNKNOWN; | |
1da177e4 LT |
112 | } |
113 | ||
114 | ecmd->autoneg = AUTONEG_DISABLE; | |
115 | return 0; | |
116 | } | |
117 | ||
d7ccb8c2 | 118 | void ixgb_set_speed_duplex(struct net_device *netdev) |
4de17c8c AK |
119 | { |
120 | struct ixgb_adapter *adapter = netdev_priv(netdev); | |
121 | /* be optimistic about our link, since we were up before */ | |
122 | adapter->link_speed = 10000; | |
123 | adapter->link_duplex = FULL_DUPLEX; | |
124 | netif_carrier_on(netdev); | |
125 | netif_wake_queue(netdev); | |
126 | } | |
127 | ||
1da177e4 LT |
128 | static int |
129 | ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |
130 | { | |
8908c6cd | 131 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
25db0338 | 132 | u32 speed = ethtool_cmd_speed(ecmd); |
1da177e4 | 133 | |
03f83041 | 134 | if (ecmd->autoneg == AUTONEG_ENABLE || |
25db0338 | 135 | (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) |
1da177e4 | 136 | return -EINVAL; |
0060c072 | 137 | |
03f83041 | 138 | if (netif_running(adapter->netdev)) { |
446490ca | 139 | ixgb_down(adapter, true); |
1da177e4 LT |
140 | ixgb_reset(adapter); |
141 | ixgb_up(adapter); | |
4de17c8c | 142 | ixgb_set_speed_duplex(netdev); |
1da177e4 LT |
143 | } else |
144 | ixgb_reset(adapter); | |
145 | ||
146 | return 0; | |
147 | } | |
148 | ||
149 | static void | |
150 | ixgb_get_pauseparam(struct net_device *netdev, | |
151 | struct ethtool_pauseparam *pause) | |
152 | { | |
8908c6cd | 153 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 154 | struct ixgb_hw *hw = &adapter->hw; |
0060c072 | 155 | |
1da177e4 | 156 | pause->autoneg = AUTONEG_DISABLE; |
0060c072 | 157 | |
03f83041 | 158 | if (hw->fc.type == ixgb_fc_rx_pause) |
1da177e4 | 159 | pause->rx_pause = 1; |
03f83041 | 160 | else if (hw->fc.type == ixgb_fc_tx_pause) |
1da177e4 | 161 | pause->tx_pause = 1; |
03f83041 | 162 | else if (hw->fc.type == ixgb_fc_full) { |
1da177e4 LT |
163 | pause->rx_pause = 1; |
164 | pause->tx_pause = 1; | |
165 | } | |
166 | } | |
167 | ||
168 | static int | |
169 | ixgb_set_pauseparam(struct net_device *netdev, | |
170 | struct ethtool_pauseparam *pause) | |
171 | { | |
8908c6cd | 172 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 173 | struct ixgb_hw *hw = &adapter->hw; |
0060c072 | 174 | |
03f83041 | 175 | if (pause->autoneg == AUTONEG_ENABLE) |
1da177e4 LT |
176 | return -EINVAL; |
177 | ||
03f83041 | 178 | if (pause->rx_pause && pause->tx_pause) |
1da177e4 | 179 | hw->fc.type = ixgb_fc_full; |
03f83041 | 180 | else if (pause->rx_pause && !pause->tx_pause) |
1da177e4 | 181 | hw->fc.type = ixgb_fc_rx_pause; |
03f83041 | 182 | else if (!pause->rx_pause && pause->tx_pause) |
1da177e4 | 183 | hw->fc.type = ixgb_fc_tx_pause; |
03f83041 | 184 | else if (!pause->rx_pause && !pause->tx_pause) |
1da177e4 LT |
185 | hw->fc.type = ixgb_fc_none; |
186 | ||
03f83041 | 187 | if (netif_running(adapter->netdev)) { |
446490ca | 188 | ixgb_down(adapter, true); |
1da177e4 | 189 | ixgb_up(adapter); |
4de17c8c | 190 | ixgb_set_speed_duplex(netdev); |
1da177e4 LT |
191 | } else |
192 | ixgb_reset(adapter); | |
0060c072 | 193 | |
1da177e4 LT |
194 | return 0; |
195 | } | |
196 | ||
222441a6 | 197 | static u32 |
ec9c3f5d AK |
198 | ixgb_get_msglevel(struct net_device *netdev) |
199 | { | |
25943071 | 200 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
ec9c3f5d AK |
201 | return adapter->msg_enable; |
202 | } | |
203 | ||
204 | static void | |
222441a6 | 205 | ixgb_set_msglevel(struct net_device *netdev, u32 data) |
ec9c3f5d | 206 | { |
25943071 | 207 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
ec9c3f5d AK |
208 | adapter->msg_enable = data; |
209 | } | |
1da177e4 LT |
210 | #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_ |
211 | ||
0060c072 | 212 | static int |
1da177e4 LT |
213 | ixgb_get_regs_len(struct net_device *netdev) |
214 | { | |
222441a6 | 215 | #define IXGB_REG_DUMP_LEN 136*sizeof(u32) |
1da177e4 LT |
216 | return IXGB_REG_DUMP_LEN; |
217 | } | |
218 | ||
219 | static void | |
220 | ixgb_get_regs(struct net_device *netdev, | |
221 | struct ethtool_regs *regs, void *p) | |
222 | { | |
8908c6cd | 223 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 224 | struct ixgb_hw *hw = &adapter->hw; |
222441a6 JP |
225 | u32 *reg = p; |
226 | u32 *reg_start = reg; | |
227 | u8 i; | |
1da177e4 | 228 | |
5e3c30de | 229 | /* the 1 (one) below indicates an attempt at versioning, if the |
ab707da7 MC |
230 | * interface in ethtool or the driver changes, this 1 should be |
231 | * incremented */ | |
5e3c30de | 232 | regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id; |
1da177e4 LT |
233 | |
234 | /* General Registers */ | |
235 | *reg++ = IXGB_READ_REG(hw, CTRL0); /* 0 */ | |
236 | *reg++ = IXGB_READ_REG(hw, CTRL1); /* 1 */ | |
237 | *reg++ = IXGB_READ_REG(hw, STATUS); /* 2 */ | |
238 | *reg++ = IXGB_READ_REG(hw, EECD); /* 3 */ | |
239 | *reg++ = IXGB_READ_REG(hw, MFS); /* 4 */ | |
240 | ||
241 | /* Interrupt */ | |
242 | *reg++ = IXGB_READ_REG(hw, ICR); /* 5 */ | |
243 | *reg++ = IXGB_READ_REG(hw, ICS); /* 6 */ | |
244 | *reg++ = IXGB_READ_REG(hw, IMS); /* 7 */ | |
245 | *reg++ = IXGB_READ_REG(hw, IMC); /* 8 */ | |
246 | ||
247 | /* Receive */ | |
248 | *reg++ = IXGB_READ_REG(hw, RCTL); /* 9 */ | |
249 | *reg++ = IXGB_READ_REG(hw, FCRTL); /* 10 */ | |
250 | *reg++ = IXGB_READ_REG(hw, FCRTH); /* 11 */ | |
251 | *reg++ = IXGB_READ_REG(hw, RDBAL); /* 12 */ | |
252 | *reg++ = IXGB_READ_REG(hw, RDBAH); /* 13 */ | |
253 | *reg++ = IXGB_READ_REG(hw, RDLEN); /* 14 */ | |
254 | *reg++ = IXGB_READ_REG(hw, RDH); /* 15 */ | |
255 | *reg++ = IXGB_READ_REG(hw, RDT); /* 16 */ | |
256 | *reg++ = IXGB_READ_REG(hw, RDTR); /* 17 */ | |
257 | *reg++ = IXGB_READ_REG(hw, RXDCTL); /* 18 */ | |
258 | *reg++ = IXGB_READ_REG(hw, RAIDC); /* 19 */ | |
259 | *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ | |
260 | ||
9ef2eec3 | 261 | /* there are 16 RAR entries in hardware, we only use 3 */ |
1459336d | 262 | for (i = 0; i < IXGB_ALL_RAR_ENTRIES; i++) { |
1da177e4 LT |
263 | *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ |
264 | *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ | |
265 | } | |
266 | ||
267 | /* Transmit */ | |
268 | *reg++ = IXGB_READ_REG(hw, TCTL); /* 53 */ | |
269 | *reg++ = IXGB_READ_REG(hw, TDBAL); /* 54 */ | |
270 | *reg++ = IXGB_READ_REG(hw, TDBAH); /* 55 */ | |
271 | *reg++ = IXGB_READ_REG(hw, TDLEN); /* 56 */ | |
272 | *reg++ = IXGB_READ_REG(hw, TDH); /* 57 */ | |
273 | *reg++ = IXGB_READ_REG(hw, TDT); /* 58 */ | |
274 | *reg++ = IXGB_READ_REG(hw, TIDV); /* 59 */ | |
275 | *reg++ = IXGB_READ_REG(hw, TXDCTL); /* 60 */ | |
276 | *reg++ = IXGB_READ_REG(hw, TSPMT); /* 61 */ | |
277 | *reg++ = IXGB_READ_REG(hw, PAP); /* 62 */ | |
278 | ||
279 | /* Physical */ | |
280 | *reg++ = IXGB_READ_REG(hw, PCSC1); /* 63 */ | |
281 | *reg++ = IXGB_READ_REG(hw, PCSC2); /* 64 */ | |
282 | *reg++ = IXGB_READ_REG(hw, PCSS1); /* 65 */ | |
283 | *reg++ = IXGB_READ_REG(hw, PCSS2); /* 66 */ | |
284 | *reg++ = IXGB_READ_REG(hw, XPCSS); /* 67 */ | |
285 | *reg++ = IXGB_READ_REG(hw, UCCR); /* 68 */ | |
286 | *reg++ = IXGB_READ_REG(hw, XPCSTC); /* 69 */ | |
287 | *reg++ = IXGB_READ_REG(hw, MACA); /* 70 */ | |
288 | *reg++ = IXGB_READ_REG(hw, APAE); /* 71 */ | |
289 | *reg++ = IXGB_READ_REG(hw, ARD); /* 72 */ | |
290 | *reg++ = IXGB_READ_REG(hw, AIS); /* 73 */ | |
291 | *reg++ = IXGB_READ_REG(hw, MSCA); /* 74 */ | |
292 | *reg++ = IXGB_READ_REG(hw, MSRWD); /* 75 */ | |
293 | ||
294 | /* Statistics */ | |
295 | *reg++ = IXGB_GET_STAT(adapter, tprl); /* 76 */ | |
296 | *reg++ = IXGB_GET_STAT(adapter, tprh); /* 77 */ | |
297 | *reg++ = IXGB_GET_STAT(adapter, gprcl); /* 78 */ | |
298 | *reg++ = IXGB_GET_STAT(adapter, gprch); /* 79 */ | |
299 | *reg++ = IXGB_GET_STAT(adapter, bprcl); /* 80 */ | |
300 | *reg++ = IXGB_GET_STAT(adapter, bprch); /* 81 */ | |
301 | *reg++ = IXGB_GET_STAT(adapter, mprcl); /* 82 */ | |
302 | *reg++ = IXGB_GET_STAT(adapter, mprch); /* 83 */ | |
303 | *reg++ = IXGB_GET_STAT(adapter, uprcl); /* 84 */ | |
304 | *reg++ = IXGB_GET_STAT(adapter, uprch); /* 85 */ | |
305 | *reg++ = IXGB_GET_STAT(adapter, vprcl); /* 86 */ | |
306 | *reg++ = IXGB_GET_STAT(adapter, vprch); /* 87 */ | |
307 | *reg++ = IXGB_GET_STAT(adapter, jprcl); /* 88 */ | |
308 | *reg++ = IXGB_GET_STAT(adapter, jprch); /* 89 */ | |
309 | *reg++ = IXGB_GET_STAT(adapter, gorcl); /* 90 */ | |
310 | *reg++ = IXGB_GET_STAT(adapter, gorch); /* 91 */ | |
311 | *reg++ = IXGB_GET_STAT(adapter, torl); /* 92 */ | |
312 | *reg++ = IXGB_GET_STAT(adapter, torh); /* 93 */ | |
313 | *reg++ = IXGB_GET_STAT(adapter, rnbc); /* 94 */ | |
314 | *reg++ = IXGB_GET_STAT(adapter, ruc); /* 95 */ | |
315 | *reg++ = IXGB_GET_STAT(adapter, roc); /* 96 */ | |
316 | *reg++ = IXGB_GET_STAT(adapter, rlec); /* 97 */ | |
317 | *reg++ = IXGB_GET_STAT(adapter, crcerrs); /* 98 */ | |
318 | *reg++ = IXGB_GET_STAT(adapter, icbc); /* 99 */ | |
319 | *reg++ = IXGB_GET_STAT(adapter, ecbc); /* 100 */ | |
320 | *reg++ = IXGB_GET_STAT(adapter, mpc); /* 101 */ | |
321 | *reg++ = IXGB_GET_STAT(adapter, tptl); /* 102 */ | |
322 | *reg++ = IXGB_GET_STAT(adapter, tpth); /* 103 */ | |
323 | *reg++ = IXGB_GET_STAT(adapter, gptcl); /* 104 */ | |
324 | *reg++ = IXGB_GET_STAT(adapter, gptch); /* 105 */ | |
325 | *reg++ = IXGB_GET_STAT(adapter, bptcl); /* 106 */ | |
326 | *reg++ = IXGB_GET_STAT(adapter, bptch); /* 107 */ | |
327 | *reg++ = IXGB_GET_STAT(adapter, mptcl); /* 108 */ | |
328 | *reg++ = IXGB_GET_STAT(adapter, mptch); /* 109 */ | |
329 | *reg++ = IXGB_GET_STAT(adapter, uptcl); /* 110 */ | |
330 | *reg++ = IXGB_GET_STAT(adapter, uptch); /* 111 */ | |
331 | *reg++ = IXGB_GET_STAT(adapter, vptcl); /* 112 */ | |
332 | *reg++ = IXGB_GET_STAT(adapter, vptch); /* 113 */ | |
333 | *reg++ = IXGB_GET_STAT(adapter, jptcl); /* 114 */ | |
334 | *reg++ = IXGB_GET_STAT(adapter, jptch); /* 115 */ | |
335 | *reg++ = IXGB_GET_STAT(adapter, gotcl); /* 116 */ | |
336 | *reg++ = IXGB_GET_STAT(adapter, gotch); /* 117 */ | |
337 | *reg++ = IXGB_GET_STAT(adapter, totl); /* 118 */ | |
338 | *reg++ = IXGB_GET_STAT(adapter, toth); /* 119 */ | |
339 | *reg++ = IXGB_GET_STAT(adapter, dc); /* 120 */ | |
340 | *reg++ = IXGB_GET_STAT(adapter, plt64c); /* 121 */ | |
341 | *reg++ = IXGB_GET_STAT(adapter, tsctc); /* 122 */ | |
342 | *reg++ = IXGB_GET_STAT(adapter, tsctfc); /* 123 */ | |
343 | *reg++ = IXGB_GET_STAT(adapter, ibic); /* 124 */ | |
344 | *reg++ = IXGB_GET_STAT(adapter, rfc); /* 125 */ | |
345 | *reg++ = IXGB_GET_STAT(adapter, lfc); /* 126 */ | |
346 | *reg++ = IXGB_GET_STAT(adapter, pfrc); /* 127 */ | |
347 | *reg++ = IXGB_GET_STAT(adapter, pftc); /* 128 */ | |
348 | *reg++ = IXGB_GET_STAT(adapter, mcfrc); /* 129 */ | |
349 | *reg++ = IXGB_GET_STAT(adapter, mcftc); /* 130 */ | |
350 | *reg++ = IXGB_GET_STAT(adapter, xonrxc); /* 131 */ | |
351 | *reg++ = IXGB_GET_STAT(adapter, xontxc); /* 132 */ | |
352 | *reg++ = IXGB_GET_STAT(adapter, xoffrxc); /* 133 */ | |
353 | *reg++ = IXGB_GET_STAT(adapter, xofftxc); /* 134 */ | |
354 | *reg++ = IXGB_GET_STAT(adapter, rjc); /* 135 */ | |
355 | ||
222441a6 | 356 | regs->len = (reg - reg_start) * sizeof(u32); |
1da177e4 LT |
357 | } |
358 | ||
359 | static int | |
360 | ixgb_get_eeprom_len(struct net_device *netdev) | |
361 | { | |
362 | /* return size in bytes */ | |
807540ba | 363 | return IXGB_EEPROM_SIZE << 1; |
1da177e4 LT |
364 | } |
365 | ||
366 | static int | |
367 | ixgb_get_eeprom(struct net_device *netdev, | |
222441a6 | 368 | struct ethtool_eeprom *eeprom, u8 *bytes) |
1da177e4 | 369 | { |
8908c6cd | 370 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 371 | struct ixgb_hw *hw = &adapter->hw; |
c676504e | 372 | __le16 *eeprom_buff; |
1da177e4 LT |
373 | int i, max_len, first_word, last_word; |
374 | int ret_val = 0; | |
375 | ||
03f83041 | 376 | if (eeprom->len == 0) { |
1da177e4 LT |
377 | ret_val = -EINVAL; |
378 | goto geeprom_error; | |
379 | } | |
380 | ||
381 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); | |
382 | ||
383 | max_len = ixgb_get_eeprom_len(netdev); | |
384 | ||
03f83041 | 385 | if (eeprom->offset > eeprom->offset + eeprom->len) { |
1da177e4 LT |
386 | ret_val = -EINVAL; |
387 | goto geeprom_error; | |
388 | } | |
389 | ||
03f83041 | 390 | if ((eeprom->offset + eeprom->len) > max_len) |
1da177e4 LT |
391 | eeprom->len = (max_len - eeprom->offset); |
392 | ||
393 | first_word = eeprom->offset >> 1; | |
394 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | |
395 | ||
c676504e | 396 | eeprom_buff = kmalloc(sizeof(__le16) * |
1da177e4 | 397 | (last_word - first_word + 1), GFP_KERNEL); |
03f83041 | 398 | if (!eeprom_buff) |
1da177e4 LT |
399 | return -ENOMEM; |
400 | ||
401 | /* note the eeprom was good because the driver loaded */ | |
1459336d | 402 | for (i = 0; i <= (last_word - first_word); i++) |
1da177e4 | 403 | eeprom_buff[i] = ixgb_get_eeprom_word(hw, (first_word + i)); |
1da177e4 | 404 | |
1459336d | 405 | memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); |
1da177e4 LT |
406 | kfree(eeprom_buff); |
407 | ||
408 | geeprom_error: | |
409 | return ret_val; | |
410 | } | |
411 | ||
412 | static int | |
413 | ixgb_set_eeprom(struct net_device *netdev, | |
222441a6 | 414 | struct ethtool_eeprom *eeprom, u8 *bytes) |
1da177e4 | 415 | { |
8908c6cd | 416 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 417 | struct ixgb_hw *hw = &adapter->hw; |
222441a6 | 418 | u16 *eeprom_buff; |
1da177e4 LT |
419 | void *ptr; |
420 | int max_len, first_word, last_word; | |
222441a6 | 421 | u16 i; |
1da177e4 | 422 | |
03f83041 | 423 | if (eeprom->len == 0) |
1da177e4 LT |
424 | return -EINVAL; |
425 | ||
03f83041 | 426 | if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) |
1da177e4 LT |
427 | return -EFAULT; |
428 | ||
429 | max_len = ixgb_get_eeprom_len(netdev); | |
430 | ||
03f83041 | 431 | if (eeprom->offset > eeprom->offset + eeprom->len) |
1da177e4 LT |
432 | return -EINVAL; |
433 | ||
03f83041 | 434 | if ((eeprom->offset + eeprom->len) > max_len) |
1da177e4 LT |
435 | eeprom->len = (max_len - eeprom->offset); |
436 | ||
437 | first_word = eeprom->offset >> 1; | |
438 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | |
439 | eeprom_buff = kmalloc(max_len, GFP_KERNEL); | |
03f83041 | 440 | if (!eeprom_buff) |
1da177e4 LT |
441 | return -ENOMEM; |
442 | ||
443 | ptr = (void *)eeprom_buff; | |
444 | ||
03f83041 | 445 | if (eeprom->offset & 1) { |
1da177e4 LT |
446 | /* need read/modify/write of first changed EEPROM word */ |
447 | /* only the second byte of the word is being modified */ | |
448 | eeprom_buff[0] = ixgb_read_eeprom(hw, first_word); | |
449 | ptr++; | |
450 | } | |
03f83041 | 451 | if ((eeprom->offset + eeprom->len) & 1) { |
1da177e4 LT |
452 | /* need read/modify/write of last changed EEPROM word */ |
453 | /* only the first byte of the word is being modified */ | |
0060c072 | 454 | eeprom_buff[last_word - first_word] |
1da177e4 LT |
455 | = ixgb_read_eeprom(hw, last_word); |
456 | } | |
457 | ||
458 | memcpy(ptr, bytes, eeprom->len); | |
1459336d | 459 | for (i = 0; i <= (last_word - first_word); i++) |
1da177e4 LT |
460 | ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]); |
461 | ||
462 | /* Update the checksum over the first part of the EEPROM if needed */ | |
03f83041 | 463 | if (first_word <= EEPROM_CHECKSUM_REG) |
1da177e4 LT |
464 | ixgb_update_eeprom_checksum(hw); |
465 | ||
466 | kfree(eeprom_buff); | |
467 | return 0; | |
468 | } | |
469 | ||
470 | static void | |
471 | ixgb_get_drvinfo(struct net_device *netdev, | |
472 | struct ethtool_drvinfo *drvinfo) | |
473 | { | |
8908c6cd | 474 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 475 | |
612a94d6 RJ |
476 | strlcpy(drvinfo->driver, ixgb_driver_name, |
477 | sizeof(drvinfo->driver)); | |
478 | strlcpy(drvinfo->version, ixgb_driver_version, | |
479 | sizeof(drvinfo->version)); | |
612a94d6 RJ |
480 | strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), |
481 | sizeof(drvinfo->bus_info)); | |
1da177e4 LT |
482 | } |
483 | ||
484 | static void | |
485 | ixgb_get_ringparam(struct net_device *netdev, | |
486 | struct ethtool_ringparam *ring) | |
487 | { | |
8908c6cd | 488 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 LT |
489 | struct ixgb_desc_ring *txdr = &adapter->tx_ring; |
490 | struct ixgb_desc_ring *rxdr = &adapter->rx_ring; | |
491 | ||
0060c072 | 492 | ring->rx_max_pending = MAX_RXD; |
1da177e4 | 493 | ring->tx_max_pending = MAX_TXD; |
1da177e4 LT |
494 | ring->rx_pending = rxdr->count; |
495 | ring->tx_pending = txdr->count; | |
1da177e4 LT |
496 | } |
497 | ||
0060c072 | 498 | static int |
1da177e4 LT |
499 | ixgb_set_ringparam(struct net_device *netdev, |
500 | struct ethtool_ringparam *ring) | |
501 | { | |
8908c6cd | 502 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 LT |
503 | struct ixgb_desc_ring *txdr = &adapter->tx_ring; |
504 | struct ixgb_desc_ring *rxdr = &adapter->rx_ring; | |
505 | struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new; | |
506 | int err; | |
507 | ||
508 | tx_old = adapter->tx_ring; | |
509 | rx_old = adapter->rx_ring; | |
510 | ||
03f83041 | 511 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) |
1da177e4 LT |
512 | return -EINVAL; |
513 | ||
03f83041 | 514 | if (netif_running(adapter->netdev)) |
446490ca | 515 | ixgb_down(adapter, true); |
1da177e4 | 516 | |
222441a6 JP |
517 | rxdr->count = max(ring->rx_pending,(u32)MIN_RXD); |
518 | rxdr->count = min(rxdr->count,(u32)MAX_RXD); | |
55e924cf | 519 | rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); |
1da177e4 | 520 | |
222441a6 JP |
521 | txdr->count = max(ring->tx_pending,(u32)MIN_TXD); |
522 | txdr->count = min(txdr->count,(u32)MAX_TXD); | |
55e924cf | 523 | txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); |
1da177e4 | 524 | |
03f83041 | 525 | if (netif_running(adapter->netdev)) { |
1da177e4 | 526 | /* Try to get new resources before deleting old */ |
03f83041 | 527 | if ((err = ixgb_setup_rx_resources(adapter))) |
1da177e4 | 528 | goto err_setup_rx; |
03f83041 | 529 | if ((err = ixgb_setup_tx_resources(adapter))) |
1da177e4 LT |
530 | goto err_setup_tx; |
531 | ||
532 | /* save the new, restore the old in order to free it, | |
533 | * then restore the new back again */ | |
534 | ||
535 | rx_new = adapter->rx_ring; | |
536 | tx_new = adapter->tx_ring; | |
537 | adapter->rx_ring = rx_old; | |
538 | adapter->tx_ring = tx_old; | |
539 | ixgb_free_rx_resources(adapter); | |
540 | ixgb_free_tx_resources(adapter); | |
541 | adapter->rx_ring = rx_new; | |
542 | adapter->tx_ring = tx_new; | |
03f83041 | 543 | if ((err = ixgb_up(adapter))) |
1da177e4 | 544 | return err; |
4de17c8c | 545 | ixgb_set_speed_duplex(netdev); |
1da177e4 LT |
546 | } |
547 | ||
548 | return 0; | |
549 | err_setup_tx: | |
550 | ixgb_free_rx_resources(adapter); | |
551 | err_setup_rx: | |
552 | adapter->rx_ring = rx_old; | |
553 | adapter->tx_ring = tx_old; | |
554 | ixgb_up(adapter); | |
555 | return err; | |
556 | } | |
557 | ||
1da177e4 | 558 | static int |
ec7e97e9 | 559 | ixgb_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) |
1da177e4 | 560 | { |
8908c6cd | 561 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 562 | |
ec7e97e9 JK |
563 | switch (state) { |
564 | case ETHTOOL_ID_ACTIVE: | |
565 | return 2; | |
1da177e4 | 566 | |
ec7e97e9 JK |
567 | case ETHTOOL_ID_ON: |
568 | ixgb_led_on(&adapter->hw); | |
569 | break; | |
1da177e4 | 570 | |
ec7e97e9 JK |
571 | case ETHTOOL_ID_OFF: |
572 | case ETHTOOL_ID_INACTIVE: | |
573 | ixgb_led_off(&adapter->hw); | |
574 | } | |
1da177e4 LT |
575 | |
576 | return 0; | |
577 | } | |
578 | ||
0060c072 | 579 | static int |
b9f2c044 | 580 | ixgb_get_sset_count(struct net_device *netdev, int sset) |
1da177e4 | 581 | { |
b9f2c044 JG |
582 | switch (sset) { |
583 | case ETH_SS_STATS: | |
584 | return IXGB_STATS_LEN; | |
585 | default: | |
586 | return -EOPNOTSUPP; | |
587 | } | |
1da177e4 LT |
588 | } |
589 | ||
0060c072 JB |
590 | static void |
591 | ixgb_get_ethtool_stats(struct net_device *netdev, | |
222441a6 | 592 | struct ethtool_stats *stats, u64 *data) |
1da177e4 | 593 | { |
8908c6cd | 594 | struct ixgb_adapter *adapter = netdev_priv(netdev); |
1da177e4 | 595 | int i; |
d189a7e8 | 596 | char *p = NULL; |
1da177e4 LT |
597 | |
598 | ixgb_update_stats(adapter); | |
1459336d | 599 | for (i = 0; i < IXGB_STATS_LEN; i++) { |
d189a7e8 AK |
600 | switch (ixgb_gstrings_stats[i].type) { |
601 | case NETDEV_STATS: | |
602 | p = (char *) netdev + | |
603 | ixgb_gstrings_stats[i].stat_offset; | |
604 | break; | |
605 | case IXGB_STATS: | |
606 | p = (char *) adapter + | |
607 | ixgb_gstrings_stats[i].stat_offset; | |
608 | break; | |
609 | } | |
610 | ||
0060c072 | 611 | data[i] = (ixgb_gstrings_stats[i].sizeof_stat == |
222441a6 | 612 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1da177e4 LT |
613 | } |
614 | } | |
615 | ||
0060c072 | 616 | static void |
222441a6 | 617 | ixgb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
1da177e4 LT |
618 | { |
619 | int i; | |
620 | ||
621 | switch(stringset) { | |
622 | case ETH_SS_STATS: | |
1459336d | 623 | for (i = 0; i < IXGB_STATS_LEN; i++) { |
0060c072 | 624 | memcpy(data + i * ETH_GSTRING_LEN, |
1da177e4 LT |
625 | ixgb_gstrings_stats[i].stat_string, |
626 | ETH_GSTRING_LEN); | |
627 | } | |
628 | break; | |
629 | } | |
630 | } | |
631 | ||
7282d491 | 632 | static const struct ethtool_ops ixgb_ethtool_ops = { |
1da177e4 LT |
633 | .get_settings = ixgb_get_settings, |
634 | .set_settings = ixgb_set_settings, | |
635 | .get_drvinfo = ixgb_get_drvinfo, | |
636 | .get_regs_len = ixgb_get_regs_len, | |
637 | .get_regs = ixgb_get_regs, | |
638 | .get_link = ethtool_op_get_link, | |
639 | .get_eeprom_len = ixgb_get_eeprom_len, | |
640 | .get_eeprom = ixgb_get_eeprom, | |
641 | .set_eeprom = ixgb_set_eeprom, | |
642 | .get_ringparam = ixgb_get_ringparam, | |
643 | .set_ringparam = ixgb_set_ringparam, | |
644 | .get_pauseparam = ixgb_get_pauseparam, | |
645 | .set_pauseparam = ixgb_set_pauseparam, | |
ec9c3f5d AK |
646 | .get_msglevel = ixgb_get_msglevel, |
647 | .set_msglevel = ixgb_set_msglevel, | |
1da177e4 | 648 | .get_strings = ixgb_get_strings, |
ec7e97e9 | 649 | .set_phys_id = ixgb_set_phys_id, |
b9f2c044 | 650 | .get_sset_count = ixgb_get_sset_count, |
1da177e4 LT |
651 | .get_ethtool_stats = ixgb_get_ethtool_stats, |
652 | }; | |
653 | ||
654 | void ixgb_set_ethtool_ops(struct net_device *netdev) | |
655 | { | |
7ad24ea4 | 656 | netdev->ethtool_ops = &ixgb_ethtool_ops; |
1da177e4 | 657 | } |