1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2018, Intel Corporation. */ |
3 | |
4 | /* ethtool support for ice */ |
5 | |
6 | #include "ice.h" |
7 | #include "ice_ethtool.h" |
8 | #include "ice_flow.h" |
9 | #include "ice_fltr.h" |
10 | #include "ice_lib.h" |
11 | #include "ice_dcb_lib.h" |
12 | #include <net/dcbnl.h> |
13 | |
14 | struct ice_stats { |
15 | char stat_string[ETH_GSTRING_LEN]; |
16 | int sizeof_stat; |
17 | int stat_offset; |
18 | }; |
19 | |
20 | #define ICE_STAT(_type, _name, _stat) { \ |
21 | .stat_string = _name, \ |
22 | .sizeof_stat = sizeof_field(_type, _stat), \ |
23 | .stat_offset = offsetof(_type, _stat) \ |
24 | } |
25 | |
26 | #define ICE_VSI_STAT(_name, _stat) \ |
27 | ICE_STAT(struct ice_vsi, _name, _stat) |
28 | #define ICE_PF_STAT(_name, _stat) \ |
29 | ICE_STAT(struct ice_pf, _name, _stat) |
30 | |
31 | static int ice_q_stats_len(struct net_device *netdev) |
32 | { |
33 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
34 | |
35 | return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) * |
36 | (sizeof(struct ice_q_stats) / sizeof(u64))); |
37 | } |
38 | |
39 | #define ICE_PF_STATS_LEN ARRAY_SIZE(ice_gstrings_pf_stats) |
40 | #define ICE_VSI_STATS_LEN ARRAY_SIZE(ice_gstrings_vsi_stats) |
41 | |
42 | #define ICE_PFC_STATS_LEN ( \ |
43 | (sizeof_field(struct ice_pf, stats.priority_xoff_rx) + \ |
44 | sizeof_field(struct ice_pf, stats.priority_xon_rx) + \ |
45 | sizeof_field(struct ice_pf, stats.priority_xoff_tx) + \ |
46 | sizeof_field(struct ice_pf, stats.priority_xon_tx)) \ |
47 | / sizeof(u64)) |
48 | #define ICE_ALL_STATS_LEN(n) (ICE_PF_STATS_LEN + ICE_PFC_STATS_LEN + \ |
49 | ICE_VSI_STATS_LEN + ice_q_stats_len(n)) |
50 | |
51 | static const struct ice_stats ice_gstrings_vsi_stats[] = { |
52 | ICE_VSI_STAT("rx_unicast" , eth_stats.rx_unicast), |
53 | ICE_VSI_STAT("tx_unicast" , eth_stats.tx_unicast), |
54 | ICE_VSI_STAT("rx_multicast" , eth_stats.rx_multicast), |
55 | ICE_VSI_STAT("tx_multicast" , eth_stats.tx_multicast), |
56 | ICE_VSI_STAT("rx_broadcast" , eth_stats.rx_broadcast), |
57 | ICE_VSI_STAT("tx_broadcast" , eth_stats.tx_broadcast), |
58 | ICE_VSI_STAT("rx_bytes" , eth_stats.rx_bytes), |
59 | ICE_VSI_STAT("tx_bytes" , eth_stats.tx_bytes), |
60 | ICE_VSI_STAT("rx_dropped" , eth_stats.rx_discards), |
61 | ICE_VSI_STAT("rx_unknown_protocol" , eth_stats.rx_unknown_protocol), |
62 | ICE_VSI_STAT("rx_alloc_fail" , rx_buf_failed), |
63 | ICE_VSI_STAT("rx_pg_alloc_fail" , rx_page_failed), |
64 | ICE_VSI_STAT("tx_errors" , eth_stats.tx_errors), |
65 | ICE_VSI_STAT("tx_linearize" , tx_linearize), |
66 | ICE_VSI_STAT("tx_busy" , tx_busy), |
67 | ICE_VSI_STAT("tx_restart" , tx_restart), |
68 | }; |
69 | |
70 | enum ice_ethtool_test_id { |
71 | ICE_ETH_TEST_REG = 0, |
72 | ICE_ETH_TEST_EEPROM, |
73 | ICE_ETH_TEST_INTR, |
74 | ICE_ETH_TEST_LOOP, |
75 | ICE_ETH_TEST_LINK, |
76 | }; |
77 | |
78 | static const char ice_gstrings_test[][ETH_GSTRING_LEN] = { |
79 | "Register test (offline)" , |
80 | "EEPROM test (offline)" , |
81 | "Interrupt test (offline)" , |
82 | "Loopback test (offline)" , |
83 | "Link test (on/offline)" , |
84 | }; |
85 | |
86 | #define ICE_TEST_LEN (sizeof(ice_gstrings_test) / ETH_GSTRING_LEN) |
87 | |
88 | /* These PF_STATs might look like duplicates of some NETDEV_STATs, |
89 | * but they aren't. This device is capable of supporting multiple |
90 | * VSIs/netdevs on a single PF. The NETDEV_STATs are for individual |
91 | * netdevs whereas the PF_STATs are for the physical function that's |
92 | * hosting these netdevs. |
93 | * |
94 | * The PF_STATs are appended to the netdev stats only when ethtool -S |
95 | * is queried on the base PF netdev. |
96 | */ |
97 | static const struct ice_stats ice_gstrings_pf_stats[] = { |
98 | ICE_PF_STAT("rx_bytes.nic" , stats.eth.rx_bytes), |
99 | ICE_PF_STAT("tx_bytes.nic" , stats.eth.tx_bytes), |
100 | ICE_PF_STAT("rx_unicast.nic" , stats.eth.rx_unicast), |
101 | ICE_PF_STAT("tx_unicast.nic" , stats.eth.tx_unicast), |
102 | ICE_PF_STAT("rx_multicast.nic" , stats.eth.rx_multicast), |
103 | ICE_PF_STAT("tx_multicast.nic" , stats.eth.tx_multicast), |
104 | ICE_PF_STAT("rx_broadcast.nic" , stats.eth.rx_broadcast), |
105 | ICE_PF_STAT("tx_broadcast.nic" , stats.eth.tx_broadcast), |
106 | ICE_PF_STAT("tx_errors.nic" , stats.eth.tx_errors), |
107 | ICE_PF_STAT("tx_timeout.nic" , tx_timeout_count), |
108 | ICE_PF_STAT("rx_size_64.nic" , stats.rx_size_64), |
109 | ICE_PF_STAT("tx_size_64.nic" , stats.tx_size_64), |
110 | ICE_PF_STAT("rx_size_127.nic" , stats.rx_size_127), |
111 | ICE_PF_STAT("tx_size_127.nic" , stats.tx_size_127), |
112 | ICE_PF_STAT("rx_size_255.nic" , stats.rx_size_255), |
113 | ICE_PF_STAT("tx_size_255.nic" , stats.tx_size_255), |
114 | ICE_PF_STAT("rx_size_511.nic" , stats.rx_size_511), |
115 | ICE_PF_STAT("tx_size_511.nic" , stats.tx_size_511), |
116 | ICE_PF_STAT("rx_size_1023.nic" , stats.rx_size_1023), |
117 | ICE_PF_STAT("tx_size_1023.nic" , stats.tx_size_1023), |
118 | ICE_PF_STAT("rx_size_1522.nic" , stats.rx_size_1522), |
119 | ICE_PF_STAT("tx_size_1522.nic" , stats.tx_size_1522), |
120 | ICE_PF_STAT("rx_size_big.nic" , stats.rx_size_big), |
121 | ICE_PF_STAT("tx_size_big.nic" , stats.tx_size_big), |
122 | ICE_PF_STAT("link_xon_rx.nic" , stats.link_xon_rx), |
123 | ICE_PF_STAT("link_xon_tx.nic" , stats.link_xon_tx), |
124 | ICE_PF_STAT("link_xoff_rx.nic" , stats.link_xoff_rx), |
125 | ICE_PF_STAT("link_xoff_tx.nic" , stats.link_xoff_tx), |
126 | ICE_PF_STAT("tx_dropped_link_down.nic" , stats.tx_dropped_link_down), |
127 | ICE_PF_STAT("rx_undersize.nic" , stats.rx_undersize), |
128 | ICE_PF_STAT("rx_fragments.nic" , stats.rx_fragments), |
129 | ICE_PF_STAT("rx_oversize.nic" , stats.rx_oversize), |
130 | ICE_PF_STAT("rx_jabber.nic" , stats.rx_jabber), |
131 | ICE_PF_STAT("rx_csum_bad.nic" , hw_csum_rx_error), |
132 | ICE_PF_STAT("rx_eipe_error.nic" , hw_rx_eipe_error), |
133 | ICE_PF_STAT("rx_dropped.nic" , stats.eth.rx_discards), |
134 | ICE_PF_STAT("rx_crc_errors.nic" , stats.crc_errors), |
135 | ICE_PF_STAT("illegal_bytes.nic" , stats.illegal_bytes), |
136 | ICE_PF_STAT("mac_local_faults.nic" , stats.mac_local_faults), |
137 | ICE_PF_STAT("mac_remote_faults.nic" , stats.mac_remote_faults), |
138 | ICE_PF_STAT("fdir_sb_match.nic" , stats.fd_sb_match), |
139 | ICE_PF_STAT("fdir_sb_status.nic" , stats.fd_sb_status), |
140 | ICE_PF_STAT("tx_hwtstamp_skipped" , ptp.tx_hwtstamp_skipped), |
141 | ICE_PF_STAT("tx_hwtstamp_timeouts" , ptp.tx_hwtstamp_timeouts), |
142 | ICE_PF_STAT("tx_hwtstamp_flushed" , ptp.tx_hwtstamp_flushed), |
143 | ICE_PF_STAT("tx_hwtstamp_discarded" , ptp.tx_hwtstamp_discarded), |
144 | ICE_PF_STAT("late_cached_phc_updates" , ptp.late_cached_phc_updates), |
145 | }; |
146 | |
147 | static const u32 ice_regs_dump_list[] = { |
148 | PFGEN_STATE, |
149 | PRTGEN_STATUS, |
150 | QRX_CTRL(0), |
151 | QINT_TQCTL(0), |
152 | QINT_RQCTL(0), |
153 | PFINT_OICR_ENA, |
154 | QRX_ITR(0), |
155 | #define GLDCB_TLPM_PCI_DM 0x000A0180 |
156 | GLDCB_TLPM_PCI_DM, |
157 | #define GLDCB_TLPM_TC2PFC 0x000A0194 |
158 | GLDCB_TLPM_TC2PFC, |
159 | #define TCDCB_TLPM_WAIT_DM(_i) (0x000A0080 + ((_i) * 4)) |
160 | TCDCB_TLPM_WAIT_DM(0), |
161 | TCDCB_TLPM_WAIT_DM(1), |
162 | TCDCB_TLPM_WAIT_DM(2), |
163 | TCDCB_TLPM_WAIT_DM(3), |
164 | TCDCB_TLPM_WAIT_DM(4), |
165 | TCDCB_TLPM_WAIT_DM(5), |
166 | TCDCB_TLPM_WAIT_DM(6), |
167 | TCDCB_TLPM_WAIT_DM(7), |
168 | TCDCB_TLPM_WAIT_DM(8), |
169 | TCDCB_TLPM_WAIT_DM(9), |
170 | TCDCB_TLPM_WAIT_DM(10), |
171 | TCDCB_TLPM_WAIT_DM(11), |
172 | TCDCB_TLPM_WAIT_DM(12), |
173 | TCDCB_TLPM_WAIT_DM(13), |
174 | TCDCB_TLPM_WAIT_DM(14), |
175 | TCDCB_TLPM_WAIT_DM(15), |
176 | TCDCB_TLPM_WAIT_DM(16), |
177 | TCDCB_TLPM_WAIT_DM(17), |
178 | TCDCB_TLPM_WAIT_DM(18), |
179 | TCDCB_TLPM_WAIT_DM(19), |
180 | TCDCB_TLPM_WAIT_DM(20), |
181 | TCDCB_TLPM_WAIT_DM(21), |
182 | TCDCB_TLPM_WAIT_DM(22), |
183 | TCDCB_TLPM_WAIT_DM(23), |
184 | TCDCB_TLPM_WAIT_DM(24), |
185 | TCDCB_TLPM_WAIT_DM(25), |
186 | TCDCB_TLPM_WAIT_DM(26), |
187 | TCDCB_TLPM_WAIT_DM(27), |
188 | TCDCB_TLPM_WAIT_DM(28), |
189 | TCDCB_TLPM_WAIT_DM(29), |
190 | TCDCB_TLPM_WAIT_DM(30), |
191 | TCDCB_TLPM_WAIT_DM(31), |
192 | #define GLPCI_WATMK_CLNT_PIPEMON 0x000BFD90 |
193 | GLPCI_WATMK_CLNT_PIPEMON, |
194 | #define GLPCI_CUR_CLNT_COMMON 0x000BFD84 |
195 | GLPCI_CUR_CLNT_COMMON, |
196 | #define GLPCI_CUR_CLNT_PIPEMON 0x000BFD88 |
197 | GLPCI_CUR_CLNT_PIPEMON, |
198 | #define GLPCI_PCIERR 0x0009DEB0 |
199 | GLPCI_PCIERR, |
200 | #define GLPSM_DEBUG_CTL_STATUS 0x000B0600 |
201 | GLPSM_DEBUG_CTL_STATUS, |
202 | #define GLPSM0_DEBUG_FIFO_OVERFLOW_DETECT 0x000B0680 |
203 | GLPSM0_DEBUG_FIFO_OVERFLOW_DETECT, |
204 | #define GLPSM0_DEBUG_FIFO_UNDERFLOW_DETECT 0x000B0684 |
205 | GLPSM0_DEBUG_FIFO_UNDERFLOW_DETECT, |
206 | #define GLPSM0_DEBUG_DT_OUT_OF_WINDOW 0x000B0688 |
207 | GLPSM0_DEBUG_DT_OUT_OF_WINDOW, |
208 | #define GLPSM0_DEBUG_INTF_HW_ERROR_DETECT 0x000B069C |
209 | GLPSM0_DEBUG_INTF_HW_ERROR_DETECT, |
210 | #define GLPSM0_DEBUG_MISC_HW_ERROR_DETECT 0x000B06A0 |
211 | GLPSM0_DEBUG_MISC_HW_ERROR_DETECT, |
212 | #define GLPSM1_DEBUG_FIFO_OVERFLOW_DETECT 0x000B0E80 |
213 | GLPSM1_DEBUG_FIFO_OVERFLOW_DETECT, |
214 | #define GLPSM1_DEBUG_FIFO_UNDERFLOW_DETECT 0x000B0E84 |
215 | GLPSM1_DEBUG_FIFO_UNDERFLOW_DETECT, |
216 | #define GLPSM1_DEBUG_SRL_FIFO_OVERFLOW_DETECT 0x000B0E88 |
217 | GLPSM1_DEBUG_SRL_FIFO_OVERFLOW_DETECT, |
218 | #define GLPSM1_DEBUG_SRL_FIFO_UNDERFLOW_DETECT 0x000B0E8C |
219 | GLPSM1_DEBUG_SRL_FIFO_UNDERFLOW_DETECT, |
220 | #define GLPSM1_DEBUG_MISC_HW_ERROR_DETECT 0x000B0E90 |
221 | GLPSM1_DEBUG_MISC_HW_ERROR_DETECT, |
222 | #define GLPSM2_DEBUG_FIFO_OVERFLOW_DETECT 0x000B1680 |
223 | GLPSM2_DEBUG_FIFO_OVERFLOW_DETECT, |
224 | #define GLPSM2_DEBUG_FIFO_UNDERFLOW_DETECT 0x000B1684 |
225 | GLPSM2_DEBUG_FIFO_UNDERFLOW_DETECT, |
226 | #define GLPSM2_DEBUG_MISC_HW_ERROR_DETECT 0x000B1688 |
227 | GLPSM2_DEBUG_MISC_HW_ERROR_DETECT, |
228 | #define GLTDPU_TCLAN_COMP_BOB(_i) (0x00049ADC + ((_i) * 4)) |
229 | GLTDPU_TCLAN_COMP_BOB(1), |
230 | GLTDPU_TCLAN_COMP_BOB(2), |
231 | GLTDPU_TCLAN_COMP_BOB(3), |
232 | GLTDPU_TCLAN_COMP_BOB(4), |
233 | GLTDPU_TCLAN_COMP_BOB(5), |
234 | GLTDPU_TCLAN_COMP_BOB(6), |
235 | GLTDPU_TCLAN_COMP_BOB(7), |
236 | GLTDPU_TCLAN_COMP_BOB(8), |
237 | #define GLTDPU_TCB_CMD_BOB(_i) (0x0004975C + ((_i) * 4)) |
238 | GLTDPU_TCB_CMD_BOB(1), |
239 | GLTDPU_TCB_CMD_BOB(2), |
240 | GLTDPU_TCB_CMD_BOB(3), |
241 | GLTDPU_TCB_CMD_BOB(4), |
242 | GLTDPU_TCB_CMD_BOB(5), |
243 | GLTDPU_TCB_CMD_BOB(6), |
244 | GLTDPU_TCB_CMD_BOB(7), |
245 | GLTDPU_TCB_CMD_BOB(8), |
246 | #define GLTDPU_PSM_UPDATE_BOB(_i) (0x00049B5C + ((_i) * 4)) |
247 | GLTDPU_PSM_UPDATE_BOB(1), |
248 | GLTDPU_PSM_UPDATE_BOB(2), |
249 | GLTDPU_PSM_UPDATE_BOB(3), |
250 | GLTDPU_PSM_UPDATE_BOB(4), |
251 | GLTDPU_PSM_UPDATE_BOB(5), |
252 | GLTDPU_PSM_UPDATE_BOB(6), |
253 | GLTDPU_PSM_UPDATE_BOB(7), |
254 | GLTDPU_PSM_UPDATE_BOB(8), |
255 | #define GLTCB_CMD_IN_BOB(_i) (0x000AE288 + ((_i) * 4)) |
256 | GLTCB_CMD_IN_BOB(1), |
257 | GLTCB_CMD_IN_BOB(2), |
258 | GLTCB_CMD_IN_BOB(3), |
259 | GLTCB_CMD_IN_BOB(4), |
260 | GLTCB_CMD_IN_BOB(5), |
261 | GLTCB_CMD_IN_BOB(6), |
262 | GLTCB_CMD_IN_BOB(7), |
263 | GLTCB_CMD_IN_BOB(8), |
264 | #define GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(_i) (0x000FC148 + ((_i) * 4)) |
265 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(1), |
266 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(2), |
267 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(3), |
268 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(4), |
269 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(5), |
270 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(6), |
271 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(7), |
272 | GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(8), |
273 | #define GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(_i) (0x000FC248 + ((_i) * 4)) |
274 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(1), |
275 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(2), |
276 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(3), |
277 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(4), |
278 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(5), |
279 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(6), |
280 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(7), |
281 | GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(8), |
282 | #define GLLAN_TCLAN_CACHE_CTL_BOB_CTL(_i) (0x000FC1C8 + ((_i) * 4)) |
283 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(1), |
284 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(2), |
285 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(3), |
286 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(4), |
287 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(5), |
288 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(6), |
289 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(7), |
290 | GLLAN_TCLAN_CACHE_CTL_BOB_CTL(8), |
291 | #define GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(_i) (0x000FC188 + ((_i) * 4)) |
292 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(1), |
293 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(2), |
294 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(3), |
295 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(4), |
296 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(5), |
297 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(6), |
298 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(7), |
299 | GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(8), |
300 | #define GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(_i) (0x000FC288 + ((_i) * 4)) |
301 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(1), |
302 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(2), |
303 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(3), |
304 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(4), |
305 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(5), |
306 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(6), |
307 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(7), |
308 | GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(8), |
309 | #define PRTDCB_TCUPM_REG_CM(_i) (0x000BC360 + ((_i) * 4)) |
310 | PRTDCB_TCUPM_REG_CM(0), |
311 | PRTDCB_TCUPM_REG_CM(1), |
312 | PRTDCB_TCUPM_REG_CM(2), |
313 | PRTDCB_TCUPM_REG_CM(3), |
314 | #define PRTDCB_TCUPM_REG_DM(_i) (0x000BC3A0 + ((_i) * 4)) |
315 | PRTDCB_TCUPM_REG_DM(0), |
316 | PRTDCB_TCUPM_REG_DM(1), |
317 | PRTDCB_TCUPM_REG_DM(2), |
318 | PRTDCB_TCUPM_REG_DM(3), |
319 | #define PRTDCB_TLPM_REG_DM(_i) (0x000A0000 + ((_i) * 4)) |
320 | PRTDCB_TLPM_REG_DM(0), |
321 | PRTDCB_TLPM_REG_DM(1), |
322 | PRTDCB_TLPM_REG_DM(2), |
323 | PRTDCB_TLPM_REG_DM(3), |
324 | }; |
325 | |
326 | struct ice_priv_flag { |
327 | char name[ETH_GSTRING_LEN]; |
328 | u32 bitno; /* bit position in pf->flags */ |
329 | }; |
330 | |
331 | #define ICE_PRIV_FLAG(_name, _bitno) { \ |
332 | .name = _name, \ |
333 | .bitno = _bitno, \ |
334 | } |
335 | |
336 | static const struct ice_priv_flag ice_gstrings_priv_flags[] = { |
337 | ICE_PRIV_FLAG("link-down-on-close" , ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA), |
338 | ICE_PRIV_FLAG("fw-lldp-agent" , ICE_FLAG_FW_LLDP_AGENT), |
339 | ICE_PRIV_FLAG("vf-true-promisc-support" , |
340 | ICE_FLAG_VF_TRUE_PROMISC_ENA), |
341 | ICE_PRIV_FLAG("mdd-auto-reset-vf" , ICE_FLAG_MDD_AUTO_RESET_VF), |
342 | ICE_PRIV_FLAG("vf-vlan-pruning" , ICE_FLAG_VF_VLAN_PRUNING), |
343 | ICE_PRIV_FLAG("legacy-rx" , ICE_FLAG_LEGACY_RX), |
344 | }; |
345 | |
346 | #define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags) |
347 | |
348 | static const u32 ice_adv_lnk_speed_100[] __initconst = { |
349 | ETHTOOL_LINK_MODE_100baseT_Full_BIT, |
350 | }; |
351 | |
352 | static const u32 ice_adv_lnk_speed_1000[] __initconst = { |
353 | ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
354 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
355 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, |
356 | }; |
357 | |
358 | static const u32 ice_adv_lnk_speed_2500[] __initconst = { |
359 | ETHTOOL_LINK_MODE_2500baseT_Full_BIT, |
360 | ETHTOOL_LINK_MODE_2500baseX_Full_BIT, |
361 | }; |
362 | |
363 | static const u32 ice_adv_lnk_speed_5000[] __initconst = { |
364 | ETHTOOL_LINK_MODE_5000baseT_Full_BIT, |
365 | }; |
366 | |
367 | static const u32 ice_adv_lnk_speed_10000[] __initconst = { |
368 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
369 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, |
370 | ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, |
371 | ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, |
372 | }; |
373 | |
374 | static const u32 ice_adv_lnk_speed_25000[] __initconst = { |
375 | ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, |
376 | ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, |
377 | ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, |
378 | }; |
379 | |
380 | static const u32 ice_adv_lnk_speed_40000[] __initconst = { |
381 | ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, |
382 | ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, |
383 | ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, |
384 | ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, |
385 | }; |
386 | |
387 | static const u32 ice_adv_lnk_speed_50000[] __initconst = { |
388 | ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, |
389 | ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, |
390 | ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, |
391 | }; |
392 | |
393 | static const u32 ice_adv_lnk_speed_100000[] __initconst = { |
394 | ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, |
395 | ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, |
396 | ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, |
397 | ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, |
398 | ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, |
399 | ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, |
400 | ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, |
401 | }; |
402 | |
403 | static const u32 ice_adv_lnk_speed_200000[] __initconst = { |
404 | ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, |
405 | ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, |
406 | ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, |
407 | ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, |
408 | ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, |
409 | }; |
410 | |
411 | static struct ethtool_forced_speed_map ice_adv_lnk_speed_maps[] __ro_after_init = { |
412 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 100), |
413 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 1000), |
414 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 2500), |
415 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 5000), |
416 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 10000), |
417 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 25000), |
418 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 40000), |
419 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 50000), |
420 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 100000), |
421 | ETHTOOL_FORCED_SPEED_MAP(ice_adv_lnk_speed, 200000), |
422 | }; |
423 | |
424 | void __init ice_adv_lnk_speed_maps_init(void) |
425 | { |
426 | ethtool_forced_speed_maps_init(maps: ice_adv_lnk_speed_maps, |
427 | ARRAY_SIZE(ice_adv_lnk_speed_maps)); |
428 | } |
429 | |
430 | static void |
431 | __ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo, |
432 | struct ice_vsi *vsi) |
433 | { |
434 | struct ice_pf *pf = vsi->back; |
435 | struct ice_hw *hw = &pf->hw; |
436 | struct ice_orom_info *orom; |
437 | struct ice_nvm_info *nvm; |
438 | |
439 | nvm = &hw->flash.nvm; |
440 | orom = &hw->flash.orom; |
441 | |
442 | strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); |
443 | |
444 | /* Display NVM version (from which the firmware version can be |
445 | * determined) which contains more pertinent information. |
446 | */ |
447 | snprintf(buf: drvinfo->fw_version, size: sizeof(drvinfo->fw_version), |
448 | fmt: "%x.%02x 0x%x %d.%d.%d" , nvm->major, nvm->minor, |
449 | nvm->eetrack, orom->major, orom->build, orom->patch); |
450 | |
451 | strscpy(drvinfo->bus_info, pci_name(pf->pdev), |
452 | sizeof(drvinfo->bus_info)); |
453 | } |
454 | |
455 | static void |
456 | ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) |
457 | { |
458 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
459 | |
460 | __ice_get_drvinfo(netdev, drvinfo, vsi: np->vsi); |
461 | drvinfo->n_priv_flags = ICE_PRIV_FLAG_ARRAY_SIZE; |
462 | } |
463 | |
464 | static int ice_get_regs_len(struct net_device __always_unused *netdev) |
465 | { |
466 | return sizeof(ice_regs_dump_list); |
467 | } |
468 | |
469 | static void |
470 | ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) |
471 | { |
472 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
473 | struct ice_pf *pf = np->vsi->back; |
474 | struct ice_hw *hw = &pf->hw; |
475 | u32 *regs_buf = (u32 *)p; |
476 | unsigned int i; |
477 | |
478 | regs->version = 1; |
479 | |
480 | for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i) |
481 | regs_buf[i] = rd32(hw, ice_regs_dump_list[i]); |
482 | } |
483 | |
484 | static u32 ice_get_msglevel(struct net_device *netdev) |
485 | { |
486 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
487 | struct ice_pf *pf = np->vsi->back; |
488 | |
489 | #ifndef CONFIG_DYNAMIC_DEBUG |
490 | if (pf->hw.debug_mask) |
491 | netdev_info(netdev, "hw debug_mask: 0x%llX\n" , |
492 | pf->hw.debug_mask); |
493 | #endif /* !CONFIG_DYNAMIC_DEBUG */ |
494 | |
495 | return pf->msg_enable; |
496 | } |
497 | |
498 | static void ice_set_msglevel(struct net_device *netdev, u32 data) |
499 | { |
500 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
501 | struct ice_pf *pf = np->vsi->back; |
502 | |
503 | #ifndef CONFIG_DYNAMIC_DEBUG |
504 | if (ICE_DBG_USER & data) |
505 | pf->hw.debug_mask = data; |
506 | else |
507 | pf->msg_enable = data; |
508 | #else |
509 | pf->msg_enable = data; |
510 | #endif /* !CONFIG_DYNAMIC_DEBUG */ |
511 | } |
512 | |
513 | static int ice_get_eeprom_len(struct net_device *netdev) |
514 | { |
515 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
516 | struct ice_pf *pf = np->vsi->back; |
517 | |
518 | return (int)pf->hw.flash.flash_size; |
519 | } |
520 | |
521 | static int |
522 | ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, |
523 | u8 *bytes) |
524 | { |
525 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
526 | struct ice_vsi *vsi = np->vsi; |
527 | struct ice_pf *pf = vsi->back; |
528 | struct ice_hw *hw = &pf->hw; |
529 | struct device *dev; |
530 | int ret; |
531 | u8 *buf; |
532 | |
533 | dev = ice_pf_to_dev(pf); |
534 | |
535 | eeprom->magic = hw->vendor_id | (hw->device_id << 16); |
536 | netdev_dbg(netdev, "GEEPROM cmd 0x%08x, offset 0x%08x, len 0x%08x\n" , |
537 | eeprom->cmd, eeprom->offset, eeprom->len); |
538 | |
539 | buf = kzalloc(size: eeprom->len, GFP_KERNEL); |
540 | if (!buf) |
541 | return -ENOMEM; |
542 | |
543 | ret = ice_acquire_nvm(hw, access: ICE_RES_READ); |
544 | if (ret) { |
545 | dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %s\n" , |
546 | ret, ice_aq_str(hw->adminq.sq_last_status)); |
547 | goto out; |
548 | } |
549 | |
550 | ret = ice_read_flat_nvm(hw, offset: eeprom->offset, length: &eeprom->len, data: buf, |
551 | read_shadow_ram: false); |
552 | if (ret) { |
553 | dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n" , |
554 | ret, ice_aq_str(hw->adminq.sq_last_status)); |
555 | goto release; |
556 | } |
557 | |
558 | memcpy(bytes, buf, eeprom->len); |
559 | release: |
560 | ice_release_nvm(hw); |
561 | out: |
562 | kfree(objp: buf); |
563 | return ret; |
564 | } |
565 | |
566 | /** |
567 | * ice_active_vfs - check if there are any active VFs |
568 | * @pf: board private structure |
569 | * |
570 | * Returns true if an active VF is found, otherwise returns false |
571 | */ |
572 | static bool ice_active_vfs(struct ice_pf *pf) |
573 | { |
574 | bool active = false; |
575 | struct ice_vf *vf; |
576 | unsigned int bkt; |
577 | |
578 | rcu_read_lock(); |
579 | ice_for_each_vf_rcu(pf, bkt, vf) { |
580 | if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { |
581 | active = true; |
582 | break; |
583 | } |
584 | } |
585 | rcu_read_unlock(); |
586 | |
587 | return active; |
588 | } |
589 | |
590 | /** |
591 | * ice_link_test - perform a link test on a given net_device |
592 | * @netdev: network interface device structure |
593 | * |
594 | * This function performs one of the self-tests required by ethtool. |
595 | * Returns 0 on success, non-zero on failure. |
596 | */ |
597 | static u64 ice_link_test(struct net_device *netdev) |
598 | { |
599 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
600 | bool link_up = false; |
601 | int status; |
602 | |
603 | netdev_info(dev: netdev, format: "link test\n" ); |
604 | status = ice_get_link_status(pi: np->vsi->port_info, link_up: &link_up); |
605 | if (status) { |
606 | netdev_err(dev: netdev, format: "link query error, status = %d\n" , |
607 | status); |
608 | return 1; |
609 | } |
610 | |
611 | if (!link_up) |
612 | return 2; |
613 | |
614 | return 0; |
615 | } |
616 | |
617 | /** |
618 | * ice_eeprom_test - perform an EEPROM test on a given net_device |
619 | * @netdev: network interface device structure |
620 | * |
621 | * This function performs one of the self-tests required by ethtool. |
622 | * Returns 0 on success, non-zero on failure. |
623 | */ |
624 | static u64 ice_eeprom_test(struct net_device *netdev) |
625 | { |
626 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
627 | struct ice_pf *pf = np->vsi->back; |
628 | |
629 | netdev_info(dev: netdev, format: "EEPROM test\n" ); |
630 | return !!(ice_nvm_validate_checksum(hw: &pf->hw)); |
631 | } |
632 | |
633 | /** |
634 | * ice_reg_pattern_test |
635 | * @hw: pointer to the HW struct |
636 | * @reg: reg to be tested |
637 | * @mask: bits to be touched |
638 | */ |
639 | static int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask) |
640 | { |
641 | struct ice_pf *pf = (struct ice_pf *)hw->back; |
642 | struct device *dev = ice_pf_to_dev(pf); |
643 | static const u32 patterns[] = { |
644 | 0x5A5A5A5A, 0xA5A5A5A5, |
645 | 0x00000000, 0xFFFFFFFF |
646 | }; |
647 | u32 val, orig_val; |
648 | unsigned int i; |
649 | |
650 | orig_val = rd32(hw, reg); |
651 | for (i = 0; i < ARRAY_SIZE(patterns); ++i) { |
652 | u32 pattern = patterns[i] & mask; |
653 | |
654 | wr32(hw, reg, pattern); |
655 | val = rd32(hw, reg); |
656 | if (val == pattern) |
657 | continue; |
658 | dev_err(dev, "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n" |
659 | , __func__, reg, pattern, val); |
660 | return 1; |
661 | } |
662 | |
663 | wr32(hw, reg, orig_val); |
664 | val = rd32(hw, reg); |
665 | if (val != orig_val) { |
666 | dev_err(dev, "%s: reg restore test failed - reg 0x%08x orig 0x%08x val 0x%08x\n" |
667 | , __func__, reg, orig_val, val); |
668 | return 1; |
669 | } |
670 | |
671 | return 0; |
672 | } |
673 | |
674 | /** |
675 | * ice_reg_test - perform a register test on a given net_device |
676 | * @netdev: network interface device structure |
677 | * |
678 | * This function performs one of the self-tests required by ethtool. |
679 | * Returns 0 on success, non-zero on failure. |
680 | */ |
681 | static u64 ice_reg_test(struct net_device *netdev) |
682 | { |
683 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
684 | struct ice_hw *hw = np->vsi->port_info->hw; |
685 | u32 int_elements = hw->func_caps.common_cap.num_msix_vectors ? |
686 | hw->func_caps.common_cap.num_msix_vectors - 1 : 1; |
687 | struct ice_diag_reg_test_info { |
688 | u32 address; |
689 | u32 mask; |
690 | u32 elem_num; |
691 | u32 elem_size; |
692 | } ice_reg_list[] = { |
693 | {GLINT_ITR(0, 0), 0x00000fff, int_elements, |
694 | GLINT_ITR(0, 1) - GLINT_ITR(0, 0)}, |
695 | {GLINT_ITR(1, 0), 0x00000fff, int_elements, |
696 | GLINT_ITR(1, 1) - GLINT_ITR(1, 0)}, |
697 | {GLINT_ITR(0, 0), 0x00000fff, int_elements, |
698 | GLINT_ITR(2, 1) - GLINT_ITR(2, 0)}, |
699 | {GLINT_CTL, 0xffff0001, 1, 0} |
700 | }; |
701 | unsigned int i; |
702 | |
703 | netdev_dbg(netdev, "Register test\n" ); |
704 | for (i = 0; i < ARRAY_SIZE(ice_reg_list); ++i) { |
705 | u32 j; |
706 | |
707 | for (j = 0; j < ice_reg_list[i].elem_num; ++j) { |
708 | u32 mask = ice_reg_list[i].mask; |
709 | u32 reg = ice_reg_list[i].address + |
710 | (j * ice_reg_list[i].elem_size); |
711 | |
712 | /* bail on failure (non-zero return) */ |
713 | if (ice_reg_pattern_test(hw, reg, mask)) |
714 | return 1; |
715 | } |
716 | } |
717 | |
718 | return 0; |
719 | } |
720 | |
721 | /** |
722 | * ice_lbtest_prepare_rings - configure Tx/Rx test rings |
723 | * @vsi: pointer to the VSI structure |
724 | * |
725 | * Function configures rings of a VSI for loopback test without |
726 | * enabling interrupts or informing the kernel about new queues. |
727 | * |
728 | * Returns 0 on success, negative on failure. |
729 | */ |
730 | static int ice_lbtest_prepare_rings(struct ice_vsi *vsi) |
731 | { |
732 | int status; |
733 | |
734 | status = ice_vsi_setup_tx_rings(vsi); |
735 | if (status) |
736 | goto err_setup_tx_ring; |
737 | |
738 | status = ice_vsi_setup_rx_rings(vsi); |
739 | if (status) |
740 | goto err_setup_rx_ring; |
741 | |
742 | status = ice_vsi_cfg_lan(vsi); |
743 | if (status) |
744 | goto err_setup_rx_ring; |
745 | |
746 | status = ice_vsi_start_all_rx_rings(vsi); |
747 | if (status) |
748 | goto err_start_rx_ring; |
749 | |
750 | return 0; |
751 | |
752 | err_start_rx_ring: |
753 | ice_vsi_free_rx_rings(vsi); |
754 | err_setup_rx_ring: |
755 | ice_vsi_stop_lan_tx_rings(vsi, rst_src: ICE_NO_RESET, rel_vmvf_num: 0); |
756 | err_setup_tx_ring: |
757 | ice_vsi_free_tx_rings(vsi); |
758 | |
759 | return status; |
760 | } |
761 | |
762 | /** |
763 | * ice_lbtest_disable_rings - disable Tx/Rx test rings after loopback test |
764 | * @vsi: pointer to the VSI structure |
765 | * |
766 | * Function stops and frees VSI rings after a loopback test. |
767 | * Returns 0 on success, negative on failure. |
768 | */ |
769 | static int ice_lbtest_disable_rings(struct ice_vsi *vsi) |
770 | { |
771 | int status; |
772 | |
773 | status = ice_vsi_stop_lan_tx_rings(vsi, rst_src: ICE_NO_RESET, rel_vmvf_num: 0); |
774 | if (status) |
775 | netdev_err(dev: vsi->netdev, format: "Failed to stop Tx rings, VSI %d error %d\n" , |
776 | vsi->vsi_num, status); |
777 | |
778 | status = ice_vsi_stop_all_rx_rings(vsi); |
779 | if (status) |
780 | netdev_err(dev: vsi->netdev, format: "Failed to stop Rx rings, VSI %d error %d\n" , |
781 | vsi->vsi_num, status); |
782 | |
783 | ice_vsi_free_tx_rings(vsi); |
784 | ice_vsi_free_rx_rings(vsi); |
785 | |
786 | return status; |
787 | } |
788 | |
789 | /** |
790 | * ice_lbtest_create_frame - create test packet |
791 | * @pf: pointer to the PF structure |
792 | * @ret_data: allocated frame buffer |
793 | * @size: size of the packet data |
794 | * |
795 | * Function allocates a frame with a test pattern on specific offsets. |
796 | * Returns 0 on success, non-zero on failure. |
797 | */ |
798 | static int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size) |
799 | { |
800 | u8 *data; |
801 | |
802 | if (!pf) |
803 | return -EINVAL; |
804 | |
805 | data = kzalloc(size, GFP_KERNEL); |
806 | if (!data) |
807 | return -ENOMEM; |
808 | |
809 | /* Since the ethernet test frame should always be at least |
810 | * 64 bytes long, fill some octets in the payload with test data. |
811 | */ |
812 | memset(data, 0xFF, size); |
813 | data[32] = 0xDE; |
814 | data[42] = 0xAD; |
815 | data[44] = 0xBE; |
816 | data[46] = 0xEF; |
817 | |
818 | *ret_data = data; |
819 | |
820 | return 0; |
821 | } |
822 | |
823 | /** |
824 | * ice_lbtest_check_frame - verify received loopback frame |
825 | * @frame: pointer to the raw packet data |
826 | * |
827 | * Function verifies received test frame with a pattern. |
828 | * Returns true if frame matches the pattern, false otherwise. |
829 | */ |
830 | static bool ice_lbtest_check_frame(u8 *frame) |
831 | { |
832 | /* Validate bytes of a frame under offsets chosen earlier */ |
833 | if (frame[32] == 0xDE && |
834 | frame[42] == 0xAD && |
835 | frame[44] == 0xBE && |
836 | frame[46] == 0xEF && |
837 | frame[48] == 0xFF) |
838 | return true; |
839 | |
840 | return false; |
841 | } |
842 | |
843 | /** |
844 | * ice_diag_send - send test frames to the test ring |
845 | * @tx_ring: pointer to the transmit ring |
846 | * @data: pointer to the raw packet data |
847 | * @size: size of the packet to send |
848 | * |
849 | * Function sends loopback packets on a test Tx ring. |
850 | */ |
851 | static int ice_diag_send(struct ice_tx_ring *tx_ring, u8 *data, u16 size) |
852 | { |
853 | struct ice_tx_desc *tx_desc; |
854 | struct ice_tx_buf *tx_buf; |
855 | dma_addr_t dma; |
856 | u64 td_cmd; |
857 | |
858 | tx_desc = ICE_TX_DESC(tx_ring, tx_ring->next_to_use); |
859 | tx_buf = &tx_ring->tx_buf[tx_ring->next_to_use]; |
860 | |
861 | dma = dma_map_single(tx_ring->dev, data, size, DMA_TO_DEVICE); |
862 | if (dma_mapping_error(dev: tx_ring->dev, dma_addr: dma)) |
863 | return -EINVAL; |
864 | |
865 | tx_desc->buf_addr = cpu_to_le64(dma); |
866 | |
867 | /* These flags are required for a descriptor to be pushed out */ |
868 | td_cmd = (u64)(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS); |
869 | tx_desc->cmd_type_offset_bsz = |
870 | cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | |
871 | (td_cmd << ICE_TXD_QW1_CMD_S) | |
872 | ((u64)0 << ICE_TXD_QW1_OFFSET_S) | |
873 | ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | |
874 | ((u64)0 << ICE_TXD_QW1_L2TAG1_S)); |
875 | |
876 | tx_buf->next_to_watch = tx_desc; |
877 | |
878 | /* Force memory write to complete before letting h/w know |
879 | * there are new descriptors to fetch. |
880 | */ |
881 | wmb(); |
882 | |
883 | tx_ring->next_to_use++; |
884 | if (tx_ring->next_to_use >= tx_ring->count) |
885 | tx_ring->next_to_use = 0; |
886 | |
887 | writel_relaxed(tx_ring->next_to_use, tx_ring->tail); |
888 | |
889 | /* Wait until the packets get transmitted to the receive queue. */ |
890 | usleep_range(min: 1000, max: 2000); |
891 | dma_unmap_single(tx_ring->dev, dma, size, DMA_TO_DEVICE); |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | #define ICE_LB_FRAME_SIZE 64 |
897 | /** |
898 | * ice_lbtest_receive_frames - receive and verify test frames |
899 | * @rx_ring: pointer to the receive ring |
900 | * |
901 | * Function receives loopback packets and verify their correctness. |
902 | * Returns number of received valid frames. |
903 | */ |
904 | static int ice_lbtest_receive_frames(struct ice_rx_ring *rx_ring) |
905 | { |
906 | struct ice_rx_buf *rx_buf; |
907 | int valid_frames, i; |
908 | u8 *received_buf; |
909 | |
910 | valid_frames = 0; |
911 | |
912 | for (i = 0; i < rx_ring->count; i++) { |
913 | union ice_32b_rx_flex_desc *rx_desc; |
914 | |
915 | rx_desc = ICE_RX_DESC(rx_ring, i); |
916 | |
917 | if (!(rx_desc->wb.status_error0 & |
918 | (cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) | |
919 | cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S))))) |
920 | continue; |
921 | |
922 | rx_buf = &rx_ring->rx_buf[i]; |
923 | received_buf = page_address(rx_buf->page) + rx_buf->page_offset; |
924 | |
925 | if (ice_lbtest_check_frame(frame: received_buf)) |
926 | valid_frames++; |
927 | } |
928 | |
929 | return valid_frames; |
930 | } |
931 | |
932 | /** |
933 | * ice_loopback_test - perform a loopback test on a given net_device |
934 | * @netdev: network interface device structure |
935 | * |
936 | * This function performs one of the self-tests required by ethtool. |
937 | * Returns 0 on success, non-zero on failure. |
938 | */ |
939 | static u64 ice_loopback_test(struct net_device *netdev) |
940 | { |
941 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
942 | struct ice_vsi *orig_vsi = np->vsi, *test_vsi; |
943 | struct ice_pf *pf = orig_vsi->back; |
944 | u8 *tx_frame __free(kfree) = NULL; |
945 | u8 broadcast[ETH_ALEN], ret = 0; |
946 | int num_frames, valid_frames; |
947 | struct ice_tx_ring *tx_ring; |
948 | struct ice_rx_ring *rx_ring; |
949 | int i; |
950 | |
951 | netdev_info(dev: netdev, format: "loopback test\n" ); |
952 | |
953 | test_vsi = ice_lb_vsi_setup(pf, pi: pf->hw.port_info); |
954 | if (!test_vsi) { |
955 | netdev_err(dev: netdev, format: "Failed to create a VSI for the loopback test\n" ); |
956 | return 1; |
957 | } |
958 | |
959 | test_vsi->netdev = netdev; |
960 | tx_ring = test_vsi->tx_rings[0]; |
961 | rx_ring = test_vsi->rx_rings[0]; |
962 | |
963 | if (ice_lbtest_prepare_rings(vsi: test_vsi)) { |
964 | ret = 2; |
965 | goto lbtest_vsi_close; |
966 | } |
967 | |
968 | if (ice_alloc_rx_bufs(rxr: rx_ring, cleaned_count: rx_ring->count)) { |
969 | ret = 3; |
970 | goto lbtest_rings_dis; |
971 | } |
972 | |
973 | /* Enable MAC loopback in firmware */ |
974 | if (ice_aq_set_mac_loopback(hw: &pf->hw, ena_lpbk: true, NULL)) { |
975 | ret = 4; |
976 | goto lbtest_mac_dis; |
977 | } |
978 | |
979 | /* Test VSI needs to receive broadcast packets */ |
980 | eth_broadcast_addr(addr: broadcast); |
981 | if (ice_fltr_add_mac(vsi: test_vsi, mac: broadcast, action: ICE_FWD_TO_VSI)) { |
982 | ret = 5; |
983 | goto lbtest_mac_dis; |
984 | } |
985 | |
986 | if (ice_lbtest_create_frame(pf, ret_data: &tx_frame, ICE_LB_FRAME_SIZE)) { |
987 | ret = 7; |
988 | goto remove_mac_filters; |
989 | } |
990 | |
991 | num_frames = min_t(int, tx_ring->count, 32); |
992 | for (i = 0; i < num_frames; i++) { |
993 | if (ice_diag_send(tx_ring, data: tx_frame, ICE_LB_FRAME_SIZE)) { |
994 | ret = 8; |
995 | goto remove_mac_filters; |
996 | } |
997 | } |
998 | |
999 | valid_frames = ice_lbtest_receive_frames(rx_ring); |
1000 | if (!valid_frames) |
1001 | ret = 9; |
1002 | else if (valid_frames != num_frames) |
1003 | ret = 10; |
1004 | |
1005 | remove_mac_filters: |
1006 | if (ice_fltr_remove_mac(vsi: test_vsi, mac: broadcast, action: ICE_FWD_TO_VSI)) |
1007 | netdev_err(dev: netdev, format: "Could not remove MAC filter for the test VSI\n" ); |
1008 | lbtest_mac_dis: |
1009 | /* Disable MAC loopback after the test is completed. */ |
1010 | if (ice_aq_set_mac_loopback(hw: &pf->hw, ena_lpbk: false, NULL)) |
1011 | netdev_err(dev: netdev, format: "Could not disable MAC loopback\n" ); |
1012 | lbtest_rings_dis: |
1013 | if (ice_lbtest_disable_rings(vsi: test_vsi)) |
1014 | netdev_err(dev: netdev, format: "Could not disable test rings\n" ); |
1015 | lbtest_vsi_close: |
1016 | test_vsi->netdev = NULL; |
1017 | if (ice_vsi_release(vsi: test_vsi)) |
1018 | netdev_err(dev: netdev, format: "Failed to remove the test VSI\n" ); |
1019 | |
1020 | return ret; |
1021 | } |
1022 | |
1023 | /** |
1024 | * ice_intr_test - perform an interrupt test on a given net_device |
1025 | * @netdev: network interface device structure |
1026 | * |
1027 | * This function performs one of the self-tests required by ethtool. |
1028 | * Returns 0 on success, non-zero on failure. |
1029 | */ |
1030 | static u64 ice_intr_test(struct net_device *netdev) |
1031 | { |
1032 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1033 | struct ice_pf *pf = np->vsi->back; |
1034 | u16 swic_old = pf->sw_int_count; |
1035 | |
1036 | netdev_info(dev: netdev, format: "interrupt test\n" ); |
1037 | |
1038 | wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_irq.index), |
1039 | GLINT_DYN_CTL_SW_ITR_INDX_M | |
1040 | GLINT_DYN_CTL_INTENA_MSK_M | |
1041 | GLINT_DYN_CTL_SWINT_TRIG_M); |
1042 | |
1043 | usleep_range(min: 1000, max: 2000); |
1044 | return (swic_old == pf->sw_int_count); |
1045 | } |
1046 | |
1047 | /** |
1048 | * ice_self_test - handler function for performing a self-test by ethtool |
1049 | * @netdev: network interface device structure |
1050 | * @eth_test: ethtool_test structure |
1051 | * @data: required by ethtool.self_test |
1052 | * |
1053 | * This function is called after invoking 'ethtool -t devname' command where |
1054 | * devname is the name of the network device on which ethtool should operate. |
1055 | * It performs a set of self-tests to check if a device works properly. |
1056 | */ |
1057 | static void |
1058 | ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, |
1059 | u64 *data) |
1060 | { |
1061 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1062 | bool if_running = netif_running(dev: netdev); |
1063 | struct ice_pf *pf = np->vsi->back; |
1064 | struct device *dev; |
1065 | |
1066 | dev = ice_pf_to_dev(pf); |
1067 | |
1068 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { |
1069 | netdev_info(dev: netdev, format: "offline testing starting\n" ); |
1070 | |
1071 | set_bit(nr: ICE_TESTING, addr: pf->state); |
1072 | |
1073 | if (ice_active_vfs(pf)) { |
1074 | dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n" ); |
1075 | data[ICE_ETH_TEST_REG] = 1; |
1076 | data[ICE_ETH_TEST_EEPROM] = 1; |
1077 | data[ICE_ETH_TEST_INTR] = 1; |
1078 | data[ICE_ETH_TEST_LOOP] = 1; |
1079 | data[ICE_ETH_TEST_LINK] = 1; |
1080 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1081 | clear_bit(nr: ICE_TESTING, addr: pf->state); |
1082 | goto skip_ol_tests; |
1083 | } |
1084 | /* If the device is online then take it offline */ |
1085 | if (if_running) |
1086 | /* indicate we're in test mode */ |
1087 | ice_stop(netdev); |
1088 | |
1089 | data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); |
1090 | data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev); |
1091 | data[ICE_ETH_TEST_INTR] = ice_intr_test(netdev); |
1092 | data[ICE_ETH_TEST_LOOP] = ice_loopback_test(netdev); |
1093 | data[ICE_ETH_TEST_REG] = ice_reg_test(netdev); |
1094 | |
1095 | if (data[ICE_ETH_TEST_LINK] || |
1096 | data[ICE_ETH_TEST_EEPROM] || |
1097 | data[ICE_ETH_TEST_LOOP] || |
1098 | data[ICE_ETH_TEST_INTR] || |
1099 | data[ICE_ETH_TEST_REG]) |
1100 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1101 | |
1102 | clear_bit(nr: ICE_TESTING, addr: pf->state); |
1103 | |
1104 | if (if_running) { |
1105 | int status = ice_open(netdev); |
1106 | |
1107 | if (status) { |
1108 | dev_err(dev, "Could not open device %s, err %d\n" , |
1109 | pf->int_name, status); |
1110 | } |
1111 | } |
1112 | } else { |
1113 | /* Online tests */ |
1114 | netdev_info(dev: netdev, format: "online testing starting\n" ); |
1115 | |
1116 | data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); |
1117 | if (data[ICE_ETH_TEST_LINK]) |
1118 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1119 | |
1120 | /* Offline only tests, not run in online; pass by default */ |
1121 | data[ICE_ETH_TEST_REG] = 0; |
1122 | data[ICE_ETH_TEST_EEPROM] = 0; |
1123 | data[ICE_ETH_TEST_INTR] = 0; |
1124 | data[ICE_ETH_TEST_LOOP] = 0; |
1125 | } |
1126 | |
1127 | skip_ol_tests: |
1128 | netdev_info(dev: netdev, format: "testing finished\n" ); |
1129 | } |
1130 | |
1131 | static void |
1132 | __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data, |
1133 | struct ice_vsi *vsi) |
1134 | { |
1135 | unsigned int i; |
1136 | u8 *p = data; |
1137 | |
1138 | switch (stringset) { |
1139 | case ETH_SS_STATS: |
1140 | for (i = 0; i < ICE_VSI_STATS_LEN; i++) |
1141 | ethtool_puts(data: &p, str: ice_gstrings_vsi_stats[i].stat_string); |
1142 | |
1143 | if (ice_is_port_repr_netdev(netdev)) |
1144 | return; |
1145 | |
1146 | ice_for_each_alloc_txq(vsi, i) { |
1147 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_packets" , i); |
1148 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_bytes" , i); |
1149 | } |
1150 | |
1151 | ice_for_each_alloc_rxq(vsi, i) { |
1152 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_packets" , i); |
1153 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_bytes" , i); |
1154 | } |
1155 | |
1156 | if (vsi->type != ICE_VSI_PF) |
1157 | return; |
1158 | |
1159 | for (i = 0; i < ICE_PF_STATS_LEN; i++) |
1160 | ethtool_puts(data: &p, str: ice_gstrings_pf_stats[i].stat_string); |
1161 | |
1162 | for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { |
1163 | ethtool_sprintf(data: &p, fmt: "tx_priority_%u_xon.nic" , i); |
1164 | ethtool_sprintf(data: &p, fmt: "tx_priority_%u_xoff.nic" , i); |
1165 | } |
1166 | for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { |
1167 | ethtool_sprintf(data: &p, fmt: "rx_priority_%u_xon.nic" , i); |
1168 | ethtool_sprintf(data: &p, fmt: "rx_priority_%u_xoff.nic" , i); |
1169 | } |
1170 | break; |
1171 | case ETH_SS_TEST: |
1172 | memcpy(data, ice_gstrings_test, ICE_TEST_LEN * ETH_GSTRING_LEN); |
1173 | break; |
1174 | case ETH_SS_PRIV_FLAGS: |
1175 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) |
1176 | ethtool_puts(data: &p, str: ice_gstrings_priv_flags[i].name); |
1177 | break; |
1178 | default: |
1179 | break; |
1180 | } |
1181 | } |
1182 | |
1183 | static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
1184 | { |
1185 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1186 | |
1187 | __ice_get_strings(netdev, stringset, data, vsi: np->vsi); |
1188 | } |
1189 | |
1190 | static int |
1191 | ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) |
1192 | { |
1193 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1194 | bool led_active; |
1195 | |
1196 | switch (state) { |
1197 | case ETHTOOL_ID_ACTIVE: |
1198 | led_active = true; |
1199 | break; |
1200 | case ETHTOOL_ID_INACTIVE: |
1201 | led_active = false; |
1202 | break; |
1203 | default: |
1204 | return -EINVAL; |
1205 | } |
1206 | |
1207 | if (ice_aq_set_port_id_led(pi: np->vsi->port_info, is_orig_mode: !led_active, NULL)) |
1208 | return -EIO; |
1209 | |
1210 | return 0; |
1211 | } |
1212 | |
1213 | /** |
1214 | * ice_set_fec_cfg - Set link FEC options |
1215 | * @netdev: network interface device structure |
1216 | * @req_fec: FEC mode to configure |
1217 | */ |
1218 | static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) |
1219 | { |
1220 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1221 | struct ice_aqc_set_phy_cfg_data config = { 0 }; |
1222 | struct ice_vsi *vsi = np->vsi; |
1223 | struct ice_port_info *pi; |
1224 | |
1225 | pi = vsi->port_info; |
1226 | if (!pi) |
1227 | return -EOPNOTSUPP; |
1228 | |
1229 | /* Changing the FEC parameters is not supported if not the PF VSI */ |
1230 | if (vsi->type != ICE_VSI_PF) { |
1231 | netdev_info(dev: netdev, format: "Changing FEC parameters only supported for PF VSI\n" ); |
1232 | return -EOPNOTSUPP; |
1233 | } |
1234 | |
1235 | /* Proceed only if requesting different FEC mode */ |
1236 | if (pi->phy.curr_user_fec_req == req_fec) |
1237 | return 0; |
1238 | |
1239 | /* Copy the current user PHY configuration. The current user PHY |
1240 | * configuration is initialized during probe from PHY capabilities |
1241 | * software mode, and updated on set PHY configuration. |
1242 | */ |
1243 | memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config)); |
1244 | |
1245 | ice_cfg_phy_fec(pi, cfg: &config, fec: req_fec); |
1246 | config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
1247 | |
1248 | if (ice_aq_set_phy_cfg(hw: pi->hw, pi, cfg: &config, NULL)) |
1249 | return -EAGAIN; |
1250 | |
1251 | /* Save requested FEC config */ |
1252 | pi->phy.curr_user_fec_req = req_fec; |
1253 | |
1254 | return 0; |
1255 | } |
1256 | |
1257 | /** |
1258 | * ice_set_fecparam - Set FEC link options |
1259 | * @netdev: network interface device structure |
1260 | * @fecparam: Ethtool structure to retrieve FEC parameters |
1261 | */ |
1262 | static int |
1263 | ice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) |
1264 | { |
1265 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1266 | struct ice_vsi *vsi = np->vsi; |
1267 | enum ice_fec_mode fec; |
1268 | |
1269 | switch (fecparam->fec) { |
1270 | case ETHTOOL_FEC_AUTO: |
1271 | fec = ICE_FEC_AUTO; |
1272 | break; |
1273 | case ETHTOOL_FEC_RS: |
1274 | fec = ICE_FEC_RS; |
1275 | break; |
1276 | case ETHTOOL_FEC_BASER: |
1277 | fec = ICE_FEC_BASER; |
1278 | break; |
1279 | case ETHTOOL_FEC_OFF: |
1280 | case ETHTOOL_FEC_NONE: |
1281 | fec = ICE_FEC_NONE; |
1282 | break; |
1283 | default: |
1284 | dev_warn(ice_pf_to_dev(vsi->back), "Unsupported FEC mode: %d\n" , |
1285 | fecparam->fec); |
1286 | return -EINVAL; |
1287 | } |
1288 | |
1289 | return ice_set_fec_cfg(netdev, req_fec: fec); |
1290 | } |
1291 | |
1292 | /** |
1293 | * ice_get_fecparam - Get link FEC options |
1294 | * @netdev: network interface device structure |
1295 | * @fecparam: Ethtool structure to retrieve FEC parameters |
1296 | */ |
1297 | static int |
1298 | ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) |
1299 | { |
1300 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1301 | struct ice_aqc_get_phy_caps_data *caps; |
1302 | struct ice_link_status *link_info; |
1303 | struct ice_vsi *vsi = np->vsi; |
1304 | struct ice_port_info *pi; |
1305 | int err; |
1306 | |
1307 | pi = vsi->port_info; |
1308 | |
1309 | if (!pi) |
1310 | return -EOPNOTSUPP; |
1311 | link_info = &pi->phy.link_info; |
1312 | |
1313 | /* Set FEC mode based on negotiated link info */ |
1314 | switch (link_info->fec_info) { |
1315 | case ICE_AQ_LINK_25G_KR_FEC_EN: |
1316 | fecparam->active_fec = ETHTOOL_FEC_BASER; |
1317 | break; |
1318 | case ICE_AQ_LINK_25G_RS_528_FEC_EN: |
1319 | case ICE_AQ_LINK_25G_RS_544_FEC_EN: |
1320 | fecparam->active_fec = ETHTOOL_FEC_RS; |
1321 | break; |
1322 | default: |
1323 | fecparam->active_fec = ETHTOOL_FEC_OFF; |
1324 | break; |
1325 | } |
1326 | |
1327 | caps = kzalloc(size: sizeof(*caps), GFP_KERNEL); |
1328 | if (!caps) |
1329 | return -ENOMEM; |
1330 | |
1331 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, |
1332 | caps, NULL); |
1333 | if (err) |
1334 | goto done; |
1335 | |
1336 | /* Set supported/configured FEC modes based on PHY capability */ |
1337 | if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC) |
1338 | fecparam->fec |= ETHTOOL_FEC_AUTO; |
1339 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || |
1340 | caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || |
1341 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN || |
1342 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) |
1343 | fecparam->fec |= ETHTOOL_FEC_BASER; |
1344 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || |
1345 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ || |
1346 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) |
1347 | fecparam->fec |= ETHTOOL_FEC_RS; |
1348 | if (caps->link_fec_options == 0) |
1349 | fecparam->fec |= ETHTOOL_FEC_OFF; |
1350 | |
1351 | done: |
1352 | kfree(objp: caps); |
1353 | return err; |
1354 | } |
1355 | |
1356 | /** |
1357 | * ice_nway_reset - restart autonegotiation |
1358 | * @netdev: network interface device structure |
1359 | */ |
1360 | static int ice_nway_reset(struct net_device *netdev) |
1361 | { |
1362 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1363 | struct ice_vsi *vsi = np->vsi; |
1364 | int err; |
1365 | |
1366 | /* If VSI state is up, then restart autoneg with link up */ |
1367 | if (!test_bit(ICE_DOWN, vsi->back->state)) |
1368 | err = ice_set_link(vsi, ena: true); |
1369 | else |
1370 | err = ice_set_link(vsi, ena: false); |
1371 | |
1372 | return err; |
1373 | } |
1374 | |
1375 | /** |
1376 | * ice_get_priv_flags - report device private flags |
1377 | * @netdev: network interface device structure |
1378 | * |
1379 | * The get string set count and the string set should be matched for each |
1380 | * flag returned. Add new strings for each flag to the ice_gstrings_priv_flags |
1381 | * array. |
1382 | * |
1383 | * Returns a u32 bitmap of flags. |
1384 | */ |
1385 | static u32 ice_get_priv_flags(struct net_device *netdev) |
1386 | { |
1387 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1388 | struct ice_vsi *vsi = np->vsi; |
1389 | struct ice_pf *pf = vsi->back; |
1390 | u32 i, ret_flags = 0; |
1391 | |
1392 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { |
1393 | const struct ice_priv_flag *priv_flag; |
1394 | |
1395 | priv_flag = &ice_gstrings_priv_flags[i]; |
1396 | |
1397 | if (test_bit(priv_flag->bitno, pf->flags)) |
1398 | ret_flags |= BIT(i); |
1399 | } |
1400 | |
1401 | return ret_flags; |
1402 | } |
1403 | |
1404 | /** |
1405 | * ice_set_priv_flags - set private flags |
1406 | * @netdev: network interface device structure |
1407 | * @flags: bit flags to be set |
1408 | */ |
1409 | static int ice_set_priv_flags(struct net_device *netdev, u32 flags) |
1410 | { |
1411 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1412 | DECLARE_BITMAP(change_flags, ICE_PF_FLAGS_NBITS); |
1413 | DECLARE_BITMAP(orig_flags, ICE_PF_FLAGS_NBITS); |
1414 | struct ice_vsi *vsi = np->vsi; |
1415 | struct ice_pf *pf = vsi->back; |
1416 | struct device *dev; |
1417 | int ret = 0; |
1418 | u32 i; |
1419 | |
1420 | if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE)) |
1421 | return -EINVAL; |
1422 | |
1423 | dev = ice_pf_to_dev(pf); |
1424 | set_bit(nr: ICE_FLAG_ETHTOOL_CTXT, addr: pf->flags); |
1425 | |
1426 | bitmap_copy(dst: orig_flags, src: pf->flags, nbits: ICE_PF_FLAGS_NBITS); |
1427 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { |
1428 | const struct ice_priv_flag *priv_flag; |
1429 | |
1430 | priv_flag = &ice_gstrings_priv_flags[i]; |
1431 | |
1432 | if (flags & BIT(i)) |
1433 | set_bit(nr: priv_flag->bitno, addr: pf->flags); |
1434 | else |
1435 | clear_bit(nr: priv_flag->bitno, addr: pf->flags); |
1436 | } |
1437 | |
1438 | bitmap_xor(dst: change_flags, src1: pf->flags, src2: orig_flags, nbits: ICE_PF_FLAGS_NBITS); |
1439 | |
1440 | /* Do not allow change to link-down-on-close when Total Port Shutdown |
1441 | * is enabled. |
1442 | */ |
1443 | if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, change_flags) && |
1444 | test_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) { |
1445 | dev_err(dev, "Setting link-down-on-close not supported on this port\n" ); |
1446 | set_bit(nr: ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, addr: pf->flags); |
1447 | ret = -EINVAL; |
1448 | goto ethtool_exit; |
1449 | } |
1450 | |
1451 | if (test_bit(ICE_FLAG_FW_LLDP_AGENT, change_flags)) { |
1452 | if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) { |
1453 | int status; |
1454 | |
1455 | /* Disable FW LLDP engine */ |
1456 | status = ice_cfg_lldp_mib_change(hw: &pf->hw, ena_mib: false); |
1457 | |
1458 | /* If unregistering for LLDP events fails, this is |
1459 | * not an error state, as there shouldn't be any |
1460 | * events to respond to. |
1461 | */ |
1462 | if (status) |
1463 | dev_info(dev, "Failed to unreg for LLDP events\n" ); |
1464 | |
1465 | /* The AQ call to stop the FW LLDP agent will generate |
1466 | * an error if the agent is already stopped. |
1467 | */ |
1468 | status = ice_aq_stop_lldp(hw: &pf->hw, shutdown_lldp_agent: true, persist: true, NULL); |
1469 | if (status) |
1470 | dev_warn(dev, "Fail to stop LLDP agent\n" ); |
1471 | /* Use case for having the FW LLDP agent stopped |
1472 | * will likely not need DCB, so failure to init is |
1473 | * not a concern of ethtool |
1474 | */ |
1475 | status = ice_init_pf_dcb(pf, locked: true); |
1476 | if (status) |
1477 | dev_warn(dev, "Fail to init DCB\n" ); |
1478 | |
1479 | pf->dcbx_cap &= ~DCB_CAP_DCBX_LLD_MANAGED; |
1480 | pf->dcbx_cap |= DCB_CAP_DCBX_HOST; |
1481 | } else { |
1482 | bool dcbx_agent_status; |
1483 | int status; |
1484 | |
1485 | if (ice_get_pfc_mode(pf) == ICE_QOS_MODE_DSCP) { |
1486 | clear_bit(nr: ICE_FLAG_FW_LLDP_AGENT, addr: pf->flags); |
1487 | dev_err(dev, "QoS in L3 DSCP mode, FW Agent not allowed to start\n" ); |
1488 | ret = -EOPNOTSUPP; |
1489 | goto ethtool_exit; |
1490 | } |
1491 | |
1492 | /* Remove rule to direct LLDP packets to default VSI. |
1493 | * The FW LLDP engine will now be consuming them. |
1494 | */ |
1495 | ice_cfg_sw_lldp(vsi, tx: false, create: false); |
1496 | |
1497 | /* AQ command to start FW LLDP agent will return an |
1498 | * error if the agent is already started |
1499 | */ |
1500 | status = ice_aq_start_lldp(hw: &pf->hw, persist: true, NULL); |
1501 | if (status) |
1502 | dev_warn(dev, "Fail to start LLDP Agent\n" ); |
1503 | |
1504 | /* AQ command to start FW DCBX agent will fail if |
1505 | * the agent is already started |
1506 | */ |
1507 | status = ice_aq_start_stop_dcbx(hw: &pf->hw, start_dcbx_agent: true, |
1508 | dcbx_agent_status: &dcbx_agent_status, |
1509 | NULL); |
1510 | if (status) |
1511 | dev_dbg(dev, "Failed to start FW DCBX\n" ); |
1512 | |
1513 | dev_info(dev, "FW DCBX agent is %s\n" , |
1514 | dcbx_agent_status ? "ACTIVE" : "DISABLED" ); |
1515 | |
1516 | /* Failure to configure MIB change or init DCB is not |
1517 | * relevant to ethtool. Print notification that |
1518 | * registration/init failed but do not return error |
1519 | * state to ethtool |
1520 | */ |
1521 | status = ice_init_pf_dcb(pf, locked: true); |
1522 | if (status) |
1523 | dev_dbg(dev, "Fail to init DCB\n" ); |
1524 | |
1525 | /* Register for MIB change events */ |
1526 | status = ice_cfg_lldp_mib_change(hw: &pf->hw, ena_mib: true); |
1527 | if (status) |
1528 | dev_dbg(dev, "Fail to enable MIB change events\n" ); |
1529 | |
1530 | pf->dcbx_cap &= ~DCB_CAP_DCBX_HOST; |
1531 | pf->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED; |
1532 | |
1533 | ice_nway_reset(netdev); |
1534 | } |
1535 | } |
1536 | if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { |
1537 | /* down and up VSI so that changes of Rx cfg are reflected. */ |
1538 | ice_down_up(vsi); |
1539 | } |
1540 | /* don't allow modification of this flag when a single VF is in |
1541 | * promiscuous mode because it's not supported |
1542 | */ |
1543 | if (test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, change_flags) && |
1544 | ice_is_any_vf_in_unicast_promisc(pf)) { |
1545 | dev_err(dev, "Changing vf-true-promisc-support flag while VF(s) are in promiscuous mode not supported\n" ); |
1546 | /* toggle bit back to previous state */ |
1547 | change_bit(nr: ICE_FLAG_VF_TRUE_PROMISC_ENA, addr: pf->flags); |
1548 | ret = -EAGAIN; |
1549 | } |
1550 | |
1551 | if (test_bit(ICE_FLAG_VF_VLAN_PRUNING, change_flags) && |
1552 | ice_has_vfs(pf)) { |
1553 | dev_err(dev, "vf-vlan-pruning: VLAN pruning cannot be changed while VFs are active.\n" ); |
1554 | /* toggle bit back to previous state */ |
1555 | change_bit(nr: ICE_FLAG_VF_VLAN_PRUNING, addr: pf->flags); |
1556 | ret = -EOPNOTSUPP; |
1557 | } |
1558 | ethtool_exit: |
1559 | clear_bit(nr: ICE_FLAG_ETHTOOL_CTXT, addr: pf->flags); |
1560 | return ret; |
1561 | } |
1562 | |
1563 | static int ice_get_sset_count(struct net_device *netdev, int sset) |
1564 | { |
1565 | switch (sset) { |
1566 | case ETH_SS_STATS: |
1567 | /* The number (and order) of strings reported *must* remain |
1568 | * constant for a given netdevice. This function must not |
1569 | * report a different number based on run time parameters |
1570 | * (such as the number of queues in use, or the setting of |
1571 | * a private ethtool flag). This is due to the nature of the |
1572 | * ethtool stats API. |
1573 | * |
1574 | * Userspace programs such as ethtool must make 3 separate |
1575 | * ioctl requests, one for size, one for the strings, and |
1576 | * finally one for the stats. Since these cross into |
1577 | * userspace, changes to the number or size could result in |
1578 | * undefined memory access or incorrect string<->value |
1579 | * correlations for statistics. |
1580 | * |
1581 | * Even if it appears to be safe, changes to the size or |
1582 | * order of strings will suffer from race conditions and are |
1583 | * not safe. |
1584 | */ |
1585 | return ICE_ALL_STATS_LEN(netdev); |
1586 | case ETH_SS_TEST: |
1587 | return ICE_TEST_LEN; |
1588 | case ETH_SS_PRIV_FLAGS: |
1589 | return ICE_PRIV_FLAG_ARRAY_SIZE; |
1590 | default: |
1591 | return -EOPNOTSUPP; |
1592 | } |
1593 | } |
1594 | |
1595 | static void |
1596 | __ice_get_ethtool_stats(struct net_device *netdev, |
1597 | struct ethtool_stats __always_unused *stats, u64 *data, |
1598 | struct ice_vsi *vsi) |
1599 | { |
1600 | struct ice_pf *pf = vsi->back; |
1601 | struct ice_tx_ring *tx_ring; |
1602 | struct ice_rx_ring *rx_ring; |
1603 | unsigned int j; |
1604 | int i = 0; |
1605 | char *p; |
1606 | |
1607 | ice_update_pf_stats(pf); |
1608 | ice_update_vsi_stats(vsi); |
1609 | |
1610 | for (j = 0; j < ICE_VSI_STATS_LEN; j++) { |
1611 | p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset; |
1612 | data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat == |
1613 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1614 | } |
1615 | |
1616 | if (ice_is_port_repr_netdev(netdev)) |
1617 | return; |
1618 | |
1619 | /* populate per queue stats */ |
1620 | rcu_read_lock(); |
1621 | |
1622 | ice_for_each_alloc_txq(vsi, j) { |
1623 | tx_ring = READ_ONCE(vsi->tx_rings[j]); |
1624 | if (tx_ring && tx_ring->ring_stats) { |
1625 | data[i++] = tx_ring->ring_stats->stats.pkts; |
1626 | data[i++] = tx_ring->ring_stats->stats.bytes; |
1627 | } else { |
1628 | data[i++] = 0; |
1629 | data[i++] = 0; |
1630 | } |
1631 | } |
1632 | |
1633 | ice_for_each_alloc_rxq(vsi, j) { |
1634 | rx_ring = READ_ONCE(vsi->rx_rings[j]); |
1635 | if (rx_ring && rx_ring->ring_stats) { |
1636 | data[i++] = rx_ring->ring_stats->stats.pkts; |
1637 | data[i++] = rx_ring->ring_stats->stats.bytes; |
1638 | } else { |
1639 | data[i++] = 0; |
1640 | data[i++] = 0; |
1641 | } |
1642 | } |
1643 | |
1644 | rcu_read_unlock(); |
1645 | |
1646 | if (vsi->type != ICE_VSI_PF) |
1647 | return; |
1648 | |
1649 | for (j = 0; j < ICE_PF_STATS_LEN; j++) { |
1650 | p = (char *)pf + ice_gstrings_pf_stats[j].stat_offset; |
1651 | data[i++] = (ice_gstrings_pf_stats[j].sizeof_stat == |
1652 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1653 | } |
1654 | |
1655 | for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { |
1656 | data[i++] = pf->stats.priority_xon_tx[j]; |
1657 | data[i++] = pf->stats.priority_xoff_tx[j]; |
1658 | } |
1659 | |
1660 | for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { |
1661 | data[i++] = pf->stats.priority_xon_rx[j]; |
1662 | data[i++] = pf->stats.priority_xoff_rx[j]; |
1663 | } |
1664 | } |
1665 | |
1666 | static void |
1667 | ice_get_ethtool_stats(struct net_device *netdev, |
1668 | struct ethtool_stats __always_unused *stats, u64 *data) |
1669 | { |
1670 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1671 | |
1672 | __ice_get_ethtool_stats(netdev, stats, data, vsi: np->vsi); |
1673 | } |
1674 | |
1675 | #define ICE_PHY_TYPE_LOW_MASK_MIN_1G (ICE_PHY_TYPE_LOW_100BASE_TX | \ |
1676 | ICE_PHY_TYPE_LOW_100M_SGMII) |
1677 | |
1678 | #define ICE_PHY_TYPE_LOW_MASK_MIN_25G (ICE_PHY_TYPE_LOW_MASK_MIN_1G | \ |
1679 | ICE_PHY_TYPE_LOW_1000BASE_T | \ |
1680 | ICE_PHY_TYPE_LOW_1000BASE_SX | \ |
1681 | ICE_PHY_TYPE_LOW_1000BASE_LX | \ |
1682 | ICE_PHY_TYPE_LOW_1000BASE_KX | \ |
1683 | ICE_PHY_TYPE_LOW_1G_SGMII | \ |
1684 | ICE_PHY_TYPE_LOW_2500BASE_T | \ |
1685 | ICE_PHY_TYPE_LOW_2500BASE_X | \ |
1686 | ICE_PHY_TYPE_LOW_2500BASE_KX | \ |
1687 | ICE_PHY_TYPE_LOW_5GBASE_T | \ |
1688 | ICE_PHY_TYPE_LOW_5GBASE_KR | \ |
1689 | ICE_PHY_TYPE_LOW_10GBASE_T | \ |
1690 | ICE_PHY_TYPE_LOW_10G_SFI_DA | \ |
1691 | ICE_PHY_TYPE_LOW_10GBASE_SR | \ |
1692 | ICE_PHY_TYPE_LOW_10GBASE_LR | \ |
1693 | ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 | \ |
1694 | ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | \ |
1695 | ICE_PHY_TYPE_LOW_10G_SFI_C2C) |
1696 | |
1697 | #define ICE_PHY_TYPE_LOW_MASK_100G (ICE_PHY_TYPE_LOW_100GBASE_CR4 | \ |
1698 | ICE_PHY_TYPE_LOW_100GBASE_SR4 | \ |
1699 | ICE_PHY_TYPE_LOW_100GBASE_LR4 | \ |
1700 | ICE_PHY_TYPE_LOW_100GBASE_KR4 | \ |
1701 | ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | \ |
1702 | ICE_PHY_TYPE_LOW_100G_CAUI4 | \ |
1703 | ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | \ |
1704 | ICE_PHY_TYPE_LOW_100G_AUI4 | \ |
1705 | ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 | \ |
1706 | ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 | \ |
1707 | ICE_PHY_TYPE_LOW_100GBASE_CP2 | \ |
1708 | ICE_PHY_TYPE_LOW_100GBASE_SR2 | \ |
1709 | ICE_PHY_TYPE_LOW_100GBASE_DR) |
1710 | |
1711 | #define ICE_PHY_TYPE_HIGH_MASK_100G (ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \ |
1712 | ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC |\ |
1713 | ICE_PHY_TYPE_HIGH_100G_CAUI2 | \ |
1714 | ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \ |
1715 | ICE_PHY_TYPE_HIGH_100G_AUI2) |
1716 | |
1717 | #define ICE_PHY_TYPE_HIGH_MASK_200G (ICE_PHY_TYPE_HIGH_200G_CR4_PAM4 | \ |
1718 | ICE_PHY_TYPE_HIGH_200G_SR4 | \ |
1719 | ICE_PHY_TYPE_HIGH_200G_FR4 | \ |
1720 | ICE_PHY_TYPE_HIGH_200G_LR4 | \ |
1721 | ICE_PHY_TYPE_HIGH_200G_DR4 | \ |
1722 | ICE_PHY_TYPE_HIGH_200G_KR4_PAM4 | \ |
1723 | ICE_PHY_TYPE_HIGH_200G_AUI4_AOC_ACC | \ |
1724 | ICE_PHY_TYPE_HIGH_200G_AUI4) |
1725 | |
1726 | /** |
1727 | * ice_mask_min_supported_speeds |
1728 | * @hw: pointer to the HW structure |
1729 | * @phy_types_high: PHY type high |
1730 | * @phy_types_low: PHY type low to apply minimum supported speeds mask |
1731 | * |
1732 | * Apply minimum supported speeds mask to PHY type low. These are the speeds |
1733 | * for ethtool supported link mode. |
1734 | */ |
1735 | static void |
1736 | ice_mask_min_supported_speeds(struct ice_hw *hw, |
1737 | u64 phy_types_high, u64 *phy_types_low) |
1738 | { |
1739 | /* if QSFP connection with 100G speed, minimum supported speed is 25G */ |
1740 | if ((*phy_types_low & ICE_PHY_TYPE_LOW_MASK_100G) || |
1741 | (phy_types_high & ICE_PHY_TYPE_HIGH_MASK_100G) || |
1742 | (phy_types_high & ICE_PHY_TYPE_HIGH_MASK_200G)) |
1743 | *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_25G; |
1744 | else if (!ice_is_100m_speed_supported(hw)) |
1745 | *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_1G; |
1746 | } |
1747 | |
1748 | /** |
1749 | * ice_linkmode_set_bit - set link mode bit |
1750 | * @phy_to_ethtool: PHY type to ethtool link mode struct to set |
1751 | * @ks: ethtool link ksettings struct to fill out |
1752 | * @req_speeds: speed requested by user |
1753 | * @advert_phy_type: advertised PHY type |
1754 | * @phy_type: PHY type |
1755 | */ |
1756 | static void |
1757 | ice_linkmode_set_bit(const struct ice_phy_type_to_ethtool *phy_to_ethtool, |
1758 | struct ethtool_link_ksettings *ks, u32 req_speeds, |
1759 | u64 advert_phy_type, u32 phy_type) |
1760 | { |
1761 | linkmode_set_bit(nr: phy_to_ethtool->link_mode, addr: ks->link_modes.supported); |
1762 | |
1763 | if (req_speeds & phy_to_ethtool->aq_link_speed || |
1764 | (!req_speeds && advert_phy_type & BIT(phy_type))) |
1765 | linkmode_set_bit(nr: phy_to_ethtool->link_mode, |
1766 | addr: ks->link_modes.advertising); |
1767 | } |
1768 | |
1769 | /** |
1770 | * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes |
1771 | * @netdev: network interface device structure |
1772 | * @ks: ethtool link ksettings struct to fill out |
1773 | */ |
1774 | static void |
1775 | ice_phy_type_to_ethtool(struct net_device *netdev, |
1776 | struct ethtool_link_ksettings *ks) |
1777 | { |
1778 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1779 | struct ice_vsi *vsi = np->vsi; |
1780 | struct ice_pf *pf = vsi->back; |
1781 | u64 advert_phy_type_lo = 0; |
1782 | u64 advert_phy_type_hi = 0; |
1783 | u64 phy_types_high = 0; |
1784 | u64 phy_types_low = 0; |
1785 | u32 req_speeds; |
1786 | u32 i; |
1787 | |
1788 | req_speeds = vsi->port_info->phy.link_info.req_speeds; |
1789 | |
1790 | /* Check if lenient mode is supported and enabled, or in strict mode. |
1791 | * |
1792 | * In lenient mode the Supported link modes are the PHY types without |
1793 | * media. The Advertising link mode is either 1. the user requested |
1794 | * speed, 2. the override PHY mask, or 3. the PHY types with media. |
1795 | * |
1796 | * In strict mode Supported link mode are the PHY type with media, |
1797 | * and Advertising link modes are the media PHY type or the speed |
1798 | * requested by user. |
1799 | */ |
1800 | if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { |
1801 | phy_types_low = le64_to_cpu(pf->nvm_phy_type_lo); |
1802 | phy_types_high = le64_to_cpu(pf->nvm_phy_type_hi); |
1803 | |
1804 | ice_mask_min_supported_speeds(hw: &pf->hw, phy_types_high, |
1805 | phy_types_low: &phy_types_low); |
1806 | /* determine advertised modes based on link override only |
1807 | * if it's supported and if the FW doesn't abstract the |
1808 | * driver from having to account for link overrides |
1809 | */ |
1810 | if (ice_fw_supports_link_override(hw: &pf->hw) && |
1811 | !ice_fw_supports_report_dflt_cfg(hw: &pf->hw)) { |
1812 | struct ice_link_default_override_tlv *ldo; |
1813 | |
1814 | ldo = &pf->link_dflt_override; |
1815 | /* If override enabled and PHY mask set, then |
1816 | * Advertising link mode is the intersection of the PHY |
1817 | * types without media and the override PHY mask. |
1818 | */ |
1819 | if (ldo->options & ICE_LINK_OVERRIDE_EN && |
1820 | (ldo->phy_type_low || ldo->phy_type_high)) { |
1821 | advert_phy_type_lo = |
1822 | le64_to_cpu(pf->nvm_phy_type_lo) & |
1823 | ldo->phy_type_low; |
1824 | advert_phy_type_hi = |
1825 | le64_to_cpu(pf->nvm_phy_type_hi) & |
1826 | ldo->phy_type_high; |
1827 | } |
1828 | } |
1829 | } else { |
1830 | /* strict mode */ |
1831 | phy_types_low = vsi->port_info->phy.phy_type_low; |
1832 | phy_types_high = vsi->port_info->phy.phy_type_high; |
1833 | } |
1834 | |
1835 | /* If Advertising link mode PHY type is not using override PHY type, |
1836 | * then use PHY type with media. |
1837 | */ |
1838 | if (!advert_phy_type_lo && !advert_phy_type_hi) { |
1839 | advert_phy_type_lo = vsi->port_info->phy.phy_type_low; |
1840 | advert_phy_type_hi = vsi->port_info->phy.phy_type_high; |
1841 | } |
1842 | |
1843 | linkmode_zero(dst: ks->link_modes.supported); |
1844 | linkmode_zero(dst: ks->link_modes.advertising); |
1845 | |
1846 | for (i = 0; i < ARRAY_SIZE(phy_type_low_lkup); i++) { |
1847 | if (phy_types_low & BIT_ULL(i)) |
1848 | ice_linkmode_set_bit(phy_to_ethtool: &phy_type_low_lkup[i], ks, |
1849 | req_speeds, advert_phy_type: advert_phy_type_lo, |
1850 | phy_type: i); |
1851 | } |
1852 | |
1853 | for (i = 0; i < ARRAY_SIZE(phy_type_high_lkup); i++) { |
1854 | if (phy_types_high & BIT_ULL(i)) |
1855 | ice_linkmode_set_bit(phy_to_ethtool: &phy_type_high_lkup[i], ks, |
1856 | req_speeds, advert_phy_type: advert_phy_type_hi, |
1857 | phy_type: i); |
1858 | } |
1859 | } |
1860 | |
1861 | #define TEST_SET_BITS_TIMEOUT 50 |
1862 | #define TEST_SET_BITS_SLEEP_MAX 2000 |
1863 | #define TEST_SET_BITS_SLEEP_MIN 1000 |
1864 | |
1865 | /** |
1866 | * ice_get_settings_link_up - Get Link settings for when link is up |
1867 | * @ks: ethtool ksettings to fill in |
1868 | * @netdev: network interface device structure |
1869 | */ |
1870 | static void |
1871 | ice_get_settings_link_up(struct ethtool_link_ksettings *ks, |
1872 | struct net_device *netdev) |
1873 | { |
1874 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1875 | struct ice_port_info *pi = np->vsi->port_info; |
1876 | struct ice_link_status *link_info; |
1877 | struct ice_vsi *vsi = np->vsi; |
1878 | |
1879 | link_info = &vsi->port_info->phy.link_info; |
1880 | |
1881 | /* Get supported and advertised settings from PHY ability with media */ |
1882 | ice_phy_type_to_ethtool(netdev, ks); |
1883 | |
1884 | switch (link_info->link_speed) { |
1885 | case ICE_AQ_LINK_SPEED_200GB: |
1886 | ks->base.speed = SPEED_200000; |
1887 | break; |
1888 | case ICE_AQ_LINK_SPEED_100GB: |
1889 | ks->base.speed = SPEED_100000; |
1890 | break; |
1891 | case ICE_AQ_LINK_SPEED_50GB: |
1892 | ks->base.speed = SPEED_50000; |
1893 | break; |
1894 | case ICE_AQ_LINK_SPEED_40GB: |
1895 | ks->base.speed = SPEED_40000; |
1896 | break; |
1897 | case ICE_AQ_LINK_SPEED_25GB: |
1898 | ks->base.speed = SPEED_25000; |
1899 | break; |
1900 | case ICE_AQ_LINK_SPEED_20GB: |
1901 | ks->base.speed = SPEED_20000; |
1902 | break; |
1903 | case ICE_AQ_LINK_SPEED_10GB: |
1904 | ks->base.speed = SPEED_10000; |
1905 | break; |
1906 | case ICE_AQ_LINK_SPEED_5GB: |
1907 | ks->base.speed = SPEED_5000; |
1908 | break; |
1909 | case ICE_AQ_LINK_SPEED_2500MB: |
1910 | ks->base.speed = SPEED_2500; |
1911 | break; |
1912 | case ICE_AQ_LINK_SPEED_1000MB: |
1913 | ks->base.speed = SPEED_1000; |
1914 | break; |
1915 | case ICE_AQ_LINK_SPEED_100MB: |
1916 | ks->base.speed = SPEED_100; |
1917 | break; |
1918 | default: |
1919 | netdev_info(dev: netdev, format: "WARNING: Unrecognized link_speed (0x%x).\n" , |
1920 | link_info->link_speed); |
1921 | break; |
1922 | } |
1923 | ks->base.duplex = DUPLEX_FULL; |
1924 | |
1925 | if (link_info->an_info & ICE_AQ_AN_COMPLETED) |
1926 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1927 | Autoneg); |
1928 | |
1929 | /* Set flow control negotiated Rx/Tx pause */ |
1930 | switch (pi->fc.current_mode) { |
1931 | case ICE_FC_FULL: |
1932 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); |
1933 | break; |
1934 | case ICE_FC_TX_PAUSE: |
1935 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); |
1936 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1937 | Asym_Pause); |
1938 | break; |
1939 | case ICE_FC_RX_PAUSE: |
1940 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1941 | Asym_Pause); |
1942 | break; |
1943 | case ICE_FC_PFC: |
1944 | default: |
1945 | ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause); |
1946 | ethtool_link_ksettings_del_link_mode(ks, lp_advertising, |
1947 | Asym_Pause); |
1948 | break; |
1949 | } |
1950 | } |
1951 | |
1952 | /** |
1953 | * ice_get_settings_link_down - Get the Link settings when link is down |
1954 | * @ks: ethtool ksettings to fill in |
1955 | * @netdev: network interface device structure |
1956 | * |
1957 | * Reports link settings that can be determined when link is down |
1958 | */ |
1959 | static void |
1960 | ice_get_settings_link_down(struct ethtool_link_ksettings *ks, |
1961 | struct net_device *netdev) |
1962 | { |
1963 | /* link is down and the driver needs to fall back on |
1964 | * supported PHY types to figure out what info to display |
1965 | */ |
1966 | ice_phy_type_to_ethtool(netdev, ks); |
1967 | |
1968 | /* With no link, speed and duplex are unknown */ |
1969 | ks->base.speed = SPEED_UNKNOWN; |
1970 | ks->base.duplex = DUPLEX_UNKNOWN; |
1971 | } |
1972 | |
1973 | /** |
1974 | * ice_get_link_ksettings - Get Link Speed and Duplex settings |
1975 | * @netdev: network interface device structure |
1976 | * @ks: ethtool ksettings |
1977 | * |
1978 | * Reports speed/duplex settings based on media_type |
1979 | */ |
1980 | static int |
1981 | ice_get_link_ksettings(struct net_device *netdev, |
1982 | struct ethtool_link_ksettings *ks) |
1983 | { |
1984 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1985 | struct ice_aqc_get_phy_caps_data *caps; |
1986 | struct ice_link_status *hw_link_info; |
1987 | struct ice_vsi *vsi = np->vsi; |
1988 | int err; |
1989 | |
1990 | ethtool_link_ksettings_zero_link_mode(ks, supported); |
1991 | ethtool_link_ksettings_zero_link_mode(ks, advertising); |
1992 | ethtool_link_ksettings_zero_link_mode(ks, lp_advertising); |
1993 | hw_link_info = &vsi->port_info->phy.link_info; |
1994 | |
1995 | /* set speed and duplex */ |
1996 | if (hw_link_info->link_info & ICE_AQ_LINK_UP) |
1997 | ice_get_settings_link_up(ks, netdev); |
1998 | else |
1999 | ice_get_settings_link_down(ks, netdev); |
2000 | |
2001 | /* set autoneg settings */ |
2002 | ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ? |
2003 | AUTONEG_ENABLE : AUTONEG_DISABLE; |
2004 | |
2005 | /* set media type settings */ |
2006 | switch (vsi->port_info->phy.media_type) { |
2007 | case ICE_MEDIA_FIBER: |
2008 | ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); |
2009 | ks->base.port = PORT_FIBRE; |
2010 | break; |
2011 | case ICE_MEDIA_BASET: |
2012 | ethtool_link_ksettings_add_link_mode(ks, supported, TP); |
2013 | ethtool_link_ksettings_add_link_mode(ks, advertising, TP); |
2014 | ks->base.port = PORT_TP; |
2015 | break; |
2016 | case ICE_MEDIA_BACKPLANE: |
2017 | ethtool_link_ksettings_add_link_mode(ks, supported, Backplane); |
2018 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2019 | Backplane); |
2020 | ks->base.port = PORT_NONE; |
2021 | break; |
2022 | case ICE_MEDIA_DA: |
2023 | ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); |
2024 | ethtool_link_ksettings_add_link_mode(ks, advertising, FIBRE); |
2025 | ks->base.port = PORT_DA; |
2026 | break; |
2027 | default: |
2028 | ks->base.port = PORT_OTHER; |
2029 | break; |
2030 | } |
2031 | |
2032 | /* flow control is symmetric and always supported */ |
2033 | ethtool_link_ksettings_add_link_mode(ks, supported, Pause); |
2034 | |
2035 | caps = kzalloc(size: sizeof(*caps), GFP_KERNEL); |
2036 | if (!caps) |
2037 | return -ENOMEM; |
2038 | |
2039 | err = ice_aq_get_phy_caps(pi: vsi->port_info, qual_mods: false, |
2040 | ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL); |
2041 | if (err) |
2042 | goto done; |
2043 | |
2044 | /* Set the advertised flow control based on the PHY capability */ |
2045 | if ((caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) && |
2046 | (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)) { |
2047 | ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); |
2048 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2049 | Asym_Pause); |
2050 | } else if (caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) { |
2051 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2052 | Asym_Pause); |
2053 | } else if (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) { |
2054 | ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); |
2055 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2056 | Asym_Pause); |
2057 | } else { |
2058 | ethtool_link_ksettings_del_link_mode(ks, advertising, Pause); |
2059 | ethtool_link_ksettings_del_link_mode(ks, advertising, |
2060 | Asym_Pause); |
2061 | } |
2062 | |
2063 | /* Set advertised FEC modes based on PHY capability */ |
2064 | ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); |
2065 | |
2066 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || |
2067 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) |
2068 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2069 | FEC_BASER); |
2070 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || |
2071 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) |
2072 | ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); |
2073 | |
2074 | err = ice_aq_get_phy_caps(pi: vsi->port_info, qual_mods: false, |
2075 | ICE_AQC_REPORT_TOPO_CAP_MEDIA, caps, NULL); |
2076 | if (err) |
2077 | goto done; |
2078 | |
2079 | /* Set supported FEC modes based on PHY capability */ |
2080 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE); |
2081 | |
2082 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || |
2083 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN) |
2084 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); |
2085 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) |
2086 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); |
2087 | |
2088 | /* Set supported and advertised autoneg */ |
2089 | if (ice_is_phy_caps_an_enabled(caps)) { |
2090 | ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); |
2091 | ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); |
2092 | } |
2093 | |
2094 | done: |
2095 | kfree(objp: caps); |
2096 | return err; |
2097 | } |
2098 | |
2099 | /** |
2100 | * ice_speed_to_aq_link - Get AQ link speed by Ethtool forced speed |
2101 | * @speed: ethtool forced speed |
2102 | */ |
2103 | static u16 ice_speed_to_aq_link(int speed) |
2104 | { |
2105 | int aq_speed; |
2106 | |
2107 | switch (speed) { |
2108 | case SPEED_10: |
2109 | aq_speed = ICE_AQ_LINK_SPEED_10MB; |
2110 | break; |
2111 | case SPEED_100: |
2112 | aq_speed = ICE_AQ_LINK_SPEED_100MB; |
2113 | break; |
2114 | case SPEED_1000: |
2115 | aq_speed = ICE_AQ_LINK_SPEED_1000MB; |
2116 | break; |
2117 | case SPEED_2500: |
2118 | aq_speed = ICE_AQ_LINK_SPEED_2500MB; |
2119 | break; |
2120 | case SPEED_5000: |
2121 | aq_speed = ICE_AQ_LINK_SPEED_5GB; |
2122 | break; |
2123 | case SPEED_10000: |
2124 | aq_speed = ICE_AQ_LINK_SPEED_10GB; |
2125 | break; |
2126 | case SPEED_20000: |
2127 | aq_speed = ICE_AQ_LINK_SPEED_20GB; |
2128 | break; |
2129 | case SPEED_25000: |
2130 | aq_speed = ICE_AQ_LINK_SPEED_25GB; |
2131 | break; |
2132 | case SPEED_40000: |
2133 | aq_speed = ICE_AQ_LINK_SPEED_40GB; |
2134 | break; |
2135 | case SPEED_50000: |
2136 | aq_speed = ICE_AQ_LINK_SPEED_50GB; |
2137 | break; |
2138 | case SPEED_100000: |
2139 | aq_speed = ICE_AQ_LINK_SPEED_100GB; |
2140 | break; |
2141 | default: |
2142 | aq_speed = ICE_AQ_LINK_SPEED_UNKNOWN; |
2143 | break; |
2144 | } |
2145 | return aq_speed; |
2146 | } |
2147 | |
2148 | /** |
2149 | * ice_ksettings_find_adv_link_speed - Find advertising link speed |
2150 | * @ks: ethtool ksettings |
2151 | */ |
2152 | static u16 |
2153 | ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks) |
2154 | { |
2155 | const struct ethtool_forced_speed_map *map; |
2156 | u16 adv_link_speed = 0; |
2157 | |
2158 | for (u32 i = 0; i < ARRAY_SIZE(ice_adv_lnk_speed_maps); i++) { |
2159 | map = ice_adv_lnk_speed_maps + i; |
2160 | if (linkmode_intersects(src1: ks->link_modes.advertising, src2: map->caps)) |
2161 | adv_link_speed |= ice_speed_to_aq_link(speed: map->speed); |
2162 | } |
2163 | |
2164 | return adv_link_speed; |
2165 | } |
2166 | |
2167 | /** |
2168 | * ice_setup_autoneg |
2169 | * @p: port info |
2170 | * @ks: ethtool_link_ksettings |
2171 | * @config: configuration that will be sent down to FW |
2172 | * @autoneg_enabled: autonegotiation is enabled or not |
2173 | * @autoneg_changed: will there a change in autonegotiation |
2174 | * @netdev: network interface device structure |
2175 | * |
2176 | * Setup PHY autonegotiation feature |
2177 | */ |
2178 | static int |
2179 | ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks, |
2180 | struct ice_aqc_set_phy_cfg_data *config, |
2181 | u8 autoneg_enabled, u8 *autoneg_changed, |
2182 | struct net_device *netdev) |
2183 | { |
2184 | int err = 0; |
2185 | |
2186 | *autoneg_changed = 0; |
2187 | |
2188 | /* Check autoneg */ |
2189 | if (autoneg_enabled == AUTONEG_ENABLE) { |
2190 | /* If autoneg was not already enabled */ |
2191 | if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) { |
2192 | /* If autoneg is not supported, return error */ |
2193 | if (!ethtool_link_ksettings_test_link_mode(ks, |
2194 | supported, |
2195 | Autoneg)) { |
2196 | netdev_info(dev: netdev, format: "Autoneg not supported on this phy.\n" ); |
2197 | err = -EINVAL; |
2198 | } else { |
2199 | /* Autoneg is allowed to change */ |
2200 | config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2201 | *autoneg_changed = 1; |
2202 | } |
2203 | } |
2204 | } else { |
2205 | /* If autoneg is currently enabled */ |
2206 | if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) { |
2207 | /* If autoneg is supported 10GBASE_T is the only PHY |
2208 | * that can disable it, so otherwise return error |
2209 | */ |
2210 | if (ethtool_link_ksettings_test_link_mode(ks, |
2211 | supported, |
2212 | Autoneg)) { |
2213 | netdev_info(dev: netdev, format: "Autoneg cannot be disabled on this phy\n" ); |
2214 | err = -EINVAL; |
2215 | } else { |
2216 | /* Autoneg is allowed to change */ |
2217 | config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2218 | *autoneg_changed = 1; |
2219 | } |
2220 | } |
2221 | } |
2222 | |
2223 | return err; |
2224 | } |
2225 | |
2226 | /** |
2227 | * ice_set_phy_type_from_speed - set phy_types based on speeds |
2228 | * and advertised modes |
2229 | * @ks: ethtool link ksettings struct |
2230 | * @phy_type_low: pointer to the lower part of phy_type |
2231 | * @phy_type_high: pointer to the higher part of phy_type |
2232 | * @adv_link_speed: targeted link speeds bitmap |
2233 | */ |
2234 | static void |
2235 | ice_set_phy_type_from_speed(const struct ethtool_link_ksettings *ks, |
2236 | u64 *phy_type_low, u64 *phy_type_high, |
2237 | u16 adv_link_speed) |
2238 | { |
2239 | /* Handle 1000M speed in a special way because ice_update_phy_type |
2240 | * enables all link modes, but having mixed copper and optical |
2241 | * standards is not supported. |
2242 | */ |
2243 | adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB; |
2244 | |
2245 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2246 | 1000baseT_Full)) |
2247 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T | |
2248 | ICE_PHY_TYPE_LOW_1G_SGMII; |
2249 | |
2250 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2251 | 1000baseKX_Full)) |
2252 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX; |
2253 | |
2254 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2255 | 1000baseX_Full)) |
2256 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX | |
2257 | ICE_PHY_TYPE_LOW_1000BASE_LX; |
2258 | |
2259 | ice_update_phy_type(phy_type_low, phy_type_high, link_speeds_bitmap: adv_link_speed); |
2260 | } |
2261 | |
2262 | /** |
2263 | * ice_set_link_ksettings - Set Speed and Duplex |
2264 | * @netdev: network interface device structure |
2265 | * @ks: ethtool ksettings |
2266 | * |
2267 | * Set speed/duplex per media_types advertised/forced |
2268 | */ |
2269 | static int |
2270 | ice_set_link_ksettings(struct net_device *netdev, |
2271 | const struct ethtool_link_ksettings *ks) |
2272 | { |
2273 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2274 | u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT; |
2275 | struct ethtool_link_ksettings copy_ks = *ks; |
2276 | struct ethtool_link_ksettings safe_ks = {}; |
2277 | struct ice_aqc_get_phy_caps_data *phy_caps; |
2278 | struct ice_aqc_set_phy_cfg_data config; |
2279 | u16 adv_link_speed, curr_link_speed; |
2280 | struct ice_pf *pf = np->vsi->back; |
2281 | struct ice_port_info *pi; |
2282 | u8 autoneg_changed = 0; |
2283 | u64 phy_type_high = 0; |
2284 | u64 phy_type_low = 0; |
2285 | bool linkup; |
2286 | int err; |
2287 | |
2288 | pi = np->vsi->port_info; |
2289 | |
2290 | if (!pi) |
2291 | return -EIO; |
2292 | |
2293 | if (pi->phy.media_type != ICE_MEDIA_BASET && |
2294 | pi->phy.media_type != ICE_MEDIA_FIBER && |
2295 | pi->phy.media_type != ICE_MEDIA_BACKPLANE && |
2296 | pi->phy.media_type != ICE_MEDIA_DA && |
2297 | pi->phy.link_info.link_info & ICE_AQ_LINK_UP) |
2298 | return -EOPNOTSUPP; |
2299 | |
2300 | phy_caps = kzalloc(size: sizeof(*phy_caps), GFP_KERNEL); |
2301 | if (!phy_caps) |
2302 | return -ENOMEM; |
2303 | |
2304 | /* Get the PHY capabilities based on media */ |
2305 | if (ice_fw_supports_report_dflt_cfg(hw: pi->hw)) |
2306 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_DFLT_CFG, |
2307 | caps: phy_caps, NULL); |
2308 | else |
2309 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, |
2310 | caps: phy_caps, NULL); |
2311 | if (err) |
2312 | goto done; |
2313 | |
2314 | /* save autoneg out of ksettings */ |
2315 | autoneg = copy_ks.base.autoneg; |
2316 | |
2317 | /* Get link modes supported by hardware.*/ |
2318 | ice_phy_type_to_ethtool(netdev, ks: &safe_ks); |
2319 | |
2320 | /* and check against modes requested by user. |
2321 | * Return an error if unsupported mode was set. |
2322 | */ |
2323 | if (!bitmap_subset(src1: copy_ks.link_modes.advertising, |
2324 | src2: safe_ks.link_modes.supported, |
2325 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS)) { |
2326 | if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) |
2327 | netdev_info(dev: netdev, format: "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n" ); |
2328 | err = -EOPNOTSUPP; |
2329 | goto done; |
2330 | } |
2331 | |
2332 | /* get our own copy of the bits to check against */ |
2333 | memset(&safe_ks, 0, sizeof(safe_ks)); |
2334 | safe_ks.base.cmd = copy_ks.base.cmd; |
2335 | safe_ks.base.link_mode_masks_nwords = |
2336 | copy_ks.base.link_mode_masks_nwords; |
2337 | ice_get_link_ksettings(netdev, ks: &safe_ks); |
2338 | |
2339 | /* set autoneg back to what it currently is */ |
2340 | copy_ks.base.autoneg = safe_ks.base.autoneg; |
2341 | /* we don't compare the speed */ |
2342 | copy_ks.base.speed = safe_ks.base.speed; |
2343 | |
2344 | /* If copy_ks.base and safe_ks.base are not the same now, then they are |
2345 | * trying to set something that we do not support. |
2346 | */ |
2347 | if (memcmp(p: ©_ks.base, q: &safe_ks.base, size: sizeof(copy_ks.base))) { |
2348 | err = -EOPNOTSUPP; |
2349 | goto done; |
2350 | } |
2351 | |
2352 | while (test_and_set_bit(nr: ICE_CFG_BUSY, addr: pf->state)) { |
2353 | timeout--; |
2354 | if (!timeout) { |
2355 | err = -EBUSY; |
2356 | goto done; |
2357 | } |
2358 | usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); |
2359 | } |
2360 | |
2361 | /* Copy the current user PHY configuration. The current user PHY |
2362 | * configuration is initialized during probe from PHY capabilities |
2363 | * software mode, and updated on set PHY configuration. |
2364 | */ |
2365 | config = pi->phy.curr_user_phy_cfg; |
2366 | |
2367 | config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2368 | |
2369 | /* Check autoneg */ |
2370 | err = ice_setup_autoneg(p: pi, ks: &safe_ks, config: &config, autoneg_enabled: autoneg, autoneg_changed: &autoneg_changed, |
2371 | netdev); |
2372 | |
2373 | if (err) |
2374 | goto done; |
2375 | |
2376 | /* Call to get the current link speed */ |
2377 | pi->phy.get_link_info = true; |
2378 | err = ice_get_link_status(pi, link_up: &linkup); |
2379 | if (err) |
2380 | goto done; |
2381 | |
2382 | curr_link_speed = pi->phy.curr_user_speed_req; |
2383 | adv_link_speed = ice_ksettings_find_adv_link_speed(ks); |
2384 | |
2385 | /* If speed didn't get set, set it to what it currently is. |
2386 | * This is needed because if advertise is 0 (as it is when autoneg |
2387 | * is disabled) then speed won't get set. |
2388 | */ |
2389 | if (!adv_link_speed) |
2390 | adv_link_speed = curr_link_speed; |
2391 | |
2392 | /* Convert the advertise link speeds to their corresponded PHY_TYPE */ |
2393 | ice_set_phy_type_from_speed(ks, phy_type_low: &phy_type_low, phy_type_high: &phy_type_high, |
2394 | adv_link_speed); |
2395 | |
2396 | if (!autoneg_changed && adv_link_speed == curr_link_speed) { |
2397 | netdev_info(dev: netdev, format: "Nothing changed, exiting without setting anything.\n" ); |
2398 | goto done; |
2399 | } |
2400 | |
2401 | /* save the requested speeds */ |
2402 | pi->phy.link_info.req_speeds = adv_link_speed; |
2403 | |
2404 | /* set link and auto negotiation so changes take effect */ |
2405 | config.caps |= ICE_AQ_PHY_ENA_LINK; |
2406 | |
2407 | /* check if there is a PHY type for the requested advertised speed */ |
2408 | if (!(phy_type_low || phy_type_high)) { |
2409 | netdev_info(dev: netdev, format: "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n" ); |
2410 | err = -EOPNOTSUPP; |
2411 | goto done; |
2412 | } |
2413 | |
2414 | /* intersect requested advertised speed PHY types with media PHY types |
2415 | * for set PHY configuration |
2416 | */ |
2417 | config.phy_type_high = cpu_to_le64(phy_type_high) & |
2418 | phy_caps->phy_type_high; |
2419 | config.phy_type_low = cpu_to_le64(phy_type_low) & |
2420 | phy_caps->phy_type_low; |
2421 | |
2422 | if (!(config.phy_type_high || config.phy_type_low)) { |
2423 | /* If there is no intersection and lenient mode is enabled, then |
2424 | * intersect the requested advertised speed with NVM media type |
2425 | * PHY types. |
2426 | */ |
2427 | if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { |
2428 | config.phy_type_high = cpu_to_le64(phy_type_high) & |
2429 | pf->nvm_phy_type_hi; |
2430 | config.phy_type_low = cpu_to_le64(phy_type_low) & |
2431 | pf->nvm_phy_type_lo; |
2432 | } else { |
2433 | netdev_info(dev: netdev, format: "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n" ); |
2434 | err = -EOPNOTSUPP; |
2435 | goto done; |
2436 | } |
2437 | } |
2438 | |
2439 | /* If link is up put link down */ |
2440 | if (pi->phy.link_info.link_info & ICE_AQ_LINK_UP) { |
2441 | /* Tell the OS link is going down, the link will go |
2442 | * back up when fw says it is ready asynchronously |
2443 | */ |
2444 | ice_print_link_msg(vsi: np->vsi, isup: false); |
2445 | netif_carrier_off(dev: netdev); |
2446 | netif_tx_stop_all_queues(dev: netdev); |
2447 | } |
2448 | |
2449 | /* make the aq call */ |
2450 | err = ice_aq_set_phy_cfg(hw: &pf->hw, pi, cfg: &config, NULL); |
2451 | if (err) { |
2452 | netdev_info(dev: netdev, format: "Set phy config failed,\n" ); |
2453 | goto done; |
2454 | } |
2455 | |
2456 | /* Save speed request */ |
2457 | pi->phy.curr_user_speed_req = adv_link_speed; |
2458 | done: |
2459 | kfree(objp: phy_caps); |
2460 | clear_bit(nr: ICE_CFG_BUSY, addr: pf->state); |
2461 | |
2462 | return err; |
2463 | } |
2464 | |
2465 | /** |
2466 | * ice_parse_hdrs - parses headers from RSS hash input |
2467 | * @nfc: ethtool rxnfc command |
2468 | * |
2469 | * This function parses the rxnfc command and returns intended |
2470 | * header types for RSS configuration |
2471 | */ |
2472 | static u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc) |
2473 | { |
2474 | u32 hdrs = ICE_FLOW_SEG_HDR_NONE; |
2475 | |
2476 | switch (nfc->flow_type) { |
2477 | case TCP_V4_FLOW: |
2478 | hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4; |
2479 | break; |
2480 | case UDP_V4_FLOW: |
2481 | hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4; |
2482 | break; |
2483 | case SCTP_V4_FLOW: |
2484 | hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4; |
2485 | break; |
2486 | case GTPU_V4_FLOW: |
2487 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_IP | ICE_FLOW_SEG_HDR_IPV4; |
2488 | break; |
2489 | case GTPC_V4_FLOW: |
2490 | hdrs |= ICE_FLOW_SEG_HDR_GTPC | ICE_FLOW_SEG_HDR_IPV4; |
2491 | break; |
2492 | case GTPC_TEID_V4_FLOW: |
2493 | hdrs |= ICE_FLOW_SEG_HDR_GTPC_TEID | ICE_FLOW_SEG_HDR_IPV4; |
2494 | break; |
2495 | case GTPU_EH_V4_FLOW: |
2496 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_EH | ICE_FLOW_SEG_HDR_IPV4; |
2497 | break; |
2498 | case GTPU_UL_V4_FLOW: |
2499 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_UP | ICE_FLOW_SEG_HDR_IPV4; |
2500 | break; |
2501 | case GTPU_DL_V4_FLOW: |
2502 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_DWN | ICE_FLOW_SEG_HDR_IPV4; |
2503 | break; |
2504 | case TCP_V6_FLOW: |
2505 | hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6; |
2506 | break; |
2507 | case UDP_V6_FLOW: |
2508 | hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6; |
2509 | break; |
2510 | case SCTP_V6_FLOW: |
2511 | hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6; |
2512 | break; |
2513 | case GTPU_V6_FLOW: |
2514 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_IP | ICE_FLOW_SEG_HDR_IPV6; |
2515 | break; |
2516 | case GTPC_V6_FLOW: |
2517 | hdrs |= ICE_FLOW_SEG_HDR_GTPC | ICE_FLOW_SEG_HDR_IPV6; |
2518 | break; |
2519 | case GTPC_TEID_V6_FLOW: |
2520 | hdrs |= ICE_FLOW_SEG_HDR_GTPC_TEID | ICE_FLOW_SEG_HDR_IPV6; |
2521 | break; |
2522 | case GTPU_EH_V6_FLOW: |
2523 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_EH | ICE_FLOW_SEG_HDR_IPV6; |
2524 | break; |
2525 | case GTPU_UL_V6_FLOW: |
2526 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_UP | ICE_FLOW_SEG_HDR_IPV6; |
2527 | break; |
2528 | case GTPU_DL_V6_FLOW: |
2529 | hdrs |= ICE_FLOW_SEG_HDR_GTPU_DWN | ICE_FLOW_SEG_HDR_IPV6; |
2530 | break; |
2531 | default: |
2532 | break; |
2533 | } |
2534 | return hdrs; |
2535 | } |
2536 | |
2537 | /** |
2538 | * ice_parse_hash_flds - parses hash fields from RSS hash input |
2539 | * @nfc: ethtool rxnfc command |
2540 | * @symm: true if Symmetric Topelitz is set |
2541 | * |
2542 | * This function parses the rxnfc command and returns intended |
2543 | * hash fields for RSS configuration |
2544 | */ |
2545 | static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc, bool symm) |
2546 | { |
2547 | u64 hfld = ICE_HASH_INVALID; |
2548 | |
2549 | if (nfc->data & RXH_IP_SRC || nfc->data & RXH_IP_DST) { |
2550 | switch (nfc->flow_type) { |
2551 | case TCP_V4_FLOW: |
2552 | case UDP_V4_FLOW: |
2553 | case SCTP_V4_FLOW: |
2554 | case GTPU_V4_FLOW: |
2555 | case GTPC_V4_FLOW: |
2556 | case GTPC_TEID_V4_FLOW: |
2557 | case GTPU_EH_V4_FLOW: |
2558 | case GTPU_UL_V4_FLOW: |
2559 | case GTPU_DL_V4_FLOW: |
2560 | if (nfc->data & RXH_IP_SRC) |
2561 | hfld |= ICE_FLOW_HASH_FLD_IPV4_SA; |
2562 | if (nfc->data & RXH_IP_DST) |
2563 | hfld |= ICE_FLOW_HASH_FLD_IPV4_DA; |
2564 | break; |
2565 | case TCP_V6_FLOW: |
2566 | case UDP_V6_FLOW: |
2567 | case SCTP_V6_FLOW: |
2568 | case GTPU_V6_FLOW: |
2569 | case GTPC_V6_FLOW: |
2570 | case GTPC_TEID_V6_FLOW: |
2571 | case GTPU_EH_V6_FLOW: |
2572 | case GTPU_UL_V6_FLOW: |
2573 | case GTPU_DL_V6_FLOW: |
2574 | if (nfc->data & RXH_IP_SRC) |
2575 | hfld |= ICE_FLOW_HASH_FLD_IPV6_SA; |
2576 | if (nfc->data & RXH_IP_DST) |
2577 | hfld |= ICE_FLOW_HASH_FLD_IPV6_DA; |
2578 | break; |
2579 | default: |
2580 | break; |
2581 | } |
2582 | } |
2583 | |
2584 | if (nfc->data & RXH_L4_B_0_1 || nfc->data & RXH_L4_B_2_3) { |
2585 | switch (nfc->flow_type) { |
2586 | case TCP_V4_FLOW: |
2587 | case TCP_V6_FLOW: |
2588 | if (nfc->data & RXH_L4_B_0_1) |
2589 | hfld |= ICE_FLOW_HASH_FLD_TCP_SRC_PORT; |
2590 | if (nfc->data & RXH_L4_B_2_3) |
2591 | hfld |= ICE_FLOW_HASH_FLD_TCP_DST_PORT; |
2592 | break; |
2593 | case UDP_V4_FLOW: |
2594 | case UDP_V6_FLOW: |
2595 | if (nfc->data & RXH_L4_B_0_1) |
2596 | hfld |= ICE_FLOW_HASH_FLD_UDP_SRC_PORT; |
2597 | if (nfc->data & RXH_L4_B_2_3) |
2598 | hfld |= ICE_FLOW_HASH_FLD_UDP_DST_PORT; |
2599 | break; |
2600 | case SCTP_V4_FLOW: |
2601 | case SCTP_V6_FLOW: |
2602 | if (nfc->data & RXH_L4_B_0_1) |
2603 | hfld |= ICE_FLOW_HASH_FLD_SCTP_SRC_PORT; |
2604 | if (nfc->data & RXH_L4_B_2_3) |
2605 | hfld |= ICE_FLOW_HASH_FLD_SCTP_DST_PORT; |
2606 | break; |
2607 | default: |
2608 | break; |
2609 | } |
2610 | } |
2611 | |
2612 | if (nfc->data & RXH_GTP_TEID) { |
2613 | switch (nfc->flow_type) { |
2614 | case GTPC_TEID_V4_FLOW: |
2615 | case GTPC_TEID_V6_FLOW: |
2616 | hfld |= ICE_FLOW_HASH_FLD_GTPC_TEID; |
2617 | break; |
2618 | case GTPU_V4_FLOW: |
2619 | case GTPU_V6_FLOW: |
2620 | hfld |= ICE_FLOW_HASH_FLD_GTPU_IP_TEID; |
2621 | break; |
2622 | case GTPU_EH_V4_FLOW: |
2623 | case GTPU_EH_V6_FLOW: |
2624 | hfld |= ICE_FLOW_HASH_FLD_GTPU_EH_TEID; |
2625 | break; |
2626 | case GTPU_UL_V4_FLOW: |
2627 | case GTPU_UL_V6_FLOW: |
2628 | hfld |= ICE_FLOW_HASH_FLD_GTPU_UP_TEID; |
2629 | break; |
2630 | case GTPU_DL_V4_FLOW: |
2631 | case GTPU_DL_V6_FLOW: |
2632 | hfld |= ICE_FLOW_HASH_FLD_GTPU_DWN_TEID; |
2633 | break; |
2634 | default: |
2635 | break; |
2636 | } |
2637 | } |
2638 | |
2639 | return hfld; |
2640 | } |
2641 | |
2642 | /** |
2643 | * ice_set_rss_hash_opt - Enable/Disable flow types for RSS hash |
2644 | * @vsi: the VSI being configured |
2645 | * @nfc: ethtool rxnfc command |
2646 | * |
2647 | * Returns Success if the flow input set is supported. |
2648 | */ |
2649 | static int |
2650 | (struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) |
2651 | { |
2652 | struct ice_pf *pf = vsi->back; |
2653 | struct ice_rss_hash_cfg cfg; |
2654 | struct device *dev; |
2655 | u64 hashed_flds; |
2656 | int status; |
2657 | bool symm; |
2658 | u32 hdrs; |
2659 | |
2660 | dev = ice_pf_to_dev(pf); |
2661 | if (ice_is_safe_mode(pf)) { |
2662 | dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n" , |
2663 | vsi->vsi_num); |
2664 | return -EINVAL; |
2665 | } |
2666 | |
2667 | symm = !!(vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ); |
2668 | hashed_flds = ice_parse_hash_flds(nfc, symm); |
2669 | if (hashed_flds == ICE_HASH_INVALID) { |
2670 | dev_dbg(dev, "Invalid hash fields, vsi num = %d\n" , |
2671 | vsi->vsi_num); |
2672 | return -EINVAL; |
2673 | } |
2674 | |
2675 | hdrs = ice_parse_hdrs(nfc); |
2676 | if (hdrs == ICE_FLOW_SEG_HDR_NONE) { |
2677 | dev_dbg(dev, "Header type is not valid, vsi num = %d\n" , |
2678 | vsi->vsi_num); |
2679 | return -EINVAL; |
2680 | } |
2681 | |
2682 | cfg.hash_flds = hashed_flds; |
2683 | cfg.addl_hdrs = hdrs; |
2684 | cfg.hdr_type = ICE_RSS_ANY_HEADERS; |
2685 | cfg.symm = symm; |
2686 | |
2687 | status = ice_add_rss_cfg(hw: &pf->hw, vsi, cfg: &cfg); |
2688 | if (status) { |
2689 | dev_dbg(dev, "ice_add_rss_cfg failed, vsi num = %d, error = %d\n" , |
2690 | vsi->vsi_num, status); |
2691 | return status; |
2692 | } |
2693 | |
2694 | return 0; |
2695 | } |
2696 | |
2697 | /** |
2698 | * ice_get_rss_hash_opt - Retrieve hash fields for a given flow-type |
2699 | * @vsi: the VSI being configured |
2700 | * @nfc: ethtool rxnfc command |
2701 | */ |
2702 | static void |
2703 | (struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) |
2704 | { |
2705 | struct ice_pf *pf = vsi->back; |
2706 | struct device *dev; |
2707 | u64 hash_flds; |
2708 | bool symm; |
2709 | u32 hdrs; |
2710 | |
2711 | dev = ice_pf_to_dev(pf); |
2712 | |
2713 | nfc->data = 0; |
2714 | if (ice_is_safe_mode(pf)) { |
2715 | dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n" , |
2716 | vsi->vsi_num); |
2717 | return; |
2718 | } |
2719 | |
2720 | hdrs = ice_parse_hdrs(nfc); |
2721 | if (hdrs == ICE_FLOW_SEG_HDR_NONE) { |
2722 | dev_dbg(dev, "Header type is not valid, vsi num = %d\n" , |
2723 | vsi->vsi_num); |
2724 | return; |
2725 | } |
2726 | |
2727 | hash_flds = ice_get_rss_cfg(hw: &pf->hw, vsi_handle: vsi->idx, hdrs, symm: &symm); |
2728 | if (hash_flds == ICE_HASH_INVALID) { |
2729 | dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n" , |
2730 | vsi->vsi_num); |
2731 | return; |
2732 | } |
2733 | |
2734 | if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_SA || |
2735 | hash_flds & ICE_FLOW_HASH_FLD_IPV6_SA) |
2736 | nfc->data |= (u64)RXH_IP_SRC; |
2737 | |
2738 | if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_DA || |
2739 | hash_flds & ICE_FLOW_HASH_FLD_IPV6_DA) |
2740 | nfc->data |= (u64)RXH_IP_DST; |
2741 | |
2742 | if (hash_flds & ICE_FLOW_HASH_FLD_TCP_SRC_PORT || |
2743 | hash_flds & ICE_FLOW_HASH_FLD_UDP_SRC_PORT || |
2744 | hash_flds & ICE_FLOW_HASH_FLD_SCTP_SRC_PORT) |
2745 | nfc->data |= (u64)RXH_L4_B_0_1; |
2746 | |
2747 | if (hash_flds & ICE_FLOW_HASH_FLD_TCP_DST_PORT || |
2748 | hash_flds & ICE_FLOW_HASH_FLD_UDP_DST_PORT || |
2749 | hash_flds & ICE_FLOW_HASH_FLD_SCTP_DST_PORT) |
2750 | nfc->data |= (u64)RXH_L4_B_2_3; |
2751 | |
2752 | if (hash_flds & ICE_FLOW_HASH_FLD_GTPC_TEID || |
2753 | hash_flds & ICE_FLOW_HASH_FLD_GTPU_IP_TEID || |
2754 | hash_flds & ICE_FLOW_HASH_FLD_GTPU_EH_TEID || |
2755 | hash_flds & ICE_FLOW_HASH_FLD_GTPU_UP_TEID || |
2756 | hash_flds & ICE_FLOW_HASH_FLD_GTPU_DWN_TEID) |
2757 | nfc->data |= (u64)RXH_GTP_TEID; |
2758 | } |
2759 | |
2760 | /** |
2761 | * ice_set_rxnfc - command to set Rx flow rules. |
2762 | * @netdev: network interface device structure |
2763 | * @cmd: ethtool rxnfc command |
2764 | * |
2765 | * Returns 0 for success and negative values for errors |
2766 | */ |
2767 | static int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) |
2768 | { |
2769 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2770 | struct ice_vsi *vsi = np->vsi; |
2771 | |
2772 | switch (cmd->cmd) { |
2773 | case ETHTOOL_SRXCLSRLINS: |
2774 | return ice_add_fdir_ethtool(vsi, cmd); |
2775 | case ETHTOOL_SRXCLSRLDEL: |
2776 | return ice_del_fdir_ethtool(vsi, cmd); |
2777 | case ETHTOOL_SRXFH: |
2778 | return ice_set_rss_hash_opt(vsi, nfc: cmd); |
2779 | default: |
2780 | break; |
2781 | } |
2782 | return -EOPNOTSUPP; |
2783 | } |
2784 | |
2785 | /** |
2786 | * ice_get_rxnfc - command to get Rx flow classification rules |
2787 | * @netdev: network interface device structure |
2788 | * @cmd: ethtool rxnfc command |
2789 | * @rule_locs: buffer to rturn Rx flow classification rules |
2790 | * |
2791 | * Returns Success if the command is supported. |
2792 | */ |
2793 | static int |
2794 | ice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, |
2795 | u32 __always_unused *rule_locs) |
2796 | { |
2797 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2798 | struct ice_vsi *vsi = np->vsi; |
2799 | int ret = -EOPNOTSUPP; |
2800 | struct ice_hw *hw; |
2801 | |
2802 | hw = &vsi->back->hw; |
2803 | |
2804 | switch (cmd->cmd) { |
2805 | case ETHTOOL_GRXRINGS: |
2806 | cmd->data = vsi->rss_size; |
2807 | ret = 0; |
2808 | break; |
2809 | case ETHTOOL_GRXCLSRLCNT: |
2810 | cmd->rule_cnt = hw->fdir_active_fltr; |
2811 | /* report total rule count */ |
2812 | cmd->data = ice_get_fdir_cnt_all(hw); |
2813 | ret = 0; |
2814 | break; |
2815 | case ETHTOOL_GRXCLSRULE: |
2816 | ret = ice_get_ethtool_fdir_entry(hw, cmd); |
2817 | break; |
2818 | case ETHTOOL_GRXCLSRLALL: |
2819 | ret = ice_get_fdir_fltr_ids(hw, cmd, rule_locs: (u32 *)rule_locs); |
2820 | break; |
2821 | case ETHTOOL_GRXFH: |
2822 | ice_get_rss_hash_opt(vsi, nfc: cmd); |
2823 | ret = 0; |
2824 | break; |
2825 | default: |
2826 | break; |
2827 | } |
2828 | |
2829 | return ret; |
2830 | } |
2831 | |
2832 | static void |
2833 | ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, |
2834 | struct kernel_ethtool_ringparam *kernel_ring, |
2835 | struct netlink_ext_ack *extack) |
2836 | { |
2837 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2838 | struct ice_vsi *vsi = np->vsi; |
2839 | |
2840 | ring->rx_max_pending = ICE_MAX_NUM_DESC; |
2841 | ring->tx_max_pending = ICE_MAX_NUM_DESC; |
2842 | if (vsi->tx_rings && vsi->rx_rings) { |
2843 | ring->rx_pending = vsi->rx_rings[0]->count; |
2844 | ring->tx_pending = vsi->tx_rings[0]->count; |
2845 | } else { |
2846 | ring->rx_pending = 0; |
2847 | ring->tx_pending = 0; |
2848 | } |
2849 | |
2850 | /* Rx mini and jumbo rings are not supported */ |
2851 | ring->rx_mini_max_pending = 0; |
2852 | ring->rx_jumbo_max_pending = 0; |
2853 | ring->rx_mini_pending = 0; |
2854 | ring->rx_jumbo_pending = 0; |
2855 | } |
2856 | |
2857 | static int |
2858 | ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, |
2859 | struct kernel_ethtool_ringparam *kernel_ring, |
2860 | struct netlink_ext_ack *extack) |
2861 | { |
2862 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2863 | struct ice_tx_ring *xdp_rings = NULL; |
2864 | struct ice_tx_ring *tx_rings = NULL; |
2865 | struct ice_rx_ring *rx_rings = NULL; |
2866 | struct ice_vsi *vsi = np->vsi; |
2867 | struct ice_pf *pf = vsi->back; |
2868 | int i, timeout = 50, err = 0; |
2869 | u16 new_rx_cnt, new_tx_cnt; |
2870 | |
2871 | if (ring->tx_pending > ICE_MAX_NUM_DESC || |
2872 | ring->tx_pending < ICE_MIN_NUM_DESC || |
2873 | ring->rx_pending > ICE_MAX_NUM_DESC || |
2874 | ring->rx_pending < ICE_MIN_NUM_DESC) { |
2875 | netdev_err(dev: netdev, format: "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n" , |
2876 | ring->tx_pending, ring->rx_pending, |
2877 | ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, |
2878 | ICE_REQ_DESC_MULTIPLE); |
2879 | return -EINVAL; |
2880 | } |
2881 | |
2882 | /* Return if there is no rings (device is reloading) */ |
2883 | if (!vsi->tx_rings || !vsi->rx_rings) |
2884 | return -EBUSY; |
2885 | |
2886 | new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); |
2887 | if (new_tx_cnt != ring->tx_pending) |
2888 | netdev_info(dev: netdev, format: "Requested Tx descriptor count rounded up to %d\n" , |
2889 | new_tx_cnt); |
2890 | new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); |
2891 | if (new_rx_cnt != ring->rx_pending) |
2892 | netdev_info(dev: netdev, format: "Requested Rx descriptor count rounded up to %d\n" , |
2893 | new_rx_cnt); |
2894 | |
2895 | /* if nothing to do return success */ |
2896 | if (new_tx_cnt == vsi->tx_rings[0]->count && |
2897 | new_rx_cnt == vsi->rx_rings[0]->count) { |
2898 | netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n" ); |
2899 | return 0; |
2900 | } |
2901 | |
2902 | /* If there is a AF_XDP UMEM attached to any of Rx rings, |
2903 | * disallow changing the number of descriptors -- regardless |
2904 | * if the netdev is running or not. |
2905 | */ |
2906 | if (ice_xsk_any_rx_ring_ena(vsi)) |
2907 | return -EBUSY; |
2908 | |
2909 | while (test_and_set_bit(nr: ICE_CFG_BUSY, addr: pf->state)) { |
2910 | timeout--; |
2911 | if (!timeout) |
2912 | return -EBUSY; |
2913 | usleep_range(min: 1000, max: 2000); |
2914 | } |
2915 | |
2916 | /* set for the next time the netdev is started */ |
2917 | if (!netif_running(dev: vsi->netdev)) { |
2918 | ice_for_each_alloc_txq(vsi, i) |
2919 | vsi->tx_rings[i]->count = new_tx_cnt; |
2920 | ice_for_each_alloc_rxq(vsi, i) |
2921 | vsi->rx_rings[i]->count = new_rx_cnt; |
2922 | if (ice_is_xdp_ena_vsi(vsi)) |
2923 | ice_for_each_xdp_txq(vsi, i) |
2924 | vsi->xdp_rings[i]->count = new_tx_cnt; |
2925 | vsi->num_tx_desc = (u16)new_tx_cnt; |
2926 | vsi->num_rx_desc = (u16)new_rx_cnt; |
2927 | netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n" ); |
2928 | goto done; |
2929 | } |
2930 | |
2931 | if (new_tx_cnt == vsi->tx_rings[0]->count) |
2932 | goto process_rx; |
2933 | |
2934 | /* alloc updated Tx resources */ |
2935 | netdev_info(dev: netdev, format: "Changing Tx descriptor count from %d to %d\n" , |
2936 | vsi->tx_rings[0]->count, new_tx_cnt); |
2937 | |
2938 | tx_rings = kcalloc(n: vsi->num_txq, size: sizeof(*tx_rings), GFP_KERNEL); |
2939 | if (!tx_rings) { |
2940 | err = -ENOMEM; |
2941 | goto done; |
2942 | } |
2943 | |
2944 | ice_for_each_txq(vsi, i) { |
2945 | /* clone ring and setup updated count */ |
2946 | tx_rings[i] = *vsi->tx_rings[i]; |
2947 | tx_rings[i].count = new_tx_cnt; |
2948 | tx_rings[i].desc = NULL; |
2949 | tx_rings[i].tx_buf = NULL; |
2950 | tx_rings[i].tx_tstamps = &pf->ptp.port.tx; |
2951 | err = ice_setup_tx_ring(tx_ring: &tx_rings[i]); |
2952 | if (err) { |
2953 | while (i--) |
2954 | ice_clean_tx_ring(tx_ring: &tx_rings[i]); |
2955 | kfree(objp: tx_rings); |
2956 | goto done; |
2957 | } |
2958 | } |
2959 | |
2960 | if (!ice_is_xdp_ena_vsi(vsi)) |
2961 | goto process_rx; |
2962 | |
2963 | /* alloc updated XDP resources */ |
2964 | netdev_info(dev: netdev, format: "Changing XDP descriptor count from %d to %d\n" , |
2965 | vsi->xdp_rings[0]->count, new_tx_cnt); |
2966 | |
2967 | xdp_rings = kcalloc(n: vsi->num_xdp_txq, size: sizeof(*xdp_rings), GFP_KERNEL); |
2968 | if (!xdp_rings) { |
2969 | err = -ENOMEM; |
2970 | goto free_tx; |
2971 | } |
2972 | |
2973 | ice_for_each_xdp_txq(vsi, i) { |
2974 | /* clone ring and setup updated count */ |
2975 | xdp_rings[i] = *vsi->xdp_rings[i]; |
2976 | xdp_rings[i].count = new_tx_cnt; |
2977 | xdp_rings[i].desc = NULL; |
2978 | xdp_rings[i].tx_buf = NULL; |
2979 | err = ice_setup_tx_ring(tx_ring: &xdp_rings[i]); |
2980 | if (err) { |
2981 | while (i--) |
2982 | ice_clean_tx_ring(tx_ring: &xdp_rings[i]); |
2983 | kfree(objp: xdp_rings); |
2984 | goto free_tx; |
2985 | } |
2986 | ice_set_ring_xdp(ring: &xdp_rings[i]); |
2987 | } |
2988 | |
2989 | process_rx: |
2990 | if (new_rx_cnt == vsi->rx_rings[0]->count) |
2991 | goto process_link; |
2992 | |
2993 | /* alloc updated Rx resources */ |
2994 | netdev_info(dev: netdev, format: "Changing Rx descriptor count from %d to %d\n" , |
2995 | vsi->rx_rings[0]->count, new_rx_cnt); |
2996 | |
2997 | rx_rings = kcalloc(n: vsi->num_rxq, size: sizeof(*rx_rings), GFP_KERNEL); |
2998 | if (!rx_rings) { |
2999 | err = -ENOMEM; |
3000 | goto done; |
3001 | } |
3002 | |
3003 | ice_for_each_rxq(vsi, i) { |
3004 | /* clone ring and setup updated count */ |
3005 | rx_rings[i] = *vsi->rx_rings[i]; |
3006 | rx_rings[i].count = new_rx_cnt; |
3007 | rx_rings[i].cached_phctime = pf->ptp.cached_phc_time; |
3008 | rx_rings[i].desc = NULL; |
3009 | rx_rings[i].rx_buf = NULL; |
3010 | /* this is to allow wr32 to have something to write to |
3011 | * during early allocation of Rx buffers |
3012 | */ |
3013 | rx_rings[i].tail = vsi->back->hw.hw_addr + PRTGEN_STATUS; |
3014 | |
3015 | err = ice_setup_rx_ring(rx_ring: &rx_rings[i]); |
3016 | if (err) |
3017 | goto rx_unwind; |
3018 | |
3019 | /* allocate Rx buffers */ |
3020 | err = ice_alloc_rx_bufs(rxr: &rx_rings[i], |
3021 | ICE_RX_DESC_UNUSED(&rx_rings[i])); |
3022 | rx_unwind: |
3023 | if (err) { |
3024 | while (i) { |
3025 | i--; |
3026 | ice_free_rx_ring(rx_ring: &rx_rings[i]); |
3027 | } |
3028 | kfree(objp: rx_rings); |
3029 | err = -ENOMEM; |
3030 | goto free_tx; |
3031 | } |
3032 | } |
3033 | |
3034 | process_link: |
3035 | /* Bring interface down, copy in the new ring info, then restore the |
3036 | * interface. if VSI is up, bring it down and then back up |
3037 | */ |
3038 | if (!test_and_set_bit(nr: ICE_VSI_DOWN, addr: vsi->state)) { |
3039 | ice_down(vsi); |
3040 | |
3041 | if (tx_rings) { |
3042 | ice_for_each_txq(vsi, i) { |
3043 | ice_free_tx_ring(tx_ring: vsi->tx_rings[i]); |
3044 | *vsi->tx_rings[i] = tx_rings[i]; |
3045 | } |
3046 | kfree(objp: tx_rings); |
3047 | } |
3048 | |
3049 | if (rx_rings) { |
3050 | ice_for_each_rxq(vsi, i) { |
3051 | ice_free_rx_ring(rx_ring: vsi->rx_rings[i]); |
3052 | /* copy the real tail offset */ |
3053 | rx_rings[i].tail = vsi->rx_rings[i]->tail; |
3054 | /* this is to fake out the allocation routine |
3055 | * into thinking it has to realloc everything |
3056 | * but the recycling logic will let us re-use |
3057 | * the buffers allocated above |
3058 | */ |
3059 | rx_rings[i].next_to_use = 0; |
3060 | rx_rings[i].next_to_clean = 0; |
3061 | rx_rings[i].next_to_alloc = 0; |
3062 | *vsi->rx_rings[i] = rx_rings[i]; |
3063 | } |
3064 | kfree(objp: rx_rings); |
3065 | } |
3066 | |
3067 | if (xdp_rings) { |
3068 | ice_for_each_xdp_txq(vsi, i) { |
3069 | ice_free_tx_ring(tx_ring: vsi->xdp_rings[i]); |
3070 | *vsi->xdp_rings[i] = xdp_rings[i]; |
3071 | } |
3072 | kfree(objp: xdp_rings); |
3073 | } |
3074 | |
3075 | vsi->num_tx_desc = new_tx_cnt; |
3076 | vsi->num_rx_desc = new_rx_cnt; |
3077 | ice_up(vsi); |
3078 | } |
3079 | goto done; |
3080 | |
3081 | free_tx: |
3082 | /* error cleanup if the Rx allocations failed after getting Tx */ |
3083 | if (tx_rings) { |
3084 | ice_for_each_txq(vsi, i) |
3085 | ice_free_tx_ring(tx_ring: &tx_rings[i]); |
3086 | kfree(objp: tx_rings); |
3087 | } |
3088 | |
3089 | done: |
3090 | clear_bit(nr: ICE_CFG_BUSY, addr: pf->state); |
3091 | return err; |
3092 | } |
3093 | |
3094 | /** |
3095 | * ice_get_pauseparam - Get Flow Control status |
3096 | * @netdev: network interface device structure |
3097 | * @pause: ethernet pause (flow control) parameters |
3098 | * |
3099 | * Get requested flow control status from PHY capability. |
3100 | * If autoneg is true, then ethtool will send the ETHTOOL_GSET ioctl which |
3101 | * is handled by ice_get_link_ksettings. ice_get_link_ksettings will report |
3102 | * the negotiated Rx/Tx pause via lp_advertising. |
3103 | */ |
3104 | static void |
3105 | ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) |
3106 | { |
3107 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3108 | struct ice_port_info *pi = np->vsi->port_info; |
3109 | struct ice_aqc_get_phy_caps_data *pcaps; |
3110 | struct ice_dcbx_cfg *dcbx_cfg; |
3111 | int status; |
3112 | |
3113 | /* Initialize pause params */ |
3114 | pause->rx_pause = 0; |
3115 | pause->tx_pause = 0; |
3116 | |
3117 | dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; |
3118 | |
3119 | pcaps = kzalloc(size: sizeof(*pcaps), GFP_KERNEL); |
3120 | if (!pcaps) |
3121 | return; |
3122 | |
3123 | /* Get current PHY config */ |
3124 | status = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_ACTIVE_CFG, caps: pcaps, |
3125 | NULL); |
3126 | if (status) |
3127 | goto out; |
3128 | |
3129 | pause->autoneg = ice_is_phy_caps_an_enabled(caps: pcaps) ? AUTONEG_ENABLE : |
3130 | AUTONEG_DISABLE; |
3131 | |
3132 | if (dcbx_cfg->pfc.pfcena) |
3133 | /* PFC enabled so report LFC as off */ |
3134 | goto out; |
3135 | |
3136 | if (pcaps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) |
3137 | pause->tx_pause = 1; |
3138 | if (pcaps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) |
3139 | pause->rx_pause = 1; |
3140 | |
3141 | out: |
3142 | kfree(objp: pcaps); |
3143 | } |
3144 | |
3145 | /** |
3146 | * ice_set_pauseparam - Set Flow Control parameter |
3147 | * @netdev: network interface device structure |
3148 | * @pause: return Tx/Rx flow control status |
3149 | */ |
3150 | static int |
3151 | ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) |
3152 | { |
3153 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3154 | struct ice_aqc_get_phy_caps_data *pcaps; |
3155 | struct ice_link_status *hw_link_info; |
3156 | struct ice_pf *pf = np->vsi->back; |
3157 | struct ice_dcbx_cfg *dcbx_cfg; |
3158 | struct ice_vsi *vsi = np->vsi; |
3159 | struct ice_hw *hw = &pf->hw; |
3160 | struct ice_port_info *pi; |
3161 | u8 aq_failures; |
3162 | bool link_up; |
3163 | u32 is_an; |
3164 | int err; |
3165 | |
3166 | pi = vsi->port_info; |
3167 | hw_link_info = &pi->phy.link_info; |
3168 | dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; |
3169 | link_up = hw_link_info->link_info & ICE_AQ_LINK_UP; |
3170 | |
3171 | /* Changing the port's flow control is not supported if this isn't the |
3172 | * PF VSI |
3173 | */ |
3174 | if (vsi->type != ICE_VSI_PF) { |
3175 | netdev_info(dev: netdev, format: "Changing flow control parameters only supported for PF VSI\n" ); |
3176 | return -EOPNOTSUPP; |
3177 | } |
3178 | |
3179 | /* Get pause param reports configured and negotiated flow control pause |
3180 | * when ETHTOOL_GLINKSETTINGS is defined. Since ETHTOOL_GLINKSETTINGS is |
3181 | * defined get pause param pause->autoneg reports SW configured setting, |
3182 | * so compare pause->autoneg with SW configured to prevent the user from |
3183 | * using set pause param to chance autoneg. |
3184 | */ |
3185 | pcaps = kzalloc(size: sizeof(*pcaps), GFP_KERNEL); |
3186 | if (!pcaps) |
3187 | return -ENOMEM; |
3188 | |
3189 | /* Get current PHY config */ |
3190 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_ACTIVE_CFG, caps: pcaps, |
3191 | NULL); |
3192 | if (err) { |
3193 | kfree(objp: pcaps); |
3194 | return err; |
3195 | } |
3196 | |
3197 | is_an = ice_is_phy_caps_an_enabled(caps: pcaps) ? AUTONEG_ENABLE : |
3198 | AUTONEG_DISABLE; |
3199 | |
3200 | kfree(objp: pcaps); |
3201 | |
3202 | if (pause->autoneg != is_an) { |
3203 | netdev_info(dev: netdev, format: "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n" ); |
3204 | return -EOPNOTSUPP; |
3205 | } |
3206 | |
3207 | /* If we have link and don't have autoneg */ |
3208 | if (!test_bit(ICE_DOWN, pf->state) && |
3209 | !(hw_link_info->an_info & ICE_AQ_AN_COMPLETED)) { |
3210 | /* Send message that it might not necessarily work*/ |
3211 | netdev_info(dev: netdev, format: "Autoneg did not complete so changing settings may not result in an actual change.\n" ); |
3212 | } |
3213 | |
3214 | if (dcbx_cfg->pfc.pfcena) { |
3215 | netdev_info(dev: netdev, format: "Priority flow control enabled. Cannot set link flow control.\n" ); |
3216 | return -EOPNOTSUPP; |
3217 | } |
3218 | if (pause->rx_pause && pause->tx_pause) |
3219 | pi->fc.req_mode = ICE_FC_FULL; |
3220 | else if (pause->rx_pause && !pause->tx_pause) |
3221 | pi->fc.req_mode = ICE_FC_RX_PAUSE; |
3222 | else if (!pause->rx_pause && pause->tx_pause) |
3223 | pi->fc.req_mode = ICE_FC_TX_PAUSE; |
3224 | else if (!pause->rx_pause && !pause->tx_pause) |
3225 | pi->fc.req_mode = ICE_FC_NONE; |
3226 | else |
3227 | return -EINVAL; |
3228 | |
3229 | /* Set the FC mode and only restart AN if link is up */ |
3230 | err = ice_set_fc(pi, aq_failures: &aq_failures, ena_auto_link_update: link_up); |
3231 | |
3232 | if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) { |
3233 | netdev_info(dev: netdev, format: "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n" , |
3234 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3235 | err = -EAGAIN; |
3236 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) { |
3237 | netdev_info(dev: netdev, format: "Set fc failed on the set_phy_config call with err %d aq_err %s\n" , |
3238 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3239 | err = -EAGAIN; |
3240 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) { |
3241 | netdev_info(dev: netdev, format: "Set fc failed on the get_link_info call with err %d aq_err %s\n" , |
3242 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3243 | err = -EAGAIN; |
3244 | } |
3245 | |
3246 | return err; |
3247 | } |
3248 | |
3249 | /** |
3250 | * ice_get_rxfh_key_size - get the RSS hash key size |
3251 | * @netdev: network interface device structure |
3252 | * |
3253 | * Returns the table size. |
3254 | */ |
3255 | static u32 ice_get_rxfh_key_size(struct net_device __always_unused *netdev) |
3256 | { |
3257 | return ICE_VSIQF_HKEY_ARRAY_SIZE; |
3258 | } |
3259 | |
3260 | /** |
3261 | * ice_get_rxfh_indir_size - get the Rx flow hash indirection table size |
3262 | * @netdev: network interface device structure |
3263 | * |
3264 | * Returns the table size. |
3265 | */ |
3266 | static u32 ice_get_rxfh_indir_size(struct net_device *netdev) |
3267 | { |
3268 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3269 | |
3270 | return np->vsi->rss_table_size; |
3271 | } |
3272 | |
3273 | /** |
3274 | * ice_get_rxfh - get the Rx flow hash indirection table |
3275 | * @netdev: network interface device structure |
3276 | * @rxfh: pointer to param struct (indir, key, hfunc) |
3277 | * |
3278 | * Reads the indirection table directly from the hardware. |
3279 | */ |
3280 | static int |
3281 | ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) |
3282 | { |
3283 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3284 | u32 = rxfh->rss_context; |
3285 | struct ice_vsi *vsi = np->vsi; |
3286 | struct ice_pf *pf = vsi->back; |
3287 | u16 qcount, offset; |
3288 | int err, num_tc, i; |
3289 | u8 *lut; |
3290 | |
3291 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { |
3292 | netdev_warn(dev: netdev, format: "RSS is not supported on this VSI!\n" ); |
3293 | return -EOPNOTSUPP; |
3294 | } |
3295 | |
3296 | if (rss_context && !ice_is_adq_active(pf)) { |
3297 | netdev_err(dev: netdev, format: "RSS context cannot be non-zero when ADQ is not configured.\n" ); |
3298 | return -EINVAL; |
3299 | } |
3300 | |
3301 | qcount = vsi->mqprio_qopt.qopt.count[rss_context]; |
3302 | offset = vsi->mqprio_qopt.qopt.offset[rss_context]; |
3303 | |
3304 | if (rss_context && ice_is_adq_active(pf)) { |
3305 | num_tc = vsi->mqprio_qopt.qopt.num_tc; |
3306 | if (rss_context >= num_tc) { |
3307 | netdev_err(dev: netdev, format: "RSS context:%d > num_tc:%d\n" , |
3308 | rss_context, num_tc); |
3309 | return -EINVAL; |
3310 | } |
3311 | /* Use channel VSI of given TC */ |
3312 | vsi = vsi->tc_map_vsi[rss_context]; |
3313 | } |
3314 | |
3315 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
3316 | if (vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ) |
3317 | rxfh->input_xfrm |= RXH_XFRM_SYM_XOR; |
3318 | |
3319 | if (!rxfh->indir) |
3320 | return 0; |
3321 | |
3322 | lut = kzalloc(size: vsi->rss_table_size, GFP_KERNEL); |
3323 | if (!lut) |
3324 | return -ENOMEM; |
3325 | |
3326 | err = ice_get_rss_key(vsi, seed: rxfh->key); |
3327 | if (err) |
3328 | goto out; |
3329 | |
3330 | err = ice_get_rss_lut(vsi, lut, lut_size: vsi->rss_table_size); |
3331 | if (err) |
3332 | goto out; |
3333 | |
3334 | if (ice_is_adq_active(pf)) { |
3335 | for (i = 0; i < vsi->rss_table_size; i++) |
3336 | rxfh->indir[i] = offset + lut[i] % qcount; |
3337 | goto out; |
3338 | } |
3339 | |
3340 | for (i = 0; i < vsi->rss_table_size; i++) |
3341 | rxfh->indir[i] = lut[i]; |
3342 | |
3343 | out: |
3344 | kfree(objp: lut); |
3345 | return err; |
3346 | } |
3347 | |
3348 | /** |
3349 | * ice_set_rxfh - set the Rx flow hash indirection table |
3350 | * @netdev: network interface device structure |
3351 | * @rxfh: pointer to param struct (indir, key, hfunc) |
3352 | * @extack: extended ACK from the Netlink message |
3353 | * |
3354 | * Returns -EINVAL if the table specifies an invalid queue ID, otherwise |
3355 | * returns 0 after programming the table. |
3356 | */ |
3357 | static int |
3358 | ice_set_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh, |
3359 | struct netlink_ext_ack *extack) |
3360 | { |
3361 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3362 | u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; |
3363 | struct ice_vsi *vsi = np->vsi; |
3364 | struct ice_pf *pf = vsi->back; |
3365 | struct device *dev; |
3366 | int err; |
3367 | |
3368 | dev = ice_pf_to_dev(pf); |
3369 | if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && |
3370 | rxfh->hfunc != ETH_RSS_HASH_TOP) |
3371 | return -EOPNOTSUPP; |
3372 | |
3373 | if (rxfh->rss_context) |
3374 | return -EOPNOTSUPP; |
3375 | |
3376 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { |
3377 | /* RSS not supported return error here */ |
3378 | netdev_warn(dev: netdev, format: "RSS is not configured on this VSI!\n" ); |
3379 | return -EIO; |
3380 | } |
3381 | |
3382 | if (ice_is_adq_active(pf)) { |
3383 | netdev_err(dev: netdev, format: "Cannot change RSS params with ADQ configured.\n" ); |
3384 | return -EOPNOTSUPP; |
3385 | } |
3386 | |
3387 | /* Update the VSI's hash function */ |
3388 | if (rxfh->input_xfrm & RXH_XFRM_SYM_XOR) |
3389 | hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ; |
3390 | |
3391 | err = ice_set_rss_hfunc(vsi, hfunc); |
3392 | if (err) |
3393 | return err; |
3394 | |
3395 | if (rxfh->key) { |
3396 | if (!vsi->rss_hkey_user) { |
3397 | vsi->rss_hkey_user = |
3398 | devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE, |
3399 | GFP_KERNEL); |
3400 | if (!vsi->rss_hkey_user) |
3401 | return -ENOMEM; |
3402 | } |
3403 | memcpy(vsi->rss_hkey_user, rxfh->key, |
3404 | ICE_VSIQF_HKEY_ARRAY_SIZE); |
3405 | |
3406 | err = ice_set_rss_key(vsi, seed: vsi->rss_hkey_user); |
3407 | if (err) |
3408 | return err; |
3409 | } |
3410 | |
3411 | if (!vsi->rss_lut_user) { |
3412 | vsi->rss_lut_user = devm_kzalloc(dev, size: vsi->rss_table_size, |
3413 | GFP_KERNEL); |
3414 | if (!vsi->rss_lut_user) |
3415 | return -ENOMEM; |
3416 | } |
3417 | |
3418 | /* Each 32 bits pointed by 'indir' is stored with a lut entry */ |
3419 | if (rxfh->indir) { |
3420 | int i; |
3421 | |
3422 | for (i = 0; i < vsi->rss_table_size; i++) |
3423 | vsi->rss_lut_user[i] = (u8)(rxfh->indir[i]); |
3424 | } else { |
3425 | ice_fill_rss_lut(lut: vsi->rss_lut_user, rss_table_size: vsi->rss_table_size, |
3426 | rss_size: vsi->rss_size); |
3427 | } |
3428 | |
3429 | err = ice_set_rss_lut(vsi, lut: vsi->rss_lut_user, lut_size: vsi->rss_table_size); |
3430 | if (err) |
3431 | return err; |
3432 | |
3433 | return 0; |
3434 | } |
3435 | |
3436 | static int |
3437 | ice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) |
3438 | { |
3439 | struct ice_pf *pf = ice_netdev_to_pf(netdev: dev); |
3440 | |
3441 | /* only report timestamping if PTP is enabled */ |
3442 | if (pf->ptp.state != ICE_PTP_READY) |
3443 | return ethtool_op_get_ts_info(dev, eti: info); |
3444 | |
3445 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
3446 | SOF_TIMESTAMPING_RX_SOFTWARE | |
3447 | SOF_TIMESTAMPING_SOFTWARE | |
3448 | SOF_TIMESTAMPING_TX_HARDWARE | |
3449 | SOF_TIMESTAMPING_RX_HARDWARE | |
3450 | SOF_TIMESTAMPING_RAW_HARDWARE; |
3451 | |
3452 | info->phc_index = ice_ptp_clock_index(pf); |
3453 | |
3454 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); |
3455 | |
3456 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); |
3457 | |
3458 | return 0; |
3459 | } |
3460 | |
3461 | /** |
3462 | * ice_get_max_txq - return the maximum number of Tx queues for in a PF |
3463 | * @pf: PF structure |
3464 | */ |
3465 | static int ice_get_max_txq(struct ice_pf *pf) |
3466 | { |
3467 | return min3(pf->num_lan_msix, (u16)num_online_cpus(), |
3468 | (u16)pf->hw.func_caps.common_cap.num_txq); |
3469 | } |
3470 | |
3471 | /** |
3472 | * ice_get_max_rxq - return the maximum number of Rx queues for in a PF |
3473 | * @pf: PF structure |
3474 | */ |
3475 | static int ice_get_max_rxq(struct ice_pf *pf) |
3476 | { |
3477 | return min3(pf->num_lan_msix, (u16)num_online_cpus(), |
3478 | (u16)pf->hw.func_caps.common_cap.num_rxq); |
3479 | } |
3480 | |
3481 | /** |
3482 | * ice_get_combined_cnt - return the current number of combined channels |
3483 | * @vsi: PF VSI pointer |
3484 | * |
3485 | * Go through all queue vectors and count ones that have both Rx and Tx ring |
3486 | * attached |
3487 | */ |
3488 | static u32 ice_get_combined_cnt(struct ice_vsi *vsi) |
3489 | { |
3490 | u32 combined = 0; |
3491 | int q_idx; |
3492 | |
3493 | ice_for_each_q_vector(vsi, q_idx) { |
3494 | struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; |
3495 | |
3496 | if (q_vector->rx.rx_ring && q_vector->tx.tx_ring) |
3497 | combined++; |
3498 | } |
3499 | |
3500 | return combined; |
3501 | } |
3502 | |
3503 | /** |
3504 | * ice_get_channels - get the current and max supported channels |
3505 | * @dev: network interface device structure |
3506 | * @ch: ethtool channel data structure |
3507 | */ |
3508 | static void |
3509 | ice_get_channels(struct net_device *dev, struct ethtool_channels *ch) |
3510 | { |
3511 | struct ice_netdev_priv *np = netdev_priv(dev); |
3512 | struct ice_vsi *vsi = np->vsi; |
3513 | struct ice_pf *pf = vsi->back; |
3514 | |
3515 | /* report maximum channels */ |
3516 | ch->max_rx = ice_get_max_rxq(pf); |
3517 | ch->max_tx = ice_get_max_txq(pf); |
3518 | ch->max_combined = min_t(int, ch->max_rx, ch->max_tx); |
3519 | |
3520 | /* report current channels */ |
3521 | ch->combined_count = ice_get_combined_cnt(vsi); |
3522 | ch->rx_count = vsi->num_rxq - ch->combined_count; |
3523 | ch->tx_count = vsi->num_txq - ch->combined_count; |
3524 | |
3525 | /* report other queues */ |
3526 | ch->other_count = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0; |
3527 | ch->max_other = ch->other_count; |
3528 | } |
3529 | |
3530 | /** |
3531 | * ice_get_valid_rss_size - return valid number of RSS queues |
3532 | * @hw: pointer to the HW structure |
3533 | * @new_size: requested RSS queues |
3534 | */ |
3535 | static int (struct ice_hw *hw, int new_size) |
3536 | { |
3537 | struct ice_hw_common_caps *caps = &hw->func_caps.common_cap; |
3538 | |
3539 | return min_t(int, new_size, BIT(caps->rss_table_entry_width)); |
3540 | } |
3541 | |
3542 | /** |
3543 | * ice_vsi_set_dflt_rss_lut - set default RSS LUT with requested RSS size |
3544 | * @vsi: VSI to reconfigure RSS LUT on |
3545 | * @req_rss_size: requested range of queue numbers for hashing |
3546 | * |
3547 | * Set the VSI's RSS parameters, configure the RSS LUT based on these. |
3548 | */ |
3549 | static int (struct ice_vsi *vsi, int ) |
3550 | { |
3551 | struct ice_pf *pf = vsi->back; |
3552 | struct device *dev; |
3553 | struct ice_hw *hw; |
3554 | int err; |
3555 | u8 *lut; |
3556 | |
3557 | dev = ice_pf_to_dev(pf); |
3558 | hw = &pf->hw; |
3559 | |
3560 | if (!req_rss_size) |
3561 | return -EINVAL; |
3562 | |
3563 | lut = kzalloc(size: vsi->rss_table_size, GFP_KERNEL); |
3564 | if (!lut) |
3565 | return -ENOMEM; |
3566 | |
3567 | /* set RSS LUT parameters */ |
3568 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) |
3569 | vsi->rss_size = 1; |
3570 | else |
3571 | vsi->rss_size = ice_get_valid_rss_size(hw, new_size: req_rss_size); |
3572 | |
3573 | /* create/set RSS LUT */ |
3574 | ice_fill_rss_lut(lut, rss_table_size: vsi->rss_table_size, rss_size: vsi->rss_size); |
3575 | err = ice_set_rss_lut(vsi, lut, lut_size: vsi->rss_table_size); |
3576 | if (err) |
3577 | dev_err(dev, "Cannot set RSS lut, err %d aq_err %s\n" , err, |
3578 | ice_aq_str(hw->adminq.sq_last_status)); |
3579 | |
3580 | kfree(objp: lut); |
3581 | return err; |
3582 | } |
3583 | |
3584 | /** |
3585 | * ice_set_channels - set the number channels |
3586 | * @dev: network interface device structure |
3587 | * @ch: ethtool channel data structure |
3588 | */ |
3589 | static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) |
3590 | { |
3591 | struct ice_netdev_priv *np = netdev_priv(dev); |
3592 | struct ice_vsi *vsi = np->vsi; |
3593 | struct ice_pf *pf = vsi->back; |
3594 | int new_rx = 0, new_tx = 0; |
3595 | bool locked = false; |
3596 | u32 curr_combined; |
3597 | int ret = 0; |
3598 | |
3599 | /* do not support changing channels in Safe Mode */ |
3600 | if (ice_is_safe_mode(pf)) { |
3601 | netdev_err(dev, format: "Changing channel in Safe Mode is not supported\n" ); |
3602 | return -EOPNOTSUPP; |
3603 | } |
3604 | /* do not support changing other_count */ |
3605 | if (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U)) |
3606 | return -EINVAL; |
3607 | |
3608 | if (ice_is_adq_active(pf)) { |
3609 | netdev_err(dev, format: "Cannot set channels with ADQ configured.\n" ); |
3610 | return -EOPNOTSUPP; |
3611 | } |
3612 | |
3613 | if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) { |
3614 | netdev_err(dev, format: "Cannot set channels when Flow Director filters are active\n" ); |
3615 | return -EOPNOTSUPP; |
3616 | } |
3617 | |
3618 | curr_combined = ice_get_combined_cnt(vsi); |
3619 | |
3620 | /* these checks are for cases where user didn't specify a particular |
3621 | * value on cmd line but we get non-zero value anyway via |
3622 | * get_channels(); look at ethtool.c in ethtool repository (the user |
3623 | * space part), particularly, do_schannels() routine |
3624 | */ |
3625 | if (ch->rx_count == vsi->num_rxq - curr_combined) |
3626 | ch->rx_count = 0; |
3627 | if (ch->tx_count == vsi->num_txq - curr_combined) |
3628 | ch->tx_count = 0; |
3629 | if (ch->combined_count == curr_combined) |
3630 | ch->combined_count = 0; |
3631 | |
3632 | if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) { |
3633 | netdev_err(dev, format: "Please specify at least 1 Rx and 1 Tx channel\n" ); |
3634 | return -EINVAL; |
3635 | } |
3636 | |
3637 | new_rx = ch->combined_count + ch->rx_count; |
3638 | new_tx = ch->combined_count + ch->tx_count; |
3639 | |
3640 | if (new_rx < vsi->tc_cfg.numtc) { |
3641 | netdev_err(dev, format: "Cannot set less Rx channels, than Traffic Classes you have (%u)\n" , |
3642 | vsi->tc_cfg.numtc); |
3643 | return -EINVAL; |
3644 | } |
3645 | if (new_tx < vsi->tc_cfg.numtc) { |
3646 | netdev_err(dev, format: "Cannot set less Tx channels, than Traffic Classes you have (%u)\n" , |
3647 | vsi->tc_cfg.numtc); |
3648 | return -EINVAL; |
3649 | } |
3650 | if (new_rx > ice_get_max_rxq(pf)) { |
3651 | netdev_err(dev, format: "Maximum allowed Rx channels is %d\n" , |
3652 | ice_get_max_rxq(pf)); |
3653 | return -EINVAL; |
3654 | } |
3655 | if (new_tx > ice_get_max_txq(pf)) { |
3656 | netdev_err(dev, format: "Maximum allowed Tx channels is %d\n" , |
3657 | ice_get_max_txq(pf)); |
3658 | return -EINVAL; |
3659 | } |
3660 | |
3661 | if (pf->adev) { |
3662 | mutex_lock(&pf->adev_mutex); |
3663 | device_lock(dev: &pf->adev->dev); |
3664 | locked = true; |
3665 | if (pf->adev->dev.driver) { |
3666 | netdev_err(dev, format: "Cannot change channels when RDMA is active\n" ); |
3667 | ret = -EBUSY; |
3668 | goto adev_unlock; |
3669 | } |
3670 | } |
3671 | |
3672 | ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked); |
3673 | |
3674 | if (!netif_is_rxfh_configured(dev)) { |
3675 | ret = ice_vsi_set_dflt_rss_lut(vsi, req_rss_size: new_rx); |
3676 | goto adev_unlock; |
3677 | } |
3678 | |
3679 | /* Update rss_size due to change in Rx queues */ |
3680 | vsi->rss_size = ice_get_valid_rss_size(hw: &pf->hw, new_size: new_rx); |
3681 | |
3682 | adev_unlock: |
3683 | if (locked) { |
3684 | device_unlock(dev: &pf->adev->dev); |
3685 | mutex_unlock(lock: &pf->adev_mutex); |
3686 | } |
3687 | return ret; |
3688 | } |
3689 | |
3690 | /** |
3691 | * ice_get_wol - get current Wake on LAN configuration |
3692 | * @netdev: network interface device structure |
3693 | * @wol: Ethtool structure to retrieve WoL settings |
3694 | */ |
3695 | static void ice_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) |
3696 | { |
3697 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3698 | struct ice_pf *pf = np->vsi->back; |
3699 | |
3700 | if (np->vsi->type != ICE_VSI_PF) |
3701 | netdev_warn(dev: netdev, format: "Wake on LAN is not supported on this interface!\n" ); |
3702 | |
3703 | /* Get WoL settings based on the HW capability */ |
3704 | if (ice_is_wol_supported(hw: &pf->hw)) { |
3705 | wol->supported = WAKE_MAGIC; |
3706 | wol->wolopts = pf->wol_ena ? WAKE_MAGIC : 0; |
3707 | } else { |
3708 | wol->supported = 0; |
3709 | wol->wolopts = 0; |
3710 | } |
3711 | } |
3712 | |
3713 | /** |
3714 | * ice_set_wol - set Wake on LAN on supported device |
3715 | * @netdev: network interface device structure |
3716 | * @wol: Ethtool structure to set WoL |
3717 | */ |
3718 | static int ice_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) |
3719 | { |
3720 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3721 | struct ice_vsi *vsi = np->vsi; |
3722 | struct ice_pf *pf = vsi->back; |
3723 | |
3724 | if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(hw: &pf->hw)) |
3725 | return -EOPNOTSUPP; |
3726 | |
3727 | /* only magic packet is supported */ |
3728 | if (wol->wolopts && wol->wolopts != WAKE_MAGIC) |
3729 | return -EOPNOTSUPP; |
3730 | |
3731 | /* Set WoL only if there is a new value */ |
3732 | if (pf->wol_ena != !!wol->wolopts) { |
3733 | pf->wol_ena = !!wol->wolopts; |
3734 | device_set_wakeup_enable(ice_pf_to_dev(pf), enable: pf->wol_ena); |
3735 | netdev_dbg(netdev, "WoL magic packet %sabled\n" , |
3736 | pf->wol_ena ? "en" : "dis" ); |
3737 | } |
3738 | |
3739 | return 0; |
3740 | } |
3741 | |
3742 | /** |
3743 | * ice_get_rc_coalesce - get ITR values for specific ring container |
3744 | * @ec: ethtool structure to fill with driver's coalesce settings |
3745 | * @rc: ring container that the ITR values will come from |
3746 | * |
3747 | * Query the device for ice_ring_container specific ITR values. This is |
3748 | * done per ice_ring_container because each q_vector can have 1 or more rings |
3749 | * and all of said ring(s) will have the same ITR values. |
3750 | * |
3751 | * Returns 0 on success, negative otherwise. |
3752 | */ |
3753 | static int |
3754 | ice_get_rc_coalesce(struct ethtool_coalesce *ec, struct ice_ring_container *rc) |
3755 | { |
3756 | if (!rc->rx_ring) |
3757 | return -EINVAL; |
3758 | |
3759 | switch (rc->type) { |
3760 | case ICE_RX_CONTAINER: |
3761 | ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc); |
3762 | ec->rx_coalesce_usecs = rc->itr_setting; |
3763 | ec->rx_coalesce_usecs_high = rc->rx_ring->q_vector->intrl; |
3764 | break; |
3765 | case ICE_TX_CONTAINER: |
3766 | ec->use_adaptive_tx_coalesce = ITR_IS_DYNAMIC(rc); |
3767 | ec->tx_coalesce_usecs = rc->itr_setting; |
3768 | break; |
3769 | default: |
3770 | dev_dbg(ice_pf_to_dev(rc->rx_ring->vsi->back), "Invalid c_type %d\n" , rc->type); |
3771 | return -EINVAL; |
3772 | } |
3773 | |
3774 | return 0; |
3775 | } |
3776 | |
3777 | /** |
3778 | * ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings |
3779 | * @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings |
3780 | * @ec: coalesce settings to program the device with |
3781 | * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index |
3782 | * |
3783 | * Return 0 on success, and negative under the following conditions: |
3784 | * 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed. |
3785 | * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. |
3786 | */ |
3787 | static int |
3788 | ice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) |
3789 | { |
3790 | if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { |
3791 | if (ice_get_rc_coalesce(ec, |
3792 | rc: &vsi->rx_rings[q_num]->q_vector->rx)) |
3793 | return -EINVAL; |
3794 | if (ice_get_rc_coalesce(ec, |
3795 | rc: &vsi->tx_rings[q_num]->q_vector->tx)) |
3796 | return -EINVAL; |
3797 | } else if (q_num < vsi->num_rxq) { |
3798 | if (ice_get_rc_coalesce(ec, |
3799 | rc: &vsi->rx_rings[q_num]->q_vector->rx)) |
3800 | return -EINVAL; |
3801 | } else if (q_num < vsi->num_txq) { |
3802 | if (ice_get_rc_coalesce(ec, |
3803 | rc: &vsi->tx_rings[q_num]->q_vector->tx)) |
3804 | return -EINVAL; |
3805 | } else { |
3806 | return -EINVAL; |
3807 | } |
3808 | |
3809 | return 0; |
3810 | } |
3811 | |
3812 | /** |
3813 | * __ice_get_coalesce - get ITR/INTRL values for the device |
3814 | * @netdev: pointer to the netdev associated with this query |
3815 | * @ec: ethtool structure to fill with driver's coalesce settings |
3816 | * @q_num: queue number to get the coalesce settings for |
3817 | * |
3818 | * If the caller passes in a negative q_num then we return coalesce settings |
3819 | * based on queue number 0, else use the actual q_num passed in. |
3820 | */ |
3821 | static int |
3822 | __ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, |
3823 | int q_num) |
3824 | { |
3825 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3826 | struct ice_vsi *vsi = np->vsi; |
3827 | |
3828 | if (q_num < 0) |
3829 | q_num = 0; |
3830 | |
3831 | if (ice_get_q_coalesce(vsi, ec, q_num)) |
3832 | return -EINVAL; |
3833 | |
3834 | return 0; |
3835 | } |
3836 | |
3837 | static int ice_get_coalesce(struct net_device *netdev, |
3838 | struct ethtool_coalesce *ec, |
3839 | struct kernel_ethtool_coalesce *kernel_coal, |
3840 | struct netlink_ext_ack *extack) |
3841 | { |
3842 | return __ice_get_coalesce(netdev, ec, q_num: -1); |
3843 | } |
3844 | |
3845 | static int |
3846 | ice_get_per_q_coalesce(struct net_device *netdev, u32 q_num, |
3847 | struct ethtool_coalesce *ec) |
3848 | { |
3849 | return __ice_get_coalesce(netdev, ec, q_num); |
3850 | } |
3851 | |
3852 | /** |
3853 | * ice_set_rc_coalesce - set ITR values for specific ring container |
3854 | * @ec: ethtool structure from user to update ITR settings |
3855 | * @rc: ring container that the ITR values will come from |
3856 | * @vsi: VSI associated to the ring container |
3857 | * |
3858 | * Set specific ITR values. This is done per ice_ring_container because each |
3859 | * q_vector can have 1 or more rings and all of said ring(s) will have the same |
3860 | * ITR values. |
3861 | * |
3862 | * Returns 0 on success, negative otherwise. |
3863 | */ |
3864 | static int |
3865 | ice_set_rc_coalesce(struct ethtool_coalesce *ec, |
3866 | struct ice_ring_container *rc, struct ice_vsi *vsi) |
3867 | { |
3868 | const char *c_type_str = (rc->type == ICE_RX_CONTAINER) ? "rx" : "tx" ; |
3869 | u32 use_adaptive_coalesce, coalesce_usecs; |
3870 | struct ice_pf *pf = vsi->back; |
3871 | u16 itr_setting; |
3872 | |
3873 | if (!rc->rx_ring) |
3874 | return -EINVAL; |
3875 | |
3876 | switch (rc->type) { |
3877 | case ICE_RX_CONTAINER: |
3878 | { |
3879 | struct ice_q_vector *q_vector = rc->rx_ring->q_vector; |
3880 | |
3881 | if (ec->rx_coalesce_usecs_high > ICE_MAX_INTRL || |
3882 | (ec->rx_coalesce_usecs_high && |
3883 | ec->rx_coalesce_usecs_high < pf->hw.intrl_gran)) { |
3884 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs-high valid values are 0 (disabled), %d-%d\n" , |
3885 | c_type_str, pf->hw.intrl_gran, |
3886 | ICE_MAX_INTRL); |
3887 | return -EINVAL; |
3888 | } |
3889 | if (ec->rx_coalesce_usecs_high != q_vector->intrl && |
3890 | (ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce)) { |
3891 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs-high cannot be changed if adaptive-tx or adaptive-rx is enabled\n" , |
3892 | c_type_str); |
3893 | return -EINVAL; |
3894 | } |
3895 | if (ec->rx_coalesce_usecs_high != q_vector->intrl) |
3896 | q_vector->intrl = ec->rx_coalesce_usecs_high; |
3897 | |
3898 | use_adaptive_coalesce = ec->use_adaptive_rx_coalesce; |
3899 | coalesce_usecs = ec->rx_coalesce_usecs; |
3900 | |
3901 | break; |
3902 | } |
3903 | case ICE_TX_CONTAINER: |
3904 | use_adaptive_coalesce = ec->use_adaptive_tx_coalesce; |
3905 | coalesce_usecs = ec->tx_coalesce_usecs; |
3906 | |
3907 | break; |
3908 | default: |
3909 | dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n" , |
3910 | rc->type); |
3911 | return -EINVAL; |
3912 | } |
3913 | |
3914 | itr_setting = rc->itr_setting; |
3915 | if (coalesce_usecs != itr_setting && use_adaptive_coalesce) { |
3916 | netdev_info(dev: vsi->netdev, format: "%s interrupt throttling cannot be changed if adaptive-%s is enabled\n" , |
3917 | c_type_str, c_type_str); |
3918 | return -EINVAL; |
3919 | } |
3920 | |
3921 | if (coalesce_usecs > ICE_ITR_MAX) { |
3922 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs range is 0-%d\n" , |
3923 | c_type_str, ICE_ITR_MAX); |
3924 | return -EINVAL; |
3925 | } |
3926 | |
3927 | if (use_adaptive_coalesce) { |
3928 | rc->itr_mode = ITR_DYNAMIC; |
3929 | } else { |
3930 | rc->itr_mode = ITR_STATIC; |
3931 | /* store user facing value how it was set */ |
3932 | rc->itr_setting = coalesce_usecs; |
3933 | /* write the change to the register */ |
3934 | ice_write_itr(rc, itr: coalesce_usecs); |
3935 | /* force writes to take effect immediately, the flush shouldn't |
3936 | * be done in the functions above because the intent is for |
3937 | * them to do lazy writes. |
3938 | */ |
3939 | ice_flush(&pf->hw); |
3940 | } |
3941 | |
3942 | return 0; |
3943 | } |
3944 | |
3945 | /** |
3946 | * ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings |
3947 | * @vsi: VSI associated to the queue that need updating |
3948 | * @ec: coalesce settings to program the device with |
3949 | * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index |
3950 | * |
3951 | * Return 0 on success, and negative under the following conditions: |
3952 | * 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed. |
3953 | * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. |
3954 | */ |
3955 | static int |
3956 | ice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) |
3957 | { |
3958 | if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { |
3959 | if (ice_set_rc_coalesce(ec, |
3960 | rc: &vsi->rx_rings[q_num]->q_vector->rx, |
3961 | vsi)) |
3962 | return -EINVAL; |
3963 | |
3964 | if (ice_set_rc_coalesce(ec, |
3965 | rc: &vsi->tx_rings[q_num]->q_vector->tx, |
3966 | vsi)) |
3967 | return -EINVAL; |
3968 | } else if (q_num < vsi->num_rxq) { |
3969 | if (ice_set_rc_coalesce(ec, |
3970 | rc: &vsi->rx_rings[q_num]->q_vector->rx, |
3971 | vsi)) |
3972 | return -EINVAL; |
3973 | } else if (q_num < vsi->num_txq) { |
3974 | if (ice_set_rc_coalesce(ec, |
3975 | rc: &vsi->tx_rings[q_num]->q_vector->tx, |
3976 | vsi)) |
3977 | return -EINVAL; |
3978 | } else { |
3979 | return -EINVAL; |
3980 | } |
3981 | |
3982 | return 0; |
3983 | } |
3984 | |
3985 | /** |
3986 | * ice_print_if_odd_usecs - print message if user tries to set odd [tx|rx]-usecs |
3987 | * @netdev: netdev used for print |
3988 | * @itr_setting: previous user setting |
3989 | * @use_adaptive_coalesce: if adaptive coalesce is enabled or being enabled |
3990 | * @coalesce_usecs: requested value of [tx|rx]-usecs |
3991 | * @c_type_str: either "rx" or "tx" to match user set field of [tx|rx]-usecs |
3992 | */ |
3993 | static void |
3994 | ice_print_if_odd_usecs(struct net_device *netdev, u16 itr_setting, |
3995 | u32 use_adaptive_coalesce, u32 coalesce_usecs, |
3996 | const char *c_type_str) |
3997 | { |
3998 | if (use_adaptive_coalesce) |
3999 | return; |
4000 | |
4001 | if (itr_setting != coalesce_usecs && (coalesce_usecs % 2)) |
4002 | netdev_info(dev: netdev, format: "User set %s-usecs to %d, device only supports even values. Rounding down and attempting to set %s-usecs to %d\n" , |
4003 | c_type_str, coalesce_usecs, c_type_str, |
4004 | ITR_REG_ALIGN(coalesce_usecs)); |
4005 | } |
4006 | |
4007 | /** |
4008 | * __ice_set_coalesce - set ITR/INTRL values for the device |
4009 | * @netdev: pointer to the netdev associated with this query |
4010 | * @ec: ethtool structure to fill with driver's coalesce settings |
4011 | * @q_num: queue number to get the coalesce settings for |
4012 | * |
4013 | * If the caller passes in a negative q_num then we set the coalesce settings |
4014 | * for all Tx/Rx queues, else use the actual q_num passed in. |
4015 | */ |
4016 | static int |
4017 | __ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, |
4018 | int q_num) |
4019 | { |
4020 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
4021 | struct ice_vsi *vsi = np->vsi; |
4022 | |
4023 | if (q_num < 0) { |
4024 | struct ice_q_vector *q_vector = vsi->q_vectors[0]; |
4025 | int v_idx; |
4026 | |
4027 | if (q_vector) { |
4028 | ice_print_if_odd_usecs(netdev, itr_setting: q_vector->rx.itr_setting, |
4029 | use_adaptive_coalesce: ec->use_adaptive_rx_coalesce, |
4030 | coalesce_usecs: ec->rx_coalesce_usecs, c_type_str: "rx" ); |
4031 | |
4032 | ice_print_if_odd_usecs(netdev, itr_setting: q_vector->tx.itr_setting, |
4033 | use_adaptive_coalesce: ec->use_adaptive_tx_coalesce, |
4034 | coalesce_usecs: ec->tx_coalesce_usecs, c_type_str: "tx" ); |
4035 | } |
4036 | |
4037 | ice_for_each_q_vector(vsi, v_idx) { |
4038 | /* In some cases if DCB is configured the num_[rx|tx]q |
4039 | * can be less than vsi->num_q_vectors. This check |
4040 | * accounts for that so we don't report a false failure |
4041 | */ |
4042 | if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq) |
4043 | goto set_complete; |
4044 | |
4045 | if (ice_set_q_coalesce(vsi, ec, q_num: v_idx)) |
4046 | return -EINVAL; |
4047 | |
4048 | ice_set_q_vector_intrl(q_vector: vsi->q_vectors[v_idx]); |
4049 | } |
4050 | goto set_complete; |
4051 | } |
4052 | |
4053 | if (ice_set_q_coalesce(vsi, ec, q_num)) |
4054 | return -EINVAL; |
4055 | |
4056 | ice_set_q_vector_intrl(q_vector: vsi->q_vectors[q_num]); |
4057 | |
4058 | set_complete: |
4059 | return 0; |
4060 | } |
4061 | |
4062 | static int ice_set_coalesce(struct net_device *netdev, |
4063 | struct ethtool_coalesce *ec, |
4064 | struct kernel_ethtool_coalesce *kernel_coal, |
4065 | struct netlink_ext_ack *extack) |
4066 | { |
4067 | return __ice_set_coalesce(netdev, ec, q_num: -1); |
4068 | } |
4069 | |
4070 | static int |
4071 | ice_set_per_q_coalesce(struct net_device *netdev, u32 q_num, |
4072 | struct ethtool_coalesce *ec) |
4073 | { |
4074 | return __ice_set_coalesce(netdev, ec, q_num); |
4075 | } |
4076 | |
4077 | static void |
4078 | ice_repr_get_drvinfo(struct net_device *netdev, |
4079 | struct ethtool_drvinfo *drvinfo) |
4080 | { |
4081 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4082 | |
4083 | if (ice_check_vf_ready_for_cfg(vf: repr->vf)) |
4084 | return; |
4085 | |
4086 | __ice_get_drvinfo(netdev, drvinfo, vsi: repr->src_vsi); |
4087 | } |
4088 | |
4089 | static void |
4090 | ice_repr_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
4091 | { |
4092 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4093 | |
4094 | /* for port representors only ETH_SS_STATS is supported */ |
4095 | if (ice_check_vf_ready_for_cfg(vf: repr->vf) || |
4096 | stringset != ETH_SS_STATS) |
4097 | return; |
4098 | |
4099 | __ice_get_strings(netdev, stringset, data, vsi: repr->src_vsi); |
4100 | } |
4101 | |
4102 | static void |
4103 | ice_repr_get_ethtool_stats(struct net_device *netdev, |
4104 | struct ethtool_stats __always_unused *stats, |
4105 | u64 *data) |
4106 | { |
4107 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4108 | |
4109 | if (ice_check_vf_ready_for_cfg(vf: repr->vf)) |
4110 | return; |
4111 | |
4112 | __ice_get_ethtool_stats(netdev, stats, data, vsi: repr->src_vsi); |
4113 | } |
4114 | |
4115 | static int ice_repr_get_sset_count(struct net_device *netdev, int sset) |
4116 | { |
4117 | switch (sset) { |
4118 | case ETH_SS_STATS: |
4119 | return ICE_VSI_STATS_LEN; |
4120 | default: |
4121 | return -EOPNOTSUPP; |
4122 | } |
4123 | } |
4124 | |
4125 | #define ICE_I2C_EEPROM_DEV_ADDR 0xA0 |
4126 | #define ICE_I2C_EEPROM_DEV_ADDR2 0xA2 |
4127 | #define ICE_MODULE_TYPE_SFP 0x03 |
4128 | #define ICE_MODULE_TYPE_QSFP_PLUS 0x0D |
4129 | #define ICE_MODULE_TYPE_QSFP28 0x11 |
4130 | #define ICE_MODULE_SFF_ADDR_MODE 0x04 |
4131 | #define ICE_MODULE_SFF_DIAG_CAPAB 0x40 |
4132 | #define ICE_MODULE_REVISION_ADDR 0x01 |
4133 | #define ICE_MODULE_SFF_8472_COMP 0x5E |
4134 | #define ICE_MODULE_SFF_8472_SWAP 0x5C |
4135 | #define ICE_MODULE_QSFP_MAX_LEN 640 |
4136 | |
4137 | /** |
4138 | * ice_get_module_info - get SFF module type and revision information |
4139 | * @netdev: network interface device structure |
4140 | * @modinfo: module EEPROM size and layout information structure |
4141 | */ |
4142 | static int |
4143 | ice_get_module_info(struct net_device *netdev, |
4144 | struct ethtool_modinfo *modinfo) |
4145 | { |
4146 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
4147 | struct ice_vsi *vsi = np->vsi; |
4148 | struct ice_pf *pf = vsi->back; |
4149 | struct ice_hw *hw = &pf->hw; |
4150 | u8 sff8472_comp = 0; |
4151 | u8 sff8472_swap = 0; |
4152 | u8 sff8636_rev = 0; |
4153 | u8 value = 0; |
4154 | int status; |
4155 | |
4156 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, mem_addr: 0x00, page: 0x00, |
4157 | set_page: 0, data: &value, length: 1, write: 0, NULL); |
4158 | if (status) |
4159 | return status; |
4160 | |
4161 | switch (value) { |
4162 | case ICE_MODULE_TYPE_SFP: |
4163 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4164 | ICE_MODULE_SFF_8472_COMP, page: 0x00, set_page: 0, |
4165 | data: &sff8472_comp, length: 1, write: 0, NULL); |
4166 | if (status) |
4167 | return status; |
4168 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4169 | ICE_MODULE_SFF_8472_SWAP, page: 0x00, set_page: 0, |
4170 | data: &sff8472_swap, length: 1, write: 0, NULL); |
4171 | if (status) |
4172 | return status; |
4173 | |
4174 | if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) { |
4175 | modinfo->type = ETH_MODULE_SFF_8079; |
4176 | modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; |
4177 | } else if (sff8472_comp && |
4178 | (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) { |
4179 | modinfo->type = ETH_MODULE_SFF_8472; |
4180 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; |
4181 | } else { |
4182 | modinfo->type = ETH_MODULE_SFF_8079; |
4183 | modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; |
4184 | } |
4185 | break; |
4186 | case ICE_MODULE_TYPE_QSFP_PLUS: |
4187 | case ICE_MODULE_TYPE_QSFP28: |
4188 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4189 | ICE_MODULE_REVISION_ADDR, page: 0x00, set_page: 0, |
4190 | data: &sff8636_rev, length: 1, write: 0, NULL); |
4191 | if (status) |
4192 | return status; |
4193 | /* Check revision compliance */ |
4194 | if (sff8636_rev > 0x02) { |
4195 | /* Module is SFF-8636 compliant */ |
4196 | modinfo->type = ETH_MODULE_SFF_8636; |
4197 | modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; |
4198 | } else { |
4199 | modinfo->type = ETH_MODULE_SFF_8436; |
4200 | modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; |
4201 | } |
4202 | break; |
4203 | default: |
4204 | netdev_warn(dev: netdev, format: "SFF Module Type not recognized.\n" ); |
4205 | return -EINVAL; |
4206 | } |
4207 | return 0; |
4208 | } |
4209 | |
4210 | /** |
4211 | * ice_get_module_eeprom - fill buffer with SFF EEPROM contents |
4212 | * @netdev: network interface device structure |
4213 | * @ee: EEPROM dump request structure |
4214 | * @data: buffer to be filled with EEPROM contents |
4215 | */ |
4216 | static int |
4217 | ice_get_module_eeprom(struct net_device *netdev, |
4218 | struct ethtool_eeprom *ee, u8 *data) |
4219 | { |
4220 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
4221 | #define SFF_READ_BLOCK_SIZE 8 |
4222 | u8 value[SFF_READ_BLOCK_SIZE] = { 0 }; |
4223 | u8 addr = ICE_I2C_EEPROM_DEV_ADDR; |
4224 | struct ice_vsi *vsi = np->vsi; |
4225 | struct ice_pf *pf = vsi->back; |
4226 | struct ice_hw *hw = &pf->hw; |
4227 | bool is_sfp = false; |
4228 | unsigned int i, j; |
4229 | u16 offset = 0; |
4230 | u8 page = 0; |
4231 | int status; |
4232 | |
4233 | if (!ee || !ee->len || !data) |
4234 | return -EINVAL; |
4235 | |
4236 | status = ice_aq_sff_eeprom(hw, lport: 0, bus_addr: addr, mem_addr: offset, page, set_page: 0, data: value, length: 1, write: 0, |
4237 | NULL); |
4238 | if (status) |
4239 | return status; |
4240 | |
4241 | if (value[0] == ICE_MODULE_TYPE_SFP) |
4242 | is_sfp = true; |
4243 | |
4244 | memset(data, 0, ee->len); |
4245 | for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) { |
4246 | offset = i + ee->offset; |
4247 | page = 0; |
4248 | |
4249 | /* Check if we need to access the other memory page */ |
4250 | if (is_sfp) { |
4251 | if (offset >= ETH_MODULE_SFF_8079_LEN) { |
4252 | offset -= ETH_MODULE_SFF_8079_LEN; |
4253 | addr = ICE_I2C_EEPROM_DEV_ADDR2; |
4254 | } |
4255 | } else { |
4256 | while (offset >= ETH_MODULE_SFF_8436_LEN) { |
4257 | /* Compute memory page number and offset. */ |
4258 | offset -= ETH_MODULE_SFF_8436_LEN / 2; |
4259 | page++; |
4260 | } |
4261 | } |
4262 | |
4263 | /* Bit 2 of EEPROM address 0x02 declares upper |
4264 | * pages are disabled on QSFP modules. |
4265 | * SFP modules only ever use page 0. |
4266 | */ |
4267 | if (page == 0 || !(data[0x2] & 0x4)) { |
4268 | u32 copy_len; |
4269 | |
4270 | /* If i2c bus is busy due to slow page change or |
4271 | * link management access, call can fail. This is normal. |
4272 | * So we retry this a few times. |
4273 | */ |
4274 | for (j = 0; j < 4; j++) { |
4275 | status = ice_aq_sff_eeprom(hw, lport: 0, bus_addr: addr, mem_addr: offset, page, |
4276 | set_page: !is_sfp, data: value, |
4277 | SFF_READ_BLOCK_SIZE, |
4278 | write: 0, NULL); |
4279 | netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n" , |
4280 | addr, offset, page, is_sfp, |
4281 | value[0], value[1], value[2], value[3], |
4282 | value[4], value[5], value[6], value[7], |
4283 | status); |
4284 | if (status) { |
4285 | usleep_range(min: 1500, max: 2500); |
4286 | memset(value, 0, SFF_READ_BLOCK_SIZE); |
4287 | continue; |
4288 | } |
4289 | break; |
4290 | } |
4291 | |
4292 | /* Make sure we have enough room for the new block */ |
4293 | copy_len = min_t(u32, SFF_READ_BLOCK_SIZE, ee->len - i); |
4294 | memcpy(data + i, value, copy_len); |
4295 | } |
4296 | } |
4297 | return 0; |
4298 | } |
4299 | |
4300 | static const struct ethtool_ops ice_ethtool_ops = { |
4301 | .cap_rss_ctx_supported = true, |
4302 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
4303 | ETHTOOL_COALESCE_USE_ADAPTIVE | |
4304 | ETHTOOL_COALESCE_RX_USECS_HIGH, |
4305 | .cap_rss_sym_xor_supported = true, |
4306 | .get_link_ksettings = ice_get_link_ksettings, |
4307 | .set_link_ksettings = ice_set_link_ksettings, |
4308 | .get_drvinfo = ice_get_drvinfo, |
4309 | .get_regs_len = ice_get_regs_len, |
4310 | .get_regs = ice_get_regs, |
4311 | .get_wol = ice_get_wol, |
4312 | .set_wol = ice_set_wol, |
4313 | .get_msglevel = ice_get_msglevel, |
4314 | .set_msglevel = ice_set_msglevel, |
4315 | .self_test = ice_self_test, |
4316 | .get_link = ethtool_op_get_link, |
4317 | .get_eeprom_len = ice_get_eeprom_len, |
4318 | .get_eeprom = ice_get_eeprom, |
4319 | .get_coalesce = ice_get_coalesce, |
4320 | .set_coalesce = ice_set_coalesce, |
4321 | .get_strings = ice_get_strings, |
4322 | .set_phys_id = ice_set_phys_id, |
4323 | .get_ethtool_stats = ice_get_ethtool_stats, |
4324 | .get_priv_flags = ice_get_priv_flags, |
4325 | .set_priv_flags = ice_set_priv_flags, |
4326 | .get_sset_count = ice_get_sset_count, |
4327 | .get_rxnfc = ice_get_rxnfc, |
4328 | .set_rxnfc = ice_set_rxnfc, |
4329 | .get_ringparam = ice_get_ringparam, |
4330 | .set_ringparam = ice_set_ringparam, |
4331 | .nway_reset = ice_nway_reset, |
4332 | .get_pauseparam = ice_get_pauseparam, |
4333 | .set_pauseparam = ice_set_pauseparam, |
4334 | .get_rxfh_key_size = ice_get_rxfh_key_size, |
4335 | .get_rxfh_indir_size = ice_get_rxfh_indir_size, |
4336 | .get_rxfh = ice_get_rxfh, |
4337 | .set_rxfh = ice_set_rxfh, |
4338 | .get_channels = ice_get_channels, |
4339 | .set_channels = ice_set_channels, |
4340 | .get_ts_info = ice_get_ts_info, |
4341 | .get_per_queue_coalesce = ice_get_per_q_coalesce, |
4342 | .set_per_queue_coalesce = ice_set_per_q_coalesce, |
4343 | .get_fecparam = ice_get_fecparam, |
4344 | .set_fecparam = ice_set_fecparam, |
4345 | .get_module_info = ice_get_module_info, |
4346 | .get_module_eeprom = ice_get_module_eeprom, |
4347 | }; |
4348 | |
4349 | static const struct ethtool_ops ice_ethtool_safe_mode_ops = { |
4350 | .get_link_ksettings = ice_get_link_ksettings, |
4351 | .set_link_ksettings = ice_set_link_ksettings, |
4352 | .get_drvinfo = ice_get_drvinfo, |
4353 | .get_regs_len = ice_get_regs_len, |
4354 | .get_regs = ice_get_regs, |
4355 | .get_wol = ice_get_wol, |
4356 | .set_wol = ice_set_wol, |
4357 | .get_msglevel = ice_get_msglevel, |
4358 | .set_msglevel = ice_set_msglevel, |
4359 | .get_link = ethtool_op_get_link, |
4360 | .get_eeprom_len = ice_get_eeprom_len, |
4361 | .get_eeprom = ice_get_eeprom, |
4362 | .get_strings = ice_get_strings, |
4363 | .get_ethtool_stats = ice_get_ethtool_stats, |
4364 | .get_sset_count = ice_get_sset_count, |
4365 | .get_ringparam = ice_get_ringparam, |
4366 | .set_ringparam = ice_set_ringparam, |
4367 | .nway_reset = ice_nway_reset, |
4368 | .get_channels = ice_get_channels, |
4369 | }; |
4370 | |
4371 | /** |
4372 | * ice_set_ethtool_safe_mode_ops - setup safe mode ethtool ops |
4373 | * @netdev: network interface device structure |
4374 | */ |
4375 | void ice_set_ethtool_safe_mode_ops(struct net_device *netdev) |
4376 | { |
4377 | netdev->ethtool_ops = &ice_ethtool_safe_mode_ops; |
4378 | } |
4379 | |
4380 | static const struct ethtool_ops ice_ethtool_repr_ops = { |
4381 | .get_drvinfo = ice_repr_get_drvinfo, |
4382 | .get_link = ethtool_op_get_link, |
4383 | .get_strings = ice_repr_get_strings, |
4384 | .get_ethtool_stats = ice_repr_get_ethtool_stats, |
4385 | .get_sset_count = ice_repr_get_sset_count, |
4386 | }; |
4387 | |
4388 | /** |
4389 | * ice_set_ethtool_repr_ops - setup VF's port representor ethtool ops |
4390 | * @netdev: network interface device structure |
4391 | */ |
4392 | void ice_set_ethtool_repr_ops(struct net_device *netdev) |
4393 | { |
4394 | netdev->ethtool_ops = &ice_ethtool_repr_ops; |
4395 | } |
4396 | |
4397 | /** |
4398 | * ice_set_ethtool_ops - setup netdev ethtool ops |
4399 | * @netdev: network interface device structure |
4400 | * |
4401 | * setup netdev ethtool ops with ice specific ops |
4402 | */ |
4403 | void ice_set_ethtool_ops(struct net_device *netdev) |
4404 | { |
4405 | netdev->ethtool_ops = &ice_ethtool_ops; |
4406 | } |
4407 | |