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