1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2018 Intel Corporation */ |
3 | |
4 | /* ethtool support for igc */ |
5 | #include <linux/if_vlan.h> |
6 | #include <linux/pm_runtime.h> |
7 | #include <linux/mdio.h> |
8 | |
9 | #include "igc.h" |
10 | #include "igc_diag.h" |
11 | |
12 | /* forward declaration */ |
13 | struct igc_stats { |
14 | char stat_string[ETH_GSTRING_LEN]; |
15 | int sizeof_stat; |
16 | int stat_offset; |
17 | }; |
18 | |
19 | #define IGC_STAT(_name, _stat) { \ |
20 | .stat_string = _name, \ |
21 | .sizeof_stat = sizeof_field(struct igc_adapter, _stat), \ |
22 | .stat_offset = offsetof(struct igc_adapter, _stat) \ |
23 | } |
24 | |
25 | static const struct igc_stats igc_gstrings_stats[] = { |
26 | IGC_STAT("rx_packets" , stats.gprc), |
27 | IGC_STAT("tx_packets" , stats.gptc), |
28 | IGC_STAT("rx_bytes" , stats.gorc), |
29 | IGC_STAT("tx_bytes" , stats.gotc), |
30 | IGC_STAT("rx_broadcast" , stats.bprc), |
31 | IGC_STAT("tx_broadcast" , stats.bptc), |
32 | IGC_STAT("rx_multicast" , stats.mprc), |
33 | IGC_STAT("tx_multicast" , stats.mptc), |
34 | IGC_STAT("multicast" , stats.mprc), |
35 | IGC_STAT("collisions" , stats.colc), |
36 | IGC_STAT("rx_crc_errors" , stats.crcerrs), |
37 | IGC_STAT("rx_no_buffer_count" , stats.rnbc), |
38 | IGC_STAT("rx_missed_errors" , stats.mpc), |
39 | IGC_STAT("tx_aborted_errors" , stats.ecol), |
40 | IGC_STAT("tx_carrier_errors" , stats.tncrs), |
41 | IGC_STAT("tx_window_errors" , stats.latecol), |
42 | IGC_STAT("tx_abort_late_coll" , stats.latecol), |
43 | IGC_STAT("tx_deferred_ok" , stats.dc), |
44 | IGC_STAT("tx_single_coll_ok" , stats.scc), |
45 | IGC_STAT("tx_multi_coll_ok" , stats.mcc), |
46 | IGC_STAT("tx_timeout_count" , tx_timeout_count), |
47 | IGC_STAT("rx_long_length_errors" , stats.roc), |
48 | IGC_STAT("rx_short_length_errors" , stats.ruc), |
49 | IGC_STAT("rx_align_errors" , stats.algnerrc), |
50 | IGC_STAT("tx_tcp_seg_good" , stats.tsctc), |
51 | IGC_STAT("tx_tcp_seg_failed" , stats.tsctfc), |
52 | IGC_STAT("rx_flow_control_xon" , stats.xonrxc), |
53 | IGC_STAT("rx_flow_control_xoff" , stats.xoffrxc), |
54 | IGC_STAT("tx_flow_control_xon" , stats.xontxc), |
55 | IGC_STAT("tx_flow_control_xoff" , stats.xofftxc), |
56 | IGC_STAT("rx_long_byte_count" , stats.gorc), |
57 | IGC_STAT("tx_dma_out_of_sync" , stats.doosync), |
58 | IGC_STAT("tx_smbus" , stats.mgptc), |
59 | IGC_STAT("rx_smbus" , stats.mgprc), |
60 | IGC_STAT("dropped_smbus" , stats.mgpdc), |
61 | IGC_STAT("os2bmc_rx_by_bmc" , stats.o2bgptc), |
62 | IGC_STAT("os2bmc_tx_by_bmc" , stats.b2ospc), |
63 | IGC_STAT("os2bmc_tx_by_host" , stats.o2bspc), |
64 | IGC_STAT("os2bmc_rx_by_host" , stats.b2ogprc), |
65 | IGC_STAT("tx_hwtstamp_timeouts" , tx_hwtstamp_timeouts), |
66 | IGC_STAT("tx_hwtstamp_skipped" , tx_hwtstamp_skipped), |
67 | IGC_STAT("rx_hwtstamp_cleared" , rx_hwtstamp_cleared), |
68 | IGC_STAT("tx_lpi_counter" , stats.tlpic), |
69 | IGC_STAT("rx_lpi_counter" , stats.rlpic), |
70 | IGC_STAT("qbv_config_change_errors" , qbv_config_change_errors), |
71 | }; |
72 | |
73 | #define IGC_NETDEV_STAT(_net_stat) { \ |
74 | .stat_string = __stringify(_net_stat), \ |
75 | .sizeof_stat = sizeof_field(struct rtnl_link_stats64, _net_stat), \ |
76 | .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ |
77 | } |
78 | |
79 | static const struct igc_stats igc_gstrings_net_stats[] = { |
80 | IGC_NETDEV_STAT(rx_errors), |
81 | IGC_NETDEV_STAT(tx_errors), |
82 | IGC_NETDEV_STAT(tx_dropped), |
83 | IGC_NETDEV_STAT(rx_length_errors), |
84 | IGC_NETDEV_STAT(rx_over_errors), |
85 | IGC_NETDEV_STAT(rx_frame_errors), |
86 | IGC_NETDEV_STAT(rx_fifo_errors), |
87 | IGC_NETDEV_STAT(tx_fifo_errors), |
88 | IGC_NETDEV_STAT(tx_heartbeat_errors) |
89 | }; |
90 | |
91 | enum igc_diagnostics_results { |
92 | TEST_REG = 0, |
93 | TEST_EEP, |
94 | TEST_IRQ, |
95 | TEST_LOOP, |
96 | TEST_LINK |
97 | }; |
98 | |
99 | static const char igc_gstrings_test[][ETH_GSTRING_LEN] = { |
100 | [TEST_REG] = "Register test (offline)" , |
101 | [TEST_EEP] = "Eeprom test (offline)" , |
102 | [TEST_IRQ] = "Interrupt test (offline)" , |
103 | [TEST_LOOP] = "Loopback test (offline)" , |
104 | [TEST_LINK] = "Link test (on/offline)" |
105 | }; |
106 | |
107 | #define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN) |
108 | |
109 | #define IGC_GLOBAL_STATS_LEN \ |
110 | (sizeof(igc_gstrings_stats) / sizeof(struct igc_stats)) |
111 | #define IGC_NETDEV_STATS_LEN \ |
112 | (sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats)) |
113 | #define IGC_RX_QUEUE_STATS_LEN \ |
114 | (sizeof(struct igc_rx_queue_stats) / sizeof(u64)) |
115 | #define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ |
116 | #define IGC_QUEUE_STATS_LEN \ |
117 | ((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \ |
118 | IGC_RX_QUEUE_STATS_LEN) + \ |
119 | (((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \ |
120 | IGC_TX_QUEUE_STATS_LEN)) |
121 | #define IGC_STATS_LEN \ |
122 | (IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN) |
123 | |
124 | static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = { |
125 | #define IGC_PRIV_FLAGS_LEGACY_RX BIT(0) |
126 | "legacy-rx" , |
127 | }; |
128 | |
129 | #define IGC_PRIV_FLAGS_STR_LEN ARRAY_SIZE(igc_priv_flags_strings) |
130 | |
131 | static void igc_ethtool_get_drvinfo(struct net_device *netdev, |
132 | struct ethtool_drvinfo *drvinfo) |
133 | { |
134 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
135 | struct igc_hw *hw = &adapter->hw; |
136 | u16 nvm_version = 0; |
137 | u16 gphy_version; |
138 | |
139 | strscpy(p: drvinfo->driver, q: igc_driver_name, size: sizeof(drvinfo->driver)); |
140 | |
141 | /* NVM image version is reported as firmware version for i225 device */ |
142 | hw->nvm.ops.read(hw, IGC_NVM_DEV_STARTER, 1, &nvm_version); |
143 | |
144 | /* gPHY firmware version is reported as PHY FW version */ |
145 | gphy_version = igc_read_phy_fw_version(hw); |
146 | |
147 | scnprintf(buf: adapter->fw_version, |
148 | size: sizeof(adapter->fw_version), |
149 | fmt: "%x:%x" , |
150 | nvm_version, |
151 | gphy_version); |
152 | |
153 | strscpy(p: drvinfo->fw_version, q: adapter->fw_version, |
154 | size: sizeof(drvinfo->fw_version)); |
155 | |
156 | strscpy(p: drvinfo->bus_info, q: pci_name(pdev: adapter->pdev), |
157 | size: sizeof(drvinfo->bus_info)); |
158 | |
159 | drvinfo->n_priv_flags = IGC_PRIV_FLAGS_STR_LEN; |
160 | } |
161 | |
162 | static int igc_ethtool_get_regs_len(struct net_device *netdev) |
163 | { |
164 | return IGC_REGS_LEN * sizeof(u32); |
165 | } |
166 | |
167 | static void igc_ethtool_get_regs(struct net_device *netdev, |
168 | struct ethtool_regs *regs, void *p) |
169 | { |
170 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
171 | struct igc_hw *hw = &adapter->hw; |
172 | u32 *regs_buff = p; |
173 | u8 i; |
174 | |
175 | memset(p, 0, IGC_REGS_LEN * sizeof(u32)); |
176 | |
177 | regs->version = (2u << 24) | (hw->revision_id << 16) | hw->device_id; |
178 | |
179 | /* General Registers */ |
180 | regs_buff[0] = rd32(IGC_CTRL); |
181 | regs_buff[1] = rd32(IGC_STATUS); |
182 | regs_buff[2] = rd32(IGC_CTRL_EXT); |
183 | regs_buff[3] = rd32(IGC_MDIC); |
184 | regs_buff[4] = rd32(IGC_CONNSW); |
185 | |
186 | /* NVM Register */ |
187 | regs_buff[5] = rd32(IGC_EECD); |
188 | |
189 | /* Interrupt */ |
190 | /* Reading EICS for EICR because they read the |
191 | * same but EICS does not clear on read |
192 | */ |
193 | regs_buff[6] = rd32(IGC_EICS); |
194 | regs_buff[7] = rd32(IGC_EICS); |
195 | regs_buff[8] = rd32(IGC_EIMS); |
196 | regs_buff[9] = rd32(IGC_EIMC); |
197 | regs_buff[10] = rd32(IGC_EIAC); |
198 | regs_buff[11] = rd32(IGC_EIAM); |
199 | /* Reading ICS for ICR because they read the |
200 | * same but ICS does not clear on read |
201 | */ |
202 | regs_buff[12] = rd32(IGC_ICS); |
203 | regs_buff[13] = rd32(IGC_ICS); |
204 | regs_buff[14] = rd32(IGC_IMS); |
205 | regs_buff[15] = rd32(IGC_IMC); |
206 | regs_buff[16] = rd32(IGC_IAC); |
207 | regs_buff[17] = rd32(IGC_IAM); |
208 | |
209 | /* Flow Control */ |
210 | regs_buff[18] = rd32(IGC_FCAL); |
211 | regs_buff[19] = rd32(IGC_FCAH); |
212 | regs_buff[20] = rd32(IGC_FCTTV); |
213 | regs_buff[21] = rd32(IGC_FCRTL); |
214 | regs_buff[22] = rd32(IGC_FCRTH); |
215 | regs_buff[23] = rd32(IGC_FCRTV); |
216 | |
217 | /* Receive */ |
218 | regs_buff[24] = rd32(IGC_RCTL); |
219 | regs_buff[25] = rd32(IGC_RXCSUM); |
220 | regs_buff[26] = rd32(IGC_RLPML); |
221 | regs_buff[27] = rd32(IGC_RFCTL); |
222 | |
223 | /* Transmit */ |
224 | regs_buff[28] = rd32(IGC_TCTL); |
225 | regs_buff[29] = rd32(IGC_TIPG); |
226 | |
227 | /* Wake Up */ |
228 | |
229 | /* MAC */ |
230 | |
231 | /* Statistics */ |
232 | regs_buff[30] = adapter->stats.crcerrs; |
233 | regs_buff[31] = adapter->stats.algnerrc; |
234 | regs_buff[32] = adapter->stats.symerrs; |
235 | regs_buff[33] = adapter->stats.rxerrc; |
236 | regs_buff[34] = adapter->stats.mpc; |
237 | regs_buff[35] = adapter->stats.scc; |
238 | regs_buff[36] = adapter->stats.ecol; |
239 | regs_buff[37] = adapter->stats.mcc; |
240 | regs_buff[38] = adapter->stats.latecol; |
241 | regs_buff[39] = adapter->stats.colc; |
242 | regs_buff[40] = adapter->stats.dc; |
243 | regs_buff[41] = adapter->stats.tncrs; |
244 | regs_buff[42] = adapter->stats.sec; |
245 | regs_buff[43] = adapter->stats.htdpmc; |
246 | regs_buff[44] = adapter->stats.rlec; |
247 | regs_buff[45] = adapter->stats.xonrxc; |
248 | regs_buff[46] = adapter->stats.xontxc; |
249 | regs_buff[47] = adapter->stats.xoffrxc; |
250 | regs_buff[48] = adapter->stats.xofftxc; |
251 | regs_buff[49] = adapter->stats.fcruc; |
252 | regs_buff[50] = adapter->stats.prc64; |
253 | regs_buff[51] = adapter->stats.prc127; |
254 | regs_buff[52] = adapter->stats.prc255; |
255 | regs_buff[53] = adapter->stats.prc511; |
256 | regs_buff[54] = adapter->stats.prc1023; |
257 | regs_buff[55] = adapter->stats.prc1522; |
258 | regs_buff[56] = adapter->stats.gprc; |
259 | regs_buff[57] = adapter->stats.bprc; |
260 | regs_buff[58] = adapter->stats.mprc; |
261 | regs_buff[59] = adapter->stats.gptc; |
262 | regs_buff[60] = adapter->stats.gorc; |
263 | regs_buff[61] = adapter->stats.gotc; |
264 | regs_buff[62] = adapter->stats.rnbc; |
265 | regs_buff[63] = adapter->stats.ruc; |
266 | regs_buff[64] = adapter->stats.rfc; |
267 | regs_buff[65] = adapter->stats.roc; |
268 | regs_buff[66] = adapter->stats.rjc; |
269 | regs_buff[67] = adapter->stats.mgprc; |
270 | regs_buff[68] = adapter->stats.mgpdc; |
271 | regs_buff[69] = adapter->stats.mgptc; |
272 | regs_buff[70] = adapter->stats.tor; |
273 | regs_buff[71] = adapter->stats.tot; |
274 | regs_buff[72] = adapter->stats.tpr; |
275 | regs_buff[73] = adapter->stats.tpt; |
276 | regs_buff[74] = adapter->stats.ptc64; |
277 | regs_buff[75] = adapter->stats.ptc127; |
278 | regs_buff[76] = adapter->stats.ptc255; |
279 | regs_buff[77] = adapter->stats.ptc511; |
280 | regs_buff[78] = adapter->stats.ptc1023; |
281 | regs_buff[79] = adapter->stats.ptc1522; |
282 | regs_buff[80] = adapter->stats.mptc; |
283 | regs_buff[81] = adapter->stats.bptc; |
284 | regs_buff[82] = adapter->stats.tsctc; |
285 | regs_buff[83] = adapter->stats.iac; |
286 | regs_buff[84] = adapter->stats.rpthc; |
287 | regs_buff[85] = adapter->stats.hgptc; |
288 | regs_buff[86] = adapter->stats.hgorc; |
289 | regs_buff[87] = adapter->stats.hgotc; |
290 | regs_buff[88] = adapter->stats.lenerrs; |
291 | regs_buff[89] = adapter->stats.scvpc; |
292 | regs_buff[90] = adapter->stats.hrmpc; |
293 | |
294 | for (i = 0; i < 4; i++) |
295 | regs_buff[91 + i] = rd32(IGC_SRRCTL(i)); |
296 | for (i = 0; i < 4; i++) |
297 | regs_buff[95 + i] = rd32(IGC_PSRTYPE(i)); |
298 | for (i = 0; i < 4; i++) |
299 | regs_buff[99 + i] = rd32(IGC_RDBAL(i)); |
300 | for (i = 0; i < 4; i++) |
301 | regs_buff[103 + i] = rd32(IGC_RDBAH(i)); |
302 | for (i = 0; i < 4; i++) |
303 | regs_buff[107 + i] = rd32(IGC_RDLEN(i)); |
304 | for (i = 0; i < 4; i++) |
305 | regs_buff[111 + i] = rd32(IGC_RDH(i)); |
306 | for (i = 0; i < 4; i++) |
307 | regs_buff[115 + i] = rd32(IGC_RDT(i)); |
308 | for (i = 0; i < 4; i++) |
309 | regs_buff[119 + i] = rd32(IGC_RXDCTL(i)); |
310 | |
311 | for (i = 0; i < 10; i++) |
312 | regs_buff[123 + i] = rd32(IGC_EITR(i)); |
313 | for (i = 0; i < 16; i++) |
314 | regs_buff[139 + i] = rd32(IGC_RAL(i)); |
315 | for (i = 0; i < 16; i++) |
316 | regs_buff[145 + i] = rd32(IGC_RAH(i)); |
317 | |
318 | for (i = 0; i < 4; i++) |
319 | regs_buff[149 + i] = rd32(IGC_TDBAL(i)); |
320 | for (i = 0; i < 4; i++) |
321 | regs_buff[152 + i] = rd32(IGC_TDBAH(i)); |
322 | for (i = 0; i < 4; i++) |
323 | regs_buff[156 + i] = rd32(IGC_TDLEN(i)); |
324 | for (i = 0; i < 4; i++) |
325 | regs_buff[160 + i] = rd32(IGC_TDH(i)); |
326 | for (i = 0; i < 4; i++) |
327 | regs_buff[164 + i] = rd32(IGC_TDT(i)); |
328 | for (i = 0; i < 4; i++) |
329 | regs_buff[168 + i] = rd32(IGC_TXDCTL(i)); |
330 | |
331 | /* XXX: Due to a bug few lines above, RAL and RAH registers are |
332 | * overwritten. To preserve the ABI, we write these registers again in |
333 | * regs_buff. |
334 | */ |
335 | for (i = 0; i < 16; i++) |
336 | regs_buff[172 + i] = rd32(IGC_RAL(i)); |
337 | for (i = 0; i < 16; i++) |
338 | regs_buff[188 + i] = rd32(IGC_RAH(i)); |
339 | |
340 | regs_buff[204] = rd32(IGC_VLANPQF); |
341 | |
342 | for (i = 0; i < 8; i++) |
343 | regs_buff[205 + i] = rd32(IGC_ETQF(i)); |
344 | |
345 | regs_buff[213] = adapter->stats.tlpic; |
346 | regs_buff[214] = adapter->stats.rlpic; |
347 | } |
348 | |
349 | static void igc_ethtool_get_wol(struct net_device *netdev, |
350 | struct ethtool_wolinfo *wol) |
351 | { |
352 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
353 | |
354 | wol->wolopts = 0; |
355 | |
356 | if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) |
357 | return; |
358 | |
359 | wol->supported = WAKE_UCAST | WAKE_MCAST | |
360 | WAKE_BCAST | WAKE_MAGIC | |
361 | WAKE_PHY; |
362 | |
363 | /* apply any specific unsupported masks here */ |
364 | switch (adapter->hw.device_id) { |
365 | default: |
366 | break; |
367 | } |
368 | |
369 | if (adapter->wol & IGC_WUFC_EX) |
370 | wol->wolopts |= WAKE_UCAST; |
371 | if (adapter->wol & IGC_WUFC_MC) |
372 | wol->wolopts |= WAKE_MCAST; |
373 | if (adapter->wol & IGC_WUFC_BC) |
374 | wol->wolopts |= WAKE_BCAST; |
375 | if (adapter->wol & IGC_WUFC_MAG) |
376 | wol->wolopts |= WAKE_MAGIC; |
377 | if (adapter->wol & IGC_WUFC_LNKC) |
378 | wol->wolopts |= WAKE_PHY; |
379 | } |
380 | |
381 | static int igc_ethtool_set_wol(struct net_device *netdev, |
382 | struct ethtool_wolinfo *wol) |
383 | { |
384 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
385 | |
386 | if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER)) |
387 | return -EOPNOTSUPP; |
388 | |
389 | if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) |
390 | return wol->wolopts ? -EOPNOTSUPP : 0; |
391 | |
392 | /* these settings will always override what we currently have */ |
393 | adapter->wol = 0; |
394 | |
395 | if (wol->wolopts & WAKE_UCAST) |
396 | adapter->wol |= IGC_WUFC_EX; |
397 | if (wol->wolopts & WAKE_MCAST) |
398 | adapter->wol |= IGC_WUFC_MC; |
399 | if (wol->wolopts & WAKE_BCAST) |
400 | adapter->wol |= IGC_WUFC_BC; |
401 | if (wol->wolopts & WAKE_MAGIC) |
402 | adapter->wol |= IGC_WUFC_MAG; |
403 | if (wol->wolopts & WAKE_PHY) |
404 | adapter->wol |= IGC_WUFC_LNKC; |
405 | device_set_wakeup_enable(dev: &adapter->pdev->dev, enable: adapter->wol); |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | static u32 igc_ethtool_get_msglevel(struct net_device *netdev) |
411 | { |
412 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
413 | |
414 | return adapter->msg_enable; |
415 | } |
416 | |
417 | static void igc_ethtool_set_msglevel(struct net_device *netdev, u32 data) |
418 | { |
419 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
420 | |
421 | adapter->msg_enable = data; |
422 | } |
423 | |
424 | static int igc_ethtool_nway_reset(struct net_device *netdev) |
425 | { |
426 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
427 | |
428 | if (netif_running(dev: netdev)) |
429 | igc_reinit_locked(adapter); |
430 | return 0; |
431 | } |
432 | |
433 | static u32 igc_ethtool_get_link(struct net_device *netdev) |
434 | { |
435 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
436 | struct igc_mac_info *mac = &adapter->hw.mac; |
437 | |
438 | /* If the link is not reported up to netdev, interrupts are disabled, |
439 | * and so the physical link state may have changed since we last |
440 | * looked. Set get_link_status to make sure that the true link |
441 | * state is interrogated, rather than pulling a cached and possibly |
442 | * stale link state from the driver. |
443 | */ |
444 | if (!netif_carrier_ok(dev: netdev)) |
445 | mac->get_link_status = 1; |
446 | |
447 | return igc_has_link(adapter); |
448 | } |
449 | |
450 | static int igc_ethtool_get_eeprom_len(struct net_device *netdev) |
451 | { |
452 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
453 | |
454 | return adapter->hw.nvm.word_size * 2; |
455 | } |
456 | |
457 | static int igc_ethtool_get_eeprom(struct net_device *netdev, |
458 | struct ethtool_eeprom *eeprom, u8 *bytes) |
459 | { |
460 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
461 | struct igc_hw *hw = &adapter->hw; |
462 | int first_word, last_word; |
463 | u16 *eeprom_buff; |
464 | int ret_val = 0; |
465 | u16 i; |
466 | |
467 | if (eeprom->len == 0) |
468 | return -EINVAL; |
469 | |
470 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); |
471 | |
472 | first_word = eeprom->offset >> 1; |
473 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; |
474 | |
475 | eeprom_buff = kmalloc_array(n: last_word - first_word + 1, size: sizeof(u16), |
476 | GFP_KERNEL); |
477 | if (!eeprom_buff) |
478 | return -ENOMEM; |
479 | |
480 | if (hw->nvm.type == igc_nvm_eeprom_spi) { |
481 | ret_val = hw->nvm.ops.read(hw, first_word, |
482 | last_word - first_word + 1, |
483 | eeprom_buff); |
484 | } else { |
485 | for (i = 0; i < last_word - first_word + 1; i++) { |
486 | ret_val = hw->nvm.ops.read(hw, first_word + i, 1, |
487 | &eeprom_buff[i]); |
488 | if (ret_val) |
489 | break; |
490 | } |
491 | } |
492 | |
493 | /* Device's eeprom is always little-endian, word addressable */ |
494 | for (i = 0; i < last_word - first_word + 1; i++) |
495 | le16_to_cpus(&eeprom_buff[i]); |
496 | |
497 | memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), |
498 | eeprom->len); |
499 | kfree(objp: eeprom_buff); |
500 | |
501 | return ret_val; |
502 | } |
503 | |
504 | static int igc_ethtool_set_eeprom(struct net_device *netdev, |
505 | struct ethtool_eeprom *eeprom, u8 *bytes) |
506 | { |
507 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
508 | struct igc_hw *hw = &adapter->hw; |
509 | int max_len, first_word, last_word, ret_val = 0; |
510 | u16 *eeprom_buff; |
511 | void *ptr; |
512 | u16 i; |
513 | |
514 | if (eeprom->len == 0) |
515 | return -EOPNOTSUPP; |
516 | |
517 | if (hw->mac.type >= igc_i225 && |
518 | !igc_get_flash_presence_i225(hw)) { |
519 | return -EOPNOTSUPP; |
520 | } |
521 | |
522 | if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) |
523 | return -EFAULT; |
524 | |
525 | max_len = hw->nvm.word_size * 2; |
526 | |
527 | first_word = eeprom->offset >> 1; |
528 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; |
529 | eeprom_buff = kmalloc(size: max_len, GFP_KERNEL); |
530 | if (!eeprom_buff) |
531 | return -ENOMEM; |
532 | |
533 | ptr = (void *)eeprom_buff; |
534 | |
535 | if (eeprom->offset & 1) { |
536 | /* need read/modify/write of first changed EEPROM word |
537 | * only the second byte of the word is being modified |
538 | */ |
539 | ret_val = hw->nvm.ops.read(hw, first_word, 1, |
540 | &eeprom_buff[0]); |
541 | ptr++; |
542 | } |
543 | if (((eeprom->offset + eeprom->len) & 1) && ret_val == 0) { |
544 | /* need read/modify/write of last changed EEPROM word |
545 | * only the first byte of the word is being modified |
546 | */ |
547 | ret_val = hw->nvm.ops.read(hw, last_word, 1, |
548 | &eeprom_buff[last_word - first_word]); |
549 | } |
550 | |
551 | /* Device's eeprom is always little-endian, word addressable */ |
552 | for (i = 0; i < last_word - first_word + 1; i++) |
553 | le16_to_cpus(&eeprom_buff[i]); |
554 | |
555 | memcpy(ptr, bytes, eeprom->len); |
556 | |
557 | for (i = 0; i < last_word - first_word + 1; i++) |
558 | cpu_to_le16s(&eeprom_buff[i]); |
559 | |
560 | ret_val = hw->nvm.ops.write(hw, first_word, |
561 | last_word - first_word + 1, eeprom_buff); |
562 | |
563 | /* Update the checksum if nvm write succeeded */ |
564 | if (ret_val == 0) |
565 | hw->nvm.ops.update(hw); |
566 | |
567 | kfree(objp: eeprom_buff); |
568 | return ret_val; |
569 | } |
570 | |
571 | static void |
572 | igc_ethtool_get_ringparam(struct net_device *netdev, |
573 | struct ethtool_ringparam *ring, |
574 | struct kernel_ethtool_ringparam *kernel_ering, |
575 | struct netlink_ext_ack *extack) |
576 | { |
577 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
578 | |
579 | ring->rx_max_pending = IGC_MAX_RXD; |
580 | ring->tx_max_pending = IGC_MAX_TXD; |
581 | ring->rx_pending = adapter->rx_ring_count; |
582 | ring->tx_pending = adapter->tx_ring_count; |
583 | } |
584 | |
585 | static int |
586 | igc_ethtool_set_ringparam(struct net_device *netdev, |
587 | struct ethtool_ringparam *ring, |
588 | struct kernel_ethtool_ringparam *kernel_ering, |
589 | struct netlink_ext_ack *extack) |
590 | { |
591 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
592 | struct igc_ring *temp_ring; |
593 | u16 new_rx_count, new_tx_count; |
594 | int i, err = 0; |
595 | |
596 | if (ring->rx_mini_pending || ring->rx_jumbo_pending) |
597 | return -EINVAL; |
598 | |
599 | new_rx_count = min_t(u32, ring->rx_pending, IGC_MAX_RXD); |
600 | new_rx_count = max_t(u16, new_rx_count, IGC_MIN_RXD); |
601 | new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); |
602 | |
603 | new_tx_count = min_t(u32, ring->tx_pending, IGC_MAX_TXD); |
604 | new_tx_count = max_t(u16, new_tx_count, IGC_MIN_TXD); |
605 | new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); |
606 | |
607 | if (new_tx_count == adapter->tx_ring_count && |
608 | new_rx_count == adapter->rx_ring_count) { |
609 | /* nothing to do */ |
610 | return 0; |
611 | } |
612 | |
613 | while (test_and_set_bit(nr: __IGC_RESETTING, addr: &adapter->state)) |
614 | usleep_range(min: 1000, max: 2000); |
615 | |
616 | if (!netif_running(dev: adapter->netdev)) { |
617 | for (i = 0; i < adapter->num_tx_queues; i++) |
618 | adapter->tx_ring[i]->count = new_tx_count; |
619 | for (i = 0; i < adapter->num_rx_queues; i++) |
620 | adapter->rx_ring[i]->count = new_rx_count; |
621 | adapter->tx_ring_count = new_tx_count; |
622 | adapter->rx_ring_count = new_rx_count; |
623 | goto clear_reset; |
624 | } |
625 | |
626 | if (adapter->num_tx_queues > adapter->num_rx_queues) |
627 | temp_ring = vmalloc(array_size(sizeof(struct igc_ring), |
628 | adapter->num_tx_queues)); |
629 | else |
630 | temp_ring = vmalloc(array_size(sizeof(struct igc_ring), |
631 | adapter->num_rx_queues)); |
632 | |
633 | if (!temp_ring) { |
634 | err = -ENOMEM; |
635 | goto clear_reset; |
636 | } |
637 | |
638 | igc_down(adapter); |
639 | |
640 | /* We can't just free everything and then setup again, |
641 | * because the ISRs in MSI-X mode get passed pointers |
642 | * to the Tx and Rx ring structs. |
643 | */ |
644 | if (new_tx_count != adapter->tx_ring_count) { |
645 | for (i = 0; i < adapter->num_tx_queues; i++) { |
646 | memcpy(&temp_ring[i], adapter->tx_ring[i], |
647 | sizeof(struct igc_ring)); |
648 | |
649 | temp_ring[i].count = new_tx_count; |
650 | err = igc_setup_tx_resources(ring: &temp_ring[i]); |
651 | if (err) { |
652 | while (i) { |
653 | i--; |
654 | igc_free_tx_resources(ring: &temp_ring[i]); |
655 | } |
656 | goto err_setup; |
657 | } |
658 | } |
659 | |
660 | for (i = 0; i < adapter->num_tx_queues; i++) { |
661 | igc_free_tx_resources(ring: adapter->tx_ring[i]); |
662 | |
663 | memcpy(adapter->tx_ring[i], &temp_ring[i], |
664 | sizeof(struct igc_ring)); |
665 | } |
666 | |
667 | adapter->tx_ring_count = new_tx_count; |
668 | } |
669 | |
670 | if (new_rx_count != adapter->rx_ring_count) { |
671 | for (i = 0; i < adapter->num_rx_queues; i++) { |
672 | memcpy(&temp_ring[i], adapter->rx_ring[i], |
673 | sizeof(struct igc_ring)); |
674 | |
675 | temp_ring[i].count = new_rx_count; |
676 | err = igc_setup_rx_resources(ring: &temp_ring[i]); |
677 | if (err) { |
678 | while (i) { |
679 | i--; |
680 | igc_free_rx_resources(ring: &temp_ring[i]); |
681 | } |
682 | goto err_setup; |
683 | } |
684 | } |
685 | |
686 | for (i = 0; i < adapter->num_rx_queues; i++) { |
687 | igc_free_rx_resources(ring: adapter->rx_ring[i]); |
688 | |
689 | memcpy(adapter->rx_ring[i], &temp_ring[i], |
690 | sizeof(struct igc_ring)); |
691 | } |
692 | |
693 | adapter->rx_ring_count = new_rx_count; |
694 | } |
695 | err_setup: |
696 | igc_up(adapter); |
697 | vfree(addr: temp_ring); |
698 | clear_reset: |
699 | clear_bit(nr: __IGC_RESETTING, addr: &adapter->state); |
700 | return err; |
701 | } |
702 | |
703 | static void igc_ethtool_get_pauseparam(struct net_device *netdev, |
704 | struct ethtool_pauseparam *pause) |
705 | { |
706 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
707 | struct igc_hw *hw = &adapter->hw; |
708 | |
709 | pause->autoneg = |
710 | (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); |
711 | |
712 | if (hw->fc.current_mode == igc_fc_rx_pause) { |
713 | pause->rx_pause = 1; |
714 | } else if (hw->fc.current_mode == igc_fc_tx_pause) { |
715 | pause->tx_pause = 1; |
716 | } else if (hw->fc.current_mode == igc_fc_full) { |
717 | pause->rx_pause = 1; |
718 | pause->tx_pause = 1; |
719 | } |
720 | } |
721 | |
722 | static int igc_ethtool_set_pauseparam(struct net_device *netdev, |
723 | struct ethtool_pauseparam *pause) |
724 | { |
725 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
726 | struct igc_hw *hw = &adapter->hw; |
727 | int retval = 0; |
728 | |
729 | adapter->fc_autoneg = pause->autoneg; |
730 | |
731 | while (test_and_set_bit(nr: __IGC_RESETTING, addr: &adapter->state)) |
732 | usleep_range(min: 1000, max: 2000); |
733 | |
734 | if (adapter->fc_autoneg == AUTONEG_ENABLE) { |
735 | hw->fc.requested_mode = igc_fc_default; |
736 | if (netif_running(dev: adapter->netdev)) { |
737 | igc_down(adapter); |
738 | igc_up(adapter); |
739 | } else { |
740 | igc_reset(adapter); |
741 | } |
742 | } else { |
743 | if (pause->rx_pause && pause->tx_pause) |
744 | hw->fc.requested_mode = igc_fc_full; |
745 | else if (pause->rx_pause && !pause->tx_pause) |
746 | hw->fc.requested_mode = igc_fc_rx_pause; |
747 | else if (!pause->rx_pause && pause->tx_pause) |
748 | hw->fc.requested_mode = igc_fc_tx_pause; |
749 | else if (!pause->rx_pause && !pause->tx_pause) |
750 | hw->fc.requested_mode = igc_fc_none; |
751 | |
752 | hw->fc.current_mode = hw->fc.requested_mode; |
753 | |
754 | retval = ((hw->phy.media_type == igc_media_type_copper) ? |
755 | igc_force_mac_fc(hw) : igc_setup_link(hw)); |
756 | } |
757 | |
758 | clear_bit(nr: __IGC_RESETTING, addr: &adapter->state); |
759 | return retval; |
760 | } |
761 | |
762 | static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset, |
763 | u8 *data) |
764 | { |
765 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
766 | u8 *p = data; |
767 | int i; |
768 | |
769 | switch (stringset) { |
770 | case ETH_SS_TEST: |
771 | memcpy(data, *igc_gstrings_test, |
772 | IGC_TEST_LEN * ETH_GSTRING_LEN); |
773 | break; |
774 | case ETH_SS_STATS: |
775 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) |
776 | ethtool_sprintf(data: &p, fmt: "%s" , |
777 | igc_gstrings_stats[i].stat_string); |
778 | for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) |
779 | ethtool_sprintf(data: &p, fmt: "%s" , |
780 | igc_gstrings_net_stats[i].stat_string); |
781 | for (i = 0; i < adapter->num_tx_queues; i++) { |
782 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_packets" , i); |
783 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_bytes" , i); |
784 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_restart" , i); |
785 | } |
786 | for (i = 0; i < adapter->num_rx_queues; i++) { |
787 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_packets" , i); |
788 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_bytes" , i); |
789 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_drops" , i); |
790 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_csum_err" , i); |
791 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_alloc_failed" , i); |
792 | } |
793 | /* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */ |
794 | break; |
795 | case ETH_SS_PRIV_FLAGS: |
796 | memcpy(data, igc_priv_flags_strings, |
797 | IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); |
798 | break; |
799 | } |
800 | } |
801 | |
802 | static int igc_ethtool_get_sset_count(struct net_device *netdev, int sset) |
803 | { |
804 | switch (sset) { |
805 | case ETH_SS_STATS: |
806 | return IGC_STATS_LEN; |
807 | case ETH_SS_TEST: |
808 | return IGC_TEST_LEN; |
809 | case ETH_SS_PRIV_FLAGS: |
810 | return IGC_PRIV_FLAGS_STR_LEN; |
811 | default: |
812 | return -ENOTSUPP; |
813 | } |
814 | } |
815 | |
816 | static void igc_ethtool_get_stats(struct net_device *netdev, |
817 | struct ethtool_stats *stats, u64 *data) |
818 | { |
819 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
820 | struct rtnl_link_stats64 *net_stats = &adapter->stats64; |
821 | unsigned int start; |
822 | struct igc_ring *ring; |
823 | int i, j; |
824 | char *p; |
825 | |
826 | spin_lock(lock: &adapter->stats64_lock); |
827 | igc_update_stats(adapter); |
828 | |
829 | for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) { |
830 | p = (char *)adapter + igc_gstrings_stats[i].stat_offset; |
831 | data[i] = (igc_gstrings_stats[i].sizeof_stat == |
832 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
833 | } |
834 | for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) { |
835 | p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset; |
836 | data[i] = (igc_gstrings_net_stats[j].sizeof_stat == |
837 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
838 | } |
839 | for (j = 0; j < adapter->num_tx_queues; j++) { |
840 | u64 restart2; |
841 | |
842 | ring = adapter->tx_ring[j]; |
843 | do { |
844 | start = u64_stats_fetch_begin(syncp: &ring->tx_syncp); |
845 | data[i] = ring->tx_stats.packets; |
846 | data[i + 1] = ring->tx_stats.bytes; |
847 | data[i + 2] = ring->tx_stats.restart_queue; |
848 | } while (u64_stats_fetch_retry(syncp: &ring->tx_syncp, start)); |
849 | do { |
850 | start = u64_stats_fetch_begin(syncp: &ring->tx_syncp2); |
851 | restart2 = ring->tx_stats.restart_queue2; |
852 | } while (u64_stats_fetch_retry(syncp: &ring->tx_syncp2, start)); |
853 | data[i + 2] += restart2; |
854 | |
855 | i += IGC_TX_QUEUE_STATS_LEN; |
856 | } |
857 | for (j = 0; j < adapter->num_rx_queues; j++) { |
858 | ring = adapter->rx_ring[j]; |
859 | do { |
860 | start = u64_stats_fetch_begin(syncp: &ring->rx_syncp); |
861 | data[i] = ring->rx_stats.packets; |
862 | data[i + 1] = ring->rx_stats.bytes; |
863 | data[i + 2] = ring->rx_stats.drops; |
864 | data[i + 3] = ring->rx_stats.csum_err; |
865 | data[i + 4] = ring->rx_stats.alloc_failed; |
866 | } while (u64_stats_fetch_retry(syncp: &ring->rx_syncp, start)); |
867 | i += IGC_RX_QUEUE_STATS_LEN; |
868 | } |
869 | spin_unlock(lock: &adapter->stats64_lock); |
870 | } |
871 | |
872 | static int igc_ethtool_get_previous_rx_coalesce(struct igc_adapter *adapter) |
873 | { |
874 | return (adapter->rx_itr_setting <= 3) ? |
875 | adapter->rx_itr_setting : adapter->rx_itr_setting >> 2; |
876 | } |
877 | |
878 | static int igc_ethtool_get_previous_tx_coalesce(struct igc_adapter *adapter) |
879 | { |
880 | return (adapter->tx_itr_setting <= 3) ? |
881 | adapter->tx_itr_setting : adapter->tx_itr_setting >> 2; |
882 | } |
883 | |
884 | static int igc_ethtool_get_coalesce(struct net_device *netdev, |
885 | struct ethtool_coalesce *ec, |
886 | struct kernel_ethtool_coalesce *kernel_coal, |
887 | struct netlink_ext_ack *extack) |
888 | { |
889 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
890 | |
891 | ec->rx_coalesce_usecs = igc_ethtool_get_previous_rx_coalesce(adapter); |
892 | ec->tx_coalesce_usecs = igc_ethtool_get_previous_tx_coalesce(adapter); |
893 | |
894 | return 0; |
895 | } |
896 | |
897 | static int igc_ethtool_set_coalesce(struct net_device *netdev, |
898 | struct ethtool_coalesce *ec, |
899 | struct kernel_ethtool_coalesce *kernel_coal, |
900 | struct netlink_ext_ack *extack) |
901 | { |
902 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
903 | int i; |
904 | |
905 | if (ec->rx_coalesce_usecs > IGC_MAX_ITR_USECS || |
906 | (ec->rx_coalesce_usecs > 3 && |
907 | ec->rx_coalesce_usecs < IGC_MIN_ITR_USECS) || |
908 | ec->rx_coalesce_usecs == 2) |
909 | return -EINVAL; |
910 | |
911 | if (ec->tx_coalesce_usecs > IGC_MAX_ITR_USECS || |
912 | (ec->tx_coalesce_usecs > 3 && |
913 | ec->tx_coalesce_usecs < IGC_MIN_ITR_USECS) || |
914 | ec->tx_coalesce_usecs == 2) |
915 | return -EINVAL; |
916 | |
917 | if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) && |
918 | ec->tx_coalesce_usecs != igc_ethtool_get_previous_tx_coalesce(adapter)) { |
919 | NL_SET_ERR_MSG_MOD(extack, |
920 | "Queue Pair mode enabled, both Rx and Tx coalescing controlled by rx-usecs" ); |
921 | return -EINVAL; |
922 | } |
923 | |
924 | /* If ITR is disabled, disable DMAC */ |
925 | if (ec->rx_coalesce_usecs == 0) { |
926 | if (adapter->flags & IGC_FLAG_DMAC) |
927 | adapter->flags &= ~IGC_FLAG_DMAC; |
928 | } |
929 | |
930 | /* convert to rate of irq's per second */ |
931 | if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) |
932 | adapter->rx_itr_setting = ec->rx_coalesce_usecs; |
933 | else |
934 | adapter->rx_itr_setting = ec->rx_coalesce_usecs << 2; |
935 | |
936 | /* convert to rate of irq's per second */ |
937 | if (adapter->flags & IGC_FLAG_QUEUE_PAIRS) |
938 | adapter->tx_itr_setting = adapter->rx_itr_setting; |
939 | else if (ec->tx_coalesce_usecs && ec->tx_coalesce_usecs <= 3) |
940 | adapter->tx_itr_setting = ec->tx_coalesce_usecs; |
941 | else |
942 | adapter->tx_itr_setting = ec->tx_coalesce_usecs << 2; |
943 | |
944 | for (i = 0; i < adapter->num_q_vectors; i++) { |
945 | struct igc_q_vector *q_vector = adapter->q_vector[i]; |
946 | |
947 | q_vector->tx.work_limit = adapter->tx_work_limit; |
948 | if (q_vector->rx.ring) |
949 | q_vector->itr_val = adapter->rx_itr_setting; |
950 | else |
951 | q_vector->itr_val = adapter->tx_itr_setting; |
952 | if (q_vector->itr_val && q_vector->itr_val <= 3) |
953 | q_vector->itr_val = IGC_START_ITR; |
954 | q_vector->set_itr = 1; |
955 | } |
956 | |
957 | return 0; |
958 | } |
959 | |
960 | #define ETHER_TYPE_FULL_MASK ((__force __be16)~0) |
961 | static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, |
962 | struct ethtool_rxnfc *cmd) |
963 | { |
964 | struct ethtool_rx_flow_spec *fsp = &cmd->fs; |
965 | struct igc_nfc_rule *rule = NULL; |
966 | |
967 | cmd->data = IGC_MAX_RXNFC_RULES; |
968 | |
969 | mutex_lock(&adapter->nfc_rule_lock); |
970 | |
971 | rule = igc_get_nfc_rule(adapter, location: fsp->location); |
972 | if (!rule) |
973 | goto out; |
974 | |
975 | fsp->flow_type = ETHER_FLOW; |
976 | fsp->ring_cookie = rule->action; |
977 | |
978 | if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { |
979 | fsp->h_u.ether_spec.h_proto = htons(rule->filter.etype); |
980 | fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK; |
981 | } |
982 | |
983 | if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { |
984 | fsp->flow_type |= FLOW_EXT; |
985 | fsp->h_ext.vlan_tci = htons(rule->filter.vlan_tci); |
986 | fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK); |
987 | } |
988 | |
989 | if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { |
990 | ether_addr_copy(dst: fsp->h_u.ether_spec.h_dest, |
991 | src: rule->filter.dst_addr); |
992 | eth_broadcast_addr(addr: fsp->m_u.ether_spec.h_dest); |
993 | } |
994 | |
995 | if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { |
996 | ether_addr_copy(dst: fsp->h_u.ether_spec.h_source, |
997 | src: rule->filter.src_addr); |
998 | eth_broadcast_addr(addr: fsp->m_u.ether_spec.h_source); |
999 | } |
1000 | |
1001 | if (rule->filter.match_flags & IGC_FILTER_FLAG_USER_DATA) { |
1002 | fsp->flow_type |= FLOW_EXT; |
1003 | memcpy(fsp->h_ext.data, rule->filter.user_data, sizeof(fsp->h_ext.data)); |
1004 | memcpy(fsp->m_ext.data, rule->filter.user_mask, sizeof(fsp->m_ext.data)); |
1005 | } |
1006 | |
1007 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1008 | return 0; |
1009 | |
1010 | out: |
1011 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1012 | return -EINVAL; |
1013 | } |
1014 | |
1015 | static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, |
1016 | struct ethtool_rxnfc *cmd, |
1017 | u32 *rule_locs) |
1018 | { |
1019 | struct igc_nfc_rule *rule; |
1020 | int cnt = 0; |
1021 | |
1022 | cmd->data = IGC_MAX_RXNFC_RULES; |
1023 | |
1024 | mutex_lock(&adapter->nfc_rule_lock); |
1025 | |
1026 | list_for_each_entry(rule, &adapter->nfc_rule_list, list) { |
1027 | if (cnt == cmd->rule_cnt) { |
1028 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1029 | return -EMSGSIZE; |
1030 | } |
1031 | rule_locs[cnt] = rule->location; |
1032 | cnt++; |
1033 | } |
1034 | |
1035 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1036 | |
1037 | cmd->rule_cnt = cnt; |
1038 | |
1039 | return 0; |
1040 | } |
1041 | |
1042 | static int (struct igc_adapter *adapter, |
1043 | struct ethtool_rxnfc *cmd) |
1044 | { |
1045 | cmd->data = 0; |
1046 | |
1047 | /* Report default options for RSS on igc */ |
1048 | switch (cmd->flow_type) { |
1049 | case TCP_V4_FLOW: |
1050 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1051 | fallthrough; |
1052 | case UDP_V4_FLOW: |
1053 | if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP) |
1054 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1055 | fallthrough; |
1056 | case SCTP_V4_FLOW: |
1057 | case AH_ESP_V4_FLOW: |
1058 | case AH_V4_FLOW: |
1059 | case ESP_V4_FLOW: |
1060 | case IPV4_FLOW: |
1061 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
1062 | break; |
1063 | case TCP_V6_FLOW: |
1064 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1065 | fallthrough; |
1066 | case UDP_V6_FLOW: |
1067 | if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP) |
1068 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1069 | fallthrough; |
1070 | case SCTP_V6_FLOW: |
1071 | case AH_ESP_V6_FLOW: |
1072 | case AH_V6_FLOW: |
1073 | case ESP_V6_FLOW: |
1074 | case IPV6_FLOW: |
1075 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
1076 | break; |
1077 | default: |
1078 | return -EINVAL; |
1079 | } |
1080 | |
1081 | return 0; |
1082 | } |
1083 | |
1084 | static int igc_ethtool_get_rxnfc(struct net_device *dev, |
1085 | struct ethtool_rxnfc *cmd, u32 *rule_locs) |
1086 | { |
1087 | struct igc_adapter *adapter = netdev_priv(dev); |
1088 | |
1089 | switch (cmd->cmd) { |
1090 | case ETHTOOL_GRXRINGS: |
1091 | cmd->data = adapter->num_rx_queues; |
1092 | return 0; |
1093 | case ETHTOOL_GRXCLSRLCNT: |
1094 | cmd->rule_cnt = adapter->nfc_rule_count; |
1095 | return 0; |
1096 | case ETHTOOL_GRXCLSRULE: |
1097 | return igc_ethtool_get_nfc_rule(adapter, cmd); |
1098 | case ETHTOOL_GRXCLSRLALL: |
1099 | return igc_ethtool_get_nfc_rules(adapter, cmd, rule_locs); |
1100 | case ETHTOOL_GRXFH: |
1101 | return igc_ethtool_get_rss_hash_opts(adapter, cmd); |
1102 | default: |
1103 | return -EOPNOTSUPP; |
1104 | } |
1105 | } |
1106 | |
1107 | #define (IGC_FLAG_RSS_FIELD_IPV4_UDP | \ |
1108 | IGC_FLAG_RSS_FIELD_IPV6_UDP) |
1109 | static int (struct igc_adapter *adapter, |
1110 | struct ethtool_rxnfc *nfc) |
1111 | { |
1112 | u32 flags = adapter->flags; |
1113 | |
1114 | /* RSS does not support anything other than hashing |
1115 | * to queues on src and dst IPs and ports |
1116 | */ |
1117 | if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | |
1118 | RXH_L4_B_0_1 | RXH_L4_B_2_3)) |
1119 | return -EINVAL; |
1120 | |
1121 | switch (nfc->flow_type) { |
1122 | case TCP_V4_FLOW: |
1123 | case TCP_V6_FLOW: |
1124 | if (!(nfc->data & RXH_IP_SRC) || |
1125 | !(nfc->data & RXH_IP_DST) || |
1126 | !(nfc->data & RXH_L4_B_0_1) || |
1127 | !(nfc->data & RXH_L4_B_2_3)) |
1128 | return -EINVAL; |
1129 | break; |
1130 | case UDP_V4_FLOW: |
1131 | if (!(nfc->data & RXH_IP_SRC) || |
1132 | !(nfc->data & RXH_IP_DST)) |
1133 | return -EINVAL; |
1134 | switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { |
1135 | case 0: |
1136 | flags &= ~IGC_FLAG_RSS_FIELD_IPV4_UDP; |
1137 | break; |
1138 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
1139 | flags |= IGC_FLAG_RSS_FIELD_IPV4_UDP; |
1140 | break; |
1141 | default: |
1142 | return -EINVAL; |
1143 | } |
1144 | break; |
1145 | case UDP_V6_FLOW: |
1146 | if (!(nfc->data & RXH_IP_SRC) || |
1147 | !(nfc->data & RXH_IP_DST)) |
1148 | return -EINVAL; |
1149 | switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { |
1150 | case 0: |
1151 | flags &= ~IGC_FLAG_RSS_FIELD_IPV6_UDP; |
1152 | break; |
1153 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
1154 | flags |= IGC_FLAG_RSS_FIELD_IPV6_UDP; |
1155 | break; |
1156 | default: |
1157 | return -EINVAL; |
1158 | } |
1159 | break; |
1160 | case AH_ESP_V4_FLOW: |
1161 | case AH_V4_FLOW: |
1162 | case ESP_V4_FLOW: |
1163 | case SCTP_V4_FLOW: |
1164 | case AH_ESP_V6_FLOW: |
1165 | case AH_V6_FLOW: |
1166 | case ESP_V6_FLOW: |
1167 | case SCTP_V6_FLOW: |
1168 | if (!(nfc->data & RXH_IP_SRC) || |
1169 | !(nfc->data & RXH_IP_DST) || |
1170 | (nfc->data & RXH_L4_B_0_1) || |
1171 | (nfc->data & RXH_L4_B_2_3)) |
1172 | return -EINVAL; |
1173 | break; |
1174 | default: |
1175 | return -EINVAL; |
1176 | } |
1177 | |
1178 | /* if we changed something we need to update flags */ |
1179 | if (flags != adapter->flags) { |
1180 | struct igc_hw *hw = &adapter->hw; |
1181 | u32 mrqc = rd32(IGC_MRQC); |
1182 | |
1183 | if ((flags & UDP_RSS_FLAGS) && |
1184 | !(adapter->flags & UDP_RSS_FLAGS)) |
1185 | netdev_err(dev: adapter->netdev, |
1186 | format: "Enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n" ); |
1187 | |
1188 | adapter->flags = flags; |
1189 | |
1190 | /* Perform hash on these packet types */ |
1191 | mrqc |= IGC_MRQC_RSS_FIELD_IPV4 | |
1192 | IGC_MRQC_RSS_FIELD_IPV4_TCP | |
1193 | IGC_MRQC_RSS_FIELD_IPV6 | |
1194 | IGC_MRQC_RSS_FIELD_IPV6_TCP; |
1195 | |
1196 | mrqc &= ~(IGC_MRQC_RSS_FIELD_IPV4_UDP | |
1197 | IGC_MRQC_RSS_FIELD_IPV6_UDP); |
1198 | |
1199 | if (flags & IGC_FLAG_RSS_FIELD_IPV4_UDP) |
1200 | mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP; |
1201 | |
1202 | if (flags & IGC_FLAG_RSS_FIELD_IPV6_UDP) |
1203 | mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP; |
1204 | |
1205 | wr32(IGC_MRQC, mrqc); |
1206 | } |
1207 | |
1208 | return 0; |
1209 | } |
1210 | |
1211 | static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, |
1212 | const struct ethtool_rx_flow_spec *fsp) |
1213 | { |
1214 | INIT_LIST_HEAD(list: &rule->list); |
1215 | |
1216 | rule->action = fsp->ring_cookie; |
1217 | rule->location = fsp->location; |
1218 | |
1219 | if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { |
1220 | rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci); |
1221 | rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; |
1222 | } |
1223 | |
1224 | if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { |
1225 | rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto); |
1226 | rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; |
1227 | } |
1228 | |
1229 | /* Both source and destination address filters only support the full |
1230 | * mask. |
1231 | */ |
1232 | if (is_broadcast_ether_addr(addr: fsp->m_u.ether_spec.h_source)) { |
1233 | rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; |
1234 | ether_addr_copy(dst: rule->filter.src_addr, |
1235 | src: fsp->h_u.ether_spec.h_source); |
1236 | } |
1237 | |
1238 | if (is_broadcast_ether_addr(addr: fsp->m_u.ether_spec.h_dest)) { |
1239 | rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; |
1240 | ether_addr_copy(dst: rule->filter.dst_addr, |
1241 | src: fsp->h_u.ether_spec.h_dest); |
1242 | } |
1243 | |
1244 | /* VLAN etype matching */ |
1245 | if ((fsp->flow_type & FLOW_EXT) && fsp->h_ext.vlan_etype) { |
1246 | rule->filter.vlan_etype = fsp->h_ext.vlan_etype; |
1247 | rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_ETYPE; |
1248 | } |
1249 | |
1250 | /* Check for user defined data */ |
1251 | if ((fsp->flow_type & FLOW_EXT) && |
1252 | (fsp->h_ext.data[0] || fsp->h_ext.data[1])) { |
1253 | rule->filter.match_flags |= IGC_FILTER_FLAG_USER_DATA; |
1254 | memcpy(rule->filter.user_data, fsp->h_ext.data, sizeof(fsp->h_ext.data)); |
1255 | memcpy(rule->filter.user_mask, fsp->m_ext.data, sizeof(fsp->m_ext.data)); |
1256 | } |
1257 | |
1258 | /* When multiple filter options or user data or vlan etype is set, use a |
1259 | * flex filter. |
1260 | */ |
1261 | if ((rule->filter.match_flags & IGC_FILTER_FLAG_USER_DATA) || |
1262 | (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_ETYPE) || |
1263 | (rule->filter.match_flags & (rule->filter.match_flags - 1))) |
1264 | rule->flex = true; |
1265 | else |
1266 | rule->flex = false; |
1267 | } |
1268 | |
1269 | /** |
1270 | * igc_ethtool_check_nfc_rule() - Check if NFC rule is valid |
1271 | * @adapter: Pointer to adapter |
1272 | * @rule: Rule under evaluation |
1273 | * |
1274 | * The driver doesn't support rules with multiple matches so if more than |
1275 | * one bit in filter flags is set, @rule is considered invalid. |
1276 | * |
1277 | * Also, if there is already another rule with the same filter in a different |
1278 | * location, @rule is considered invalid. |
1279 | * |
1280 | * Context: Expects adapter->nfc_rule_lock to be held by caller. |
1281 | * |
1282 | * Return: 0 in case of success, negative errno code otherwise. |
1283 | */ |
1284 | static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter, |
1285 | struct igc_nfc_rule *rule) |
1286 | { |
1287 | struct net_device *dev = adapter->netdev; |
1288 | u8 flags = rule->filter.match_flags; |
1289 | struct igc_nfc_rule *tmp; |
1290 | |
1291 | if (!flags) { |
1292 | netdev_dbg(dev, "Rule with no match\n" ); |
1293 | return -EINVAL; |
1294 | } |
1295 | |
1296 | list_for_each_entry(tmp, &adapter->nfc_rule_list, list) { |
1297 | if (!memcmp(p: &rule->filter, q: &tmp->filter, |
1298 | size: sizeof(rule->filter)) && |
1299 | tmp->location != rule->location) { |
1300 | netdev_dbg(dev, "Rule already exists\n" ); |
1301 | return -EEXIST; |
1302 | } |
1303 | } |
1304 | |
1305 | return 0; |
1306 | } |
1307 | |
1308 | static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, |
1309 | struct ethtool_rxnfc *cmd) |
1310 | { |
1311 | struct net_device *netdev = adapter->netdev; |
1312 | struct ethtool_rx_flow_spec *fsp = |
1313 | (struct ethtool_rx_flow_spec *)&cmd->fs; |
1314 | struct igc_nfc_rule *rule, *old_rule; |
1315 | int err; |
1316 | |
1317 | if (!(netdev->hw_features & NETIF_F_NTUPLE)) { |
1318 | netdev_dbg(netdev, "N-tuple filters disabled\n" ); |
1319 | return -EOPNOTSUPP; |
1320 | } |
1321 | |
1322 | if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) { |
1323 | netdev_dbg(netdev, "Only ethernet flow type is supported\n" ); |
1324 | return -EOPNOTSUPP; |
1325 | } |
1326 | |
1327 | if (fsp->ring_cookie >= adapter->num_rx_queues) { |
1328 | netdev_dbg(netdev, "Invalid action\n" ); |
1329 | return -EINVAL; |
1330 | } |
1331 | |
1332 | if (fsp->location >= IGC_MAX_RXNFC_RULES) { |
1333 | netdev_dbg(netdev, "Invalid location\n" ); |
1334 | return -EINVAL; |
1335 | } |
1336 | |
1337 | rule = kzalloc(size: sizeof(*rule), GFP_KERNEL); |
1338 | if (!rule) |
1339 | return -ENOMEM; |
1340 | |
1341 | igc_ethtool_init_nfc_rule(rule, fsp); |
1342 | |
1343 | mutex_lock(&adapter->nfc_rule_lock); |
1344 | |
1345 | err = igc_ethtool_check_nfc_rule(adapter, rule); |
1346 | if (err) |
1347 | goto err; |
1348 | |
1349 | old_rule = igc_get_nfc_rule(adapter, location: fsp->location); |
1350 | if (old_rule) |
1351 | igc_del_nfc_rule(adapter, rule: old_rule); |
1352 | |
1353 | err = igc_add_nfc_rule(adapter, rule); |
1354 | if (err) |
1355 | goto err; |
1356 | |
1357 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1358 | return 0; |
1359 | |
1360 | err: |
1361 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1362 | kfree(objp: rule); |
1363 | return err; |
1364 | } |
1365 | |
1366 | static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter, |
1367 | struct ethtool_rxnfc *cmd) |
1368 | { |
1369 | struct ethtool_rx_flow_spec *fsp = |
1370 | (struct ethtool_rx_flow_spec *)&cmd->fs; |
1371 | struct igc_nfc_rule *rule; |
1372 | |
1373 | mutex_lock(&adapter->nfc_rule_lock); |
1374 | |
1375 | rule = igc_get_nfc_rule(adapter, location: fsp->location); |
1376 | if (!rule) { |
1377 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1378 | return -EINVAL; |
1379 | } |
1380 | |
1381 | igc_del_nfc_rule(adapter, rule); |
1382 | |
1383 | mutex_unlock(lock: &adapter->nfc_rule_lock); |
1384 | return 0; |
1385 | } |
1386 | |
1387 | static int igc_ethtool_set_rxnfc(struct net_device *dev, |
1388 | struct ethtool_rxnfc *cmd) |
1389 | { |
1390 | struct igc_adapter *adapter = netdev_priv(dev); |
1391 | |
1392 | switch (cmd->cmd) { |
1393 | case ETHTOOL_SRXFH: |
1394 | return igc_ethtool_set_rss_hash_opt(adapter, nfc: cmd); |
1395 | case ETHTOOL_SRXCLSRLINS: |
1396 | return igc_ethtool_add_nfc_rule(adapter, cmd); |
1397 | case ETHTOOL_SRXCLSRLDEL: |
1398 | return igc_ethtool_del_nfc_rule(adapter, cmd); |
1399 | default: |
1400 | return -EOPNOTSUPP; |
1401 | } |
1402 | } |
1403 | |
1404 | void (struct igc_adapter *adapter) |
1405 | { |
1406 | struct igc_hw *hw = &adapter->hw; |
1407 | u32 reg = IGC_RETA(0); |
1408 | u32 shift = 0; |
1409 | int i = 0; |
1410 | |
1411 | while (i < IGC_RETA_SIZE) { |
1412 | u32 val = 0; |
1413 | int j; |
1414 | |
1415 | for (j = 3; j >= 0; j--) { |
1416 | val <<= 8; |
1417 | val |= adapter->rss_indir_tbl[i + j]; |
1418 | } |
1419 | |
1420 | wr32(reg, val << shift); |
1421 | reg += 4; |
1422 | i += 4; |
1423 | } |
1424 | } |
1425 | |
1426 | static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev) |
1427 | { |
1428 | return IGC_RETA_SIZE; |
1429 | } |
1430 | |
1431 | static int igc_ethtool_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, |
1432 | u8 *hfunc) |
1433 | { |
1434 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1435 | int i; |
1436 | |
1437 | if (hfunc) |
1438 | *hfunc = ETH_RSS_HASH_TOP; |
1439 | if (!indir) |
1440 | return 0; |
1441 | for (i = 0; i < IGC_RETA_SIZE; i++) |
1442 | indir[i] = adapter->rss_indir_tbl[i]; |
1443 | |
1444 | return 0; |
1445 | } |
1446 | |
1447 | static int igc_ethtool_set_rxfh(struct net_device *netdev, const u32 *indir, |
1448 | const u8 *key, const u8 hfunc) |
1449 | { |
1450 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1451 | u32 num_queues; |
1452 | int i; |
1453 | |
1454 | /* We do not allow change in unsupported parameters */ |
1455 | if (key || |
1456 | (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) |
1457 | return -EOPNOTSUPP; |
1458 | if (!indir) |
1459 | return 0; |
1460 | |
1461 | num_queues = adapter->rss_queues; |
1462 | |
1463 | /* Verify user input. */ |
1464 | for (i = 0; i < IGC_RETA_SIZE; i++) |
1465 | if (indir[i] >= num_queues) |
1466 | return -EINVAL; |
1467 | |
1468 | for (i = 0; i < IGC_RETA_SIZE; i++) |
1469 | adapter->rss_indir_tbl[i] = indir[i]; |
1470 | |
1471 | igc_write_rss_indir_tbl(adapter); |
1472 | |
1473 | return 0; |
1474 | } |
1475 | |
1476 | static void igc_ethtool_get_channels(struct net_device *netdev, |
1477 | struct ethtool_channels *ch) |
1478 | { |
1479 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1480 | |
1481 | /* Report maximum channels */ |
1482 | ch->max_combined = igc_get_max_rss_queues(adapter); |
1483 | |
1484 | /* Report info for other vector */ |
1485 | if (adapter->flags & IGC_FLAG_HAS_MSIX) { |
1486 | ch->max_other = NON_Q_VECTORS; |
1487 | ch->other_count = NON_Q_VECTORS; |
1488 | } |
1489 | |
1490 | ch->combined_count = adapter->rss_queues; |
1491 | } |
1492 | |
1493 | static int igc_ethtool_set_channels(struct net_device *netdev, |
1494 | struct ethtool_channels *ch) |
1495 | { |
1496 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1497 | unsigned int count = ch->combined_count; |
1498 | unsigned int max_combined = 0; |
1499 | |
1500 | /* Verify they are not requesting separate vectors */ |
1501 | if (!count || ch->rx_count || ch->tx_count) |
1502 | return -EINVAL; |
1503 | |
1504 | /* Verify other_count is valid and has not been changed */ |
1505 | if (ch->other_count != NON_Q_VECTORS) |
1506 | return -EINVAL; |
1507 | |
1508 | /* Verify the number of channels doesn't exceed hw limits */ |
1509 | max_combined = igc_get_max_rss_queues(adapter); |
1510 | if (count > max_combined) |
1511 | return -EINVAL; |
1512 | |
1513 | if (count != adapter->rss_queues) { |
1514 | adapter->rss_queues = count; |
1515 | igc_set_flag_queue_pairs(adapter, max_rss_queues: max_combined); |
1516 | |
1517 | /* Hardware has to reinitialize queues and interrupts to |
1518 | * match the new configuration. |
1519 | */ |
1520 | return igc_reinit_queues(adapter); |
1521 | } |
1522 | |
1523 | return 0; |
1524 | } |
1525 | |
1526 | static int igc_ethtool_get_ts_info(struct net_device *dev, |
1527 | struct ethtool_ts_info *info) |
1528 | { |
1529 | struct igc_adapter *adapter = netdev_priv(dev); |
1530 | |
1531 | if (adapter->ptp_clock) |
1532 | info->phc_index = ptp_clock_index(ptp: adapter->ptp_clock); |
1533 | else |
1534 | info->phc_index = -1; |
1535 | |
1536 | switch (adapter->hw.mac.type) { |
1537 | case igc_i225: |
1538 | info->so_timestamping = |
1539 | SOF_TIMESTAMPING_TX_SOFTWARE | |
1540 | SOF_TIMESTAMPING_RX_SOFTWARE | |
1541 | SOF_TIMESTAMPING_SOFTWARE | |
1542 | SOF_TIMESTAMPING_TX_HARDWARE | |
1543 | SOF_TIMESTAMPING_RX_HARDWARE | |
1544 | SOF_TIMESTAMPING_RAW_HARDWARE; |
1545 | |
1546 | info->tx_types = |
1547 | BIT(HWTSTAMP_TX_OFF) | |
1548 | BIT(HWTSTAMP_TX_ON); |
1549 | |
1550 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); |
1551 | info->rx_filters |= BIT(HWTSTAMP_FILTER_ALL); |
1552 | |
1553 | return 0; |
1554 | default: |
1555 | return -EOPNOTSUPP; |
1556 | } |
1557 | } |
1558 | |
1559 | static u32 igc_ethtool_get_priv_flags(struct net_device *netdev) |
1560 | { |
1561 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1562 | u32 priv_flags = 0; |
1563 | |
1564 | if (adapter->flags & IGC_FLAG_RX_LEGACY) |
1565 | priv_flags |= IGC_PRIV_FLAGS_LEGACY_RX; |
1566 | |
1567 | return priv_flags; |
1568 | } |
1569 | |
1570 | static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags) |
1571 | { |
1572 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1573 | unsigned int flags = adapter->flags; |
1574 | |
1575 | flags &= ~IGC_FLAG_RX_LEGACY; |
1576 | if (priv_flags & IGC_PRIV_FLAGS_LEGACY_RX) |
1577 | flags |= IGC_FLAG_RX_LEGACY; |
1578 | |
1579 | if (flags != adapter->flags) { |
1580 | adapter->flags = flags; |
1581 | |
1582 | /* reset interface to repopulate queues */ |
1583 | if (netif_running(dev: netdev)) |
1584 | igc_reinit_locked(adapter); |
1585 | } |
1586 | |
1587 | return 0; |
1588 | } |
1589 | |
1590 | static int igc_ethtool_get_eee(struct net_device *netdev, |
1591 | struct ethtool_eee *edata) |
1592 | { |
1593 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1594 | struct igc_hw *hw = &adapter->hw; |
1595 | u32 eeer; |
1596 | |
1597 | if (hw->dev_spec._base.eee_enable) |
1598 | edata->advertised = |
1599 | mmd_eee_adv_to_ethtool_adv_t(eee_adv: adapter->eee_advert); |
1600 | |
1601 | *edata = adapter->eee; |
1602 | edata->supported = SUPPORTED_Autoneg; |
1603 | |
1604 | eeer = rd32(IGC_EEER); |
1605 | |
1606 | /* EEE status on negotiated link */ |
1607 | if (eeer & IGC_EEER_EEE_NEG) |
1608 | edata->eee_active = true; |
1609 | |
1610 | if (eeer & IGC_EEER_TX_LPI_EN) |
1611 | edata->tx_lpi_enabled = true; |
1612 | |
1613 | edata->eee_enabled = hw->dev_spec._base.eee_enable; |
1614 | |
1615 | edata->advertised = SUPPORTED_Autoneg; |
1616 | edata->lp_advertised = SUPPORTED_Autoneg; |
1617 | |
1618 | /* Report correct negotiated EEE status for devices that |
1619 | * wrongly report EEE at half-duplex |
1620 | */ |
1621 | if (adapter->link_duplex == HALF_DUPLEX) { |
1622 | edata->eee_enabled = false; |
1623 | edata->eee_active = false; |
1624 | edata->tx_lpi_enabled = false; |
1625 | edata->advertised &= ~edata->advertised; |
1626 | } |
1627 | |
1628 | return 0; |
1629 | } |
1630 | |
1631 | static int igc_ethtool_set_eee(struct net_device *netdev, |
1632 | struct ethtool_eee *edata) |
1633 | { |
1634 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1635 | struct igc_hw *hw = &adapter->hw; |
1636 | struct ethtool_eee eee_curr; |
1637 | s32 ret_val; |
1638 | |
1639 | memset(&eee_curr, 0, sizeof(struct ethtool_eee)); |
1640 | |
1641 | ret_val = igc_ethtool_get_eee(netdev, edata: &eee_curr); |
1642 | if (ret_val) { |
1643 | netdev_err(dev: netdev, |
1644 | format: "Problem setting EEE advertisement options\n" ); |
1645 | return -EINVAL; |
1646 | } |
1647 | |
1648 | if (eee_curr.eee_enabled) { |
1649 | if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) { |
1650 | netdev_err(dev: netdev, |
1651 | format: "Setting EEE tx-lpi is not supported\n" ); |
1652 | return -EINVAL; |
1653 | } |
1654 | |
1655 | /* Tx LPI timer is not implemented currently */ |
1656 | if (edata->tx_lpi_timer) { |
1657 | netdev_err(dev: netdev, |
1658 | format: "Setting EEE Tx LPI timer is not supported\n" ); |
1659 | return -EINVAL; |
1660 | } |
1661 | } else if (!edata->eee_enabled) { |
1662 | netdev_err(dev: netdev, |
1663 | format: "Setting EEE options are not supported with EEE disabled\n" ); |
1664 | return -EINVAL; |
1665 | } |
1666 | |
1667 | adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(adv: edata->advertised); |
1668 | if (hw->dev_spec._base.eee_enable != edata->eee_enabled) { |
1669 | hw->dev_spec._base.eee_enable = edata->eee_enabled; |
1670 | adapter->flags |= IGC_FLAG_EEE; |
1671 | |
1672 | /* reset link */ |
1673 | if (netif_running(dev: netdev)) |
1674 | igc_reinit_locked(adapter); |
1675 | else |
1676 | igc_reset(adapter); |
1677 | } |
1678 | |
1679 | return 0; |
1680 | } |
1681 | |
1682 | static int igc_ethtool_begin(struct net_device *netdev) |
1683 | { |
1684 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1685 | |
1686 | pm_runtime_get_sync(dev: &adapter->pdev->dev); |
1687 | return 0; |
1688 | } |
1689 | |
1690 | static void igc_ethtool_complete(struct net_device *netdev) |
1691 | { |
1692 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1693 | |
1694 | pm_runtime_put(dev: &adapter->pdev->dev); |
1695 | } |
1696 | |
1697 | static int igc_ethtool_get_link_ksettings(struct net_device *netdev, |
1698 | struct ethtool_link_ksettings *cmd) |
1699 | { |
1700 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1701 | struct igc_hw *hw = &adapter->hw; |
1702 | u32 status; |
1703 | u32 speed; |
1704 | |
1705 | ethtool_link_ksettings_zero_link_mode(cmd, supported); |
1706 | ethtool_link_ksettings_zero_link_mode(cmd, advertising); |
1707 | |
1708 | /* supported link modes */ |
1709 | ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half); |
1710 | ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full); |
1711 | ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Half); |
1712 | ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full); |
1713 | ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); |
1714 | ethtool_link_ksettings_add_link_mode(cmd, supported, 2500baseT_Full); |
1715 | |
1716 | /* twisted pair */ |
1717 | cmd->base.port = PORT_TP; |
1718 | cmd->base.phy_address = hw->phy.addr; |
1719 | ethtool_link_ksettings_add_link_mode(cmd, supported, TP); |
1720 | ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); |
1721 | |
1722 | /* advertising link modes */ |
1723 | if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF) |
1724 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); |
1725 | if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL) |
1726 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); |
1727 | if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF) |
1728 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); |
1729 | if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL) |
1730 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); |
1731 | if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL) |
1732 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); |
1733 | if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL) |
1734 | ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full); |
1735 | |
1736 | /* set autoneg settings */ |
1737 | if (hw->mac.autoneg == 1) { |
1738 | ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); |
1739 | ethtool_link_ksettings_add_link_mode(cmd, advertising, |
1740 | Autoneg); |
1741 | } |
1742 | |
1743 | /* Set pause flow control settings */ |
1744 | ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); |
1745 | |
1746 | switch (hw->fc.requested_mode) { |
1747 | case igc_fc_full: |
1748 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); |
1749 | break; |
1750 | case igc_fc_rx_pause: |
1751 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); |
1752 | ethtool_link_ksettings_add_link_mode(cmd, advertising, |
1753 | Asym_Pause); |
1754 | break; |
1755 | case igc_fc_tx_pause: |
1756 | ethtool_link_ksettings_add_link_mode(cmd, advertising, |
1757 | Asym_Pause); |
1758 | break; |
1759 | default: |
1760 | break; |
1761 | } |
1762 | |
1763 | status = pm_runtime_suspended(dev: &adapter->pdev->dev) ? |
1764 | 0 : rd32(IGC_STATUS); |
1765 | |
1766 | if (status & IGC_STATUS_LU) { |
1767 | if (status & IGC_STATUS_SPEED_1000) { |
1768 | /* For I225, STATUS will indicate 1G speed in both |
1769 | * 1 Gbps and 2.5 Gbps link modes. |
1770 | * An additional bit is used |
1771 | * to differentiate between 1 Gbps and 2.5 Gbps. |
1772 | */ |
1773 | if (hw->mac.type == igc_i225 && |
1774 | (status & IGC_STATUS_SPEED_2500)) { |
1775 | speed = SPEED_2500; |
1776 | } else { |
1777 | speed = SPEED_1000; |
1778 | } |
1779 | } else if (status & IGC_STATUS_SPEED_100) { |
1780 | speed = SPEED_100; |
1781 | } else { |
1782 | speed = SPEED_10; |
1783 | } |
1784 | if ((status & IGC_STATUS_FD) || |
1785 | hw->phy.media_type != igc_media_type_copper) |
1786 | cmd->base.duplex = DUPLEX_FULL; |
1787 | else |
1788 | cmd->base.duplex = DUPLEX_HALF; |
1789 | } else { |
1790 | speed = SPEED_UNKNOWN; |
1791 | cmd->base.duplex = DUPLEX_UNKNOWN; |
1792 | } |
1793 | cmd->base.speed = speed; |
1794 | if (hw->mac.autoneg) |
1795 | cmd->base.autoneg = AUTONEG_ENABLE; |
1796 | else |
1797 | cmd->base.autoneg = AUTONEG_DISABLE; |
1798 | |
1799 | /* MDI-X => 2; MDI =>1; Invalid =>0 */ |
1800 | if (hw->phy.media_type == igc_media_type_copper) |
1801 | cmd->base.eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : |
1802 | ETH_TP_MDI; |
1803 | else |
1804 | cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; |
1805 | |
1806 | if (hw->phy.mdix == AUTO_ALL_MODES) |
1807 | cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; |
1808 | else |
1809 | cmd->base.eth_tp_mdix_ctrl = hw->phy.mdix; |
1810 | |
1811 | return 0; |
1812 | } |
1813 | |
1814 | static int |
1815 | igc_ethtool_set_link_ksettings(struct net_device *netdev, |
1816 | const struct ethtool_link_ksettings *cmd) |
1817 | { |
1818 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1819 | struct net_device *dev = adapter->netdev; |
1820 | struct igc_hw *hw = &adapter->hw; |
1821 | u16 advertised = 0; |
1822 | |
1823 | /* When adapter in resetting mode, autoneg/speed/duplex |
1824 | * cannot be changed |
1825 | */ |
1826 | if (igc_check_reset_block(hw)) { |
1827 | netdev_err(dev, format: "Cannot change link characteristics when reset is active\n" ); |
1828 | return -EINVAL; |
1829 | } |
1830 | |
1831 | /* MDI setting is only allowed when autoneg enabled because |
1832 | * some hardware doesn't allow MDI setting when speed or |
1833 | * duplex is forced. |
1834 | */ |
1835 | if (cmd->base.eth_tp_mdix_ctrl) { |
1836 | if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO && |
1837 | cmd->base.autoneg != AUTONEG_ENABLE) { |
1838 | netdev_err(dev, format: "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n" ); |
1839 | return -EINVAL; |
1840 | } |
1841 | } |
1842 | |
1843 | while (test_and_set_bit(nr: __IGC_RESETTING, addr: &adapter->state)) |
1844 | usleep_range(min: 1000, max: 2000); |
1845 | |
1846 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1847 | 2500baseT_Full)) |
1848 | advertised |= ADVERTISE_2500_FULL; |
1849 | |
1850 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1851 | 1000baseT_Full)) |
1852 | advertised |= ADVERTISE_1000_FULL; |
1853 | |
1854 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1855 | 100baseT_Full)) |
1856 | advertised |= ADVERTISE_100_FULL; |
1857 | |
1858 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1859 | 100baseT_Half)) |
1860 | advertised |= ADVERTISE_100_HALF; |
1861 | |
1862 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1863 | 10baseT_Full)) |
1864 | advertised |= ADVERTISE_10_FULL; |
1865 | |
1866 | if (ethtool_link_ksettings_test_link_mode(cmd, advertising, |
1867 | 10baseT_Half)) |
1868 | advertised |= ADVERTISE_10_HALF; |
1869 | |
1870 | if (cmd->base.autoneg == AUTONEG_ENABLE) { |
1871 | hw->mac.autoneg = 1; |
1872 | hw->phy.autoneg_advertised = advertised; |
1873 | if (adapter->fc_autoneg) |
1874 | hw->fc.requested_mode = igc_fc_default; |
1875 | } else { |
1876 | netdev_info(dev, format: "Force mode currently not supported\n" ); |
1877 | } |
1878 | |
1879 | /* MDI-X => 2; MDI => 1; Auto => 3 */ |
1880 | if (cmd->base.eth_tp_mdix_ctrl) { |
1881 | /* fix up the value for auto (3 => 0) as zero is mapped |
1882 | * internally to auto |
1883 | */ |
1884 | if (cmd->base.eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) |
1885 | hw->phy.mdix = AUTO_ALL_MODES; |
1886 | else |
1887 | hw->phy.mdix = cmd->base.eth_tp_mdix_ctrl; |
1888 | } |
1889 | |
1890 | /* reset the link */ |
1891 | if (netif_running(dev: adapter->netdev)) { |
1892 | igc_down(adapter); |
1893 | igc_up(adapter); |
1894 | } else { |
1895 | igc_reset(adapter); |
1896 | } |
1897 | |
1898 | clear_bit(nr: __IGC_RESETTING, addr: &adapter->state); |
1899 | |
1900 | return 0; |
1901 | } |
1902 | |
1903 | static void igc_ethtool_diag_test(struct net_device *netdev, |
1904 | struct ethtool_test *eth_test, u64 *data) |
1905 | { |
1906 | struct igc_adapter *adapter = netdev_priv(dev: netdev); |
1907 | bool if_running = netif_running(dev: netdev); |
1908 | |
1909 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { |
1910 | netdev_info(dev: adapter->netdev, format: "Offline testing starting" ); |
1911 | set_bit(nr: __IGC_TESTING, addr: &adapter->state); |
1912 | |
1913 | /* Link test performed before hardware reset so autoneg doesn't |
1914 | * interfere with test result |
1915 | */ |
1916 | if (!igc_link_test(adapter, data: &data[TEST_LINK])) |
1917 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1918 | |
1919 | if (if_running) |
1920 | igc_close(netdev); |
1921 | else |
1922 | igc_reset(adapter); |
1923 | |
1924 | netdev_info(dev: adapter->netdev, format: "Register testing starting" ); |
1925 | if (!igc_reg_test(adapter, data: &data[TEST_REG])) |
1926 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1927 | |
1928 | igc_reset(adapter); |
1929 | |
1930 | netdev_info(dev: adapter->netdev, format: "EEPROM testing starting" ); |
1931 | if (!igc_eeprom_test(adapter, data: &data[TEST_EEP])) |
1932 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1933 | |
1934 | igc_reset(adapter); |
1935 | |
1936 | /* loopback and interrupt tests |
1937 | * will be implemented in the future |
1938 | */ |
1939 | data[TEST_LOOP] = 0; |
1940 | data[TEST_IRQ] = 0; |
1941 | |
1942 | clear_bit(nr: __IGC_TESTING, addr: &adapter->state); |
1943 | if (if_running) |
1944 | igc_open(netdev); |
1945 | } else { |
1946 | netdev_info(dev: adapter->netdev, format: "Online testing starting" ); |
1947 | |
1948 | /* register, eeprom, intr and loopback tests not run online */ |
1949 | data[TEST_REG] = 0; |
1950 | data[TEST_EEP] = 0; |
1951 | data[TEST_IRQ] = 0; |
1952 | data[TEST_LOOP] = 0; |
1953 | |
1954 | if (!igc_link_test(adapter, data: &data[TEST_LINK])) |
1955 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1956 | } |
1957 | |
1958 | msleep_interruptible(msecs: 4 * 1000); |
1959 | } |
1960 | |
1961 | static const struct ethtool_ops igc_ethtool_ops = { |
1962 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS, |
1963 | .get_drvinfo = igc_ethtool_get_drvinfo, |
1964 | .get_regs_len = igc_ethtool_get_regs_len, |
1965 | .get_regs = igc_ethtool_get_regs, |
1966 | .get_wol = igc_ethtool_get_wol, |
1967 | .set_wol = igc_ethtool_set_wol, |
1968 | .get_msglevel = igc_ethtool_get_msglevel, |
1969 | .set_msglevel = igc_ethtool_set_msglevel, |
1970 | .nway_reset = igc_ethtool_nway_reset, |
1971 | .get_link = igc_ethtool_get_link, |
1972 | .get_eeprom_len = igc_ethtool_get_eeprom_len, |
1973 | .get_eeprom = igc_ethtool_get_eeprom, |
1974 | .set_eeprom = igc_ethtool_set_eeprom, |
1975 | .get_ringparam = igc_ethtool_get_ringparam, |
1976 | .set_ringparam = igc_ethtool_set_ringparam, |
1977 | .get_pauseparam = igc_ethtool_get_pauseparam, |
1978 | .set_pauseparam = igc_ethtool_set_pauseparam, |
1979 | .get_strings = igc_ethtool_get_strings, |
1980 | .get_sset_count = igc_ethtool_get_sset_count, |
1981 | .get_ethtool_stats = igc_ethtool_get_stats, |
1982 | .get_coalesce = igc_ethtool_get_coalesce, |
1983 | .set_coalesce = igc_ethtool_set_coalesce, |
1984 | .get_rxnfc = igc_ethtool_get_rxnfc, |
1985 | .set_rxnfc = igc_ethtool_set_rxnfc, |
1986 | .get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size, |
1987 | .get_rxfh = igc_ethtool_get_rxfh, |
1988 | .set_rxfh = igc_ethtool_set_rxfh, |
1989 | .get_ts_info = igc_ethtool_get_ts_info, |
1990 | .get_channels = igc_ethtool_get_channels, |
1991 | .set_channels = igc_ethtool_set_channels, |
1992 | .get_priv_flags = igc_ethtool_get_priv_flags, |
1993 | .set_priv_flags = igc_ethtool_set_priv_flags, |
1994 | .get_eee = igc_ethtool_get_eee, |
1995 | .set_eee = igc_ethtool_set_eee, |
1996 | .begin = igc_ethtool_begin, |
1997 | .complete = igc_ethtool_complete, |
1998 | .get_link_ksettings = igc_ethtool_get_link_ksettings, |
1999 | .set_link_ksettings = igc_ethtool_set_link_ksettings, |
2000 | .self_test = igc_ethtool_diag_test, |
2001 | }; |
2002 | |
2003 | void igc_ethtool_set_ops(struct net_device *netdev) |
2004 | { |
2005 | netdev->ethtool_ops = &igc_ethtool_ops; |
2006 | } |
2007 | |