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_length_errors.nic" , stats.rx_len_errors), |
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(p: drvinfo->driver, KBUILD_MODNAME, size: 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(p: drvinfo->bus_info, q: pci_name(pdev: pf->pdev), |
452 | size: 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 = devm_kzalloc(ice_pf_to_dev(pf), 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 broadcast[ETH_ALEN], ret = 0; |
945 | int num_frames, valid_frames; |
946 | struct ice_tx_ring *tx_ring; |
947 | struct ice_rx_ring *rx_ring; |
948 | struct device *dev; |
949 | u8 *tx_frame; |
950 | int i; |
951 | |
952 | dev = ice_pf_to_dev(pf); |
953 | netdev_info(dev: netdev, format: "loopback test\n" ); |
954 | |
955 | test_vsi = ice_lb_vsi_setup(pf, pi: pf->hw.port_info); |
956 | if (!test_vsi) { |
957 | netdev_err(dev: netdev, format: "Failed to create a VSI for the loopback test\n" ); |
958 | return 1; |
959 | } |
960 | |
961 | test_vsi->netdev = netdev; |
962 | tx_ring = test_vsi->tx_rings[0]; |
963 | rx_ring = test_vsi->rx_rings[0]; |
964 | |
965 | if (ice_lbtest_prepare_rings(vsi: test_vsi)) { |
966 | ret = 2; |
967 | goto lbtest_vsi_close; |
968 | } |
969 | |
970 | if (ice_alloc_rx_bufs(rxr: rx_ring, cleaned_count: rx_ring->count)) { |
971 | ret = 3; |
972 | goto lbtest_rings_dis; |
973 | } |
974 | |
975 | /* Enable MAC loopback in firmware */ |
976 | if (ice_aq_set_mac_loopback(hw: &pf->hw, ena_lpbk: true, NULL)) { |
977 | ret = 4; |
978 | goto lbtest_mac_dis; |
979 | } |
980 | |
981 | /* Test VSI needs to receive broadcast packets */ |
982 | eth_broadcast_addr(addr: broadcast); |
983 | if (ice_fltr_add_mac(vsi: test_vsi, mac: broadcast, action: ICE_FWD_TO_VSI)) { |
984 | ret = 5; |
985 | goto lbtest_mac_dis; |
986 | } |
987 | |
988 | if (ice_lbtest_create_frame(pf, ret_data: &tx_frame, ICE_LB_FRAME_SIZE)) { |
989 | ret = 7; |
990 | goto remove_mac_filters; |
991 | } |
992 | |
993 | num_frames = min_t(int, tx_ring->count, 32); |
994 | for (i = 0; i < num_frames; i++) { |
995 | if (ice_diag_send(tx_ring, data: tx_frame, ICE_LB_FRAME_SIZE)) { |
996 | ret = 8; |
997 | goto lbtest_free_frame; |
998 | } |
999 | } |
1000 | |
1001 | valid_frames = ice_lbtest_receive_frames(rx_ring); |
1002 | if (!valid_frames) |
1003 | ret = 9; |
1004 | else if (valid_frames != num_frames) |
1005 | ret = 10; |
1006 | |
1007 | lbtest_free_frame: |
1008 | devm_kfree(dev, p: tx_frame); |
1009 | remove_mac_filters: |
1010 | if (ice_fltr_remove_mac(vsi: test_vsi, mac: broadcast, action: ICE_FWD_TO_VSI)) |
1011 | netdev_err(dev: netdev, format: "Could not remove MAC filter for the test VSI\n" ); |
1012 | lbtest_mac_dis: |
1013 | /* Disable MAC loopback after the test is completed. */ |
1014 | if (ice_aq_set_mac_loopback(hw: &pf->hw, ena_lpbk: false, NULL)) |
1015 | netdev_err(dev: netdev, format: "Could not disable MAC loopback\n" ); |
1016 | lbtest_rings_dis: |
1017 | if (ice_lbtest_disable_rings(vsi: test_vsi)) |
1018 | netdev_err(dev: netdev, format: "Could not disable test rings\n" ); |
1019 | lbtest_vsi_close: |
1020 | test_vsi->netdev = NULL; |
1021 | if (ice_vsi_release(vsi: test_vsi)) |
1022 | netdev_err(dev: netdev, format: "Failed to remove the test VSI\n" ); |
1023 | |
1024 | return ret; |
1025 | } |
1026 | |
1027 | /** |
1028 | * ice_intr_test - perform an interrupt test on a given net_device |
1029 | * @netdev: network interface device structure |
1030 | * |
1031 | * This function performs one of the self-tests required by ethtool. |
1032 | * Returns 0 on success, non-zero on failure. |
1033 | */ |
1034 | static u64 ice_intr_test(struct net_device *netdev) |
1035 | { |
1036 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1037 | struct ice_pf *pf = np->vsi->back; |
1038 | u16 swic_old = pf->sw_int_count; |
1039 | |
1040 | netdev_info(dev: netdev, format: "interrupt test\n" ); |
1041 | |
1042 | wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_irq.index), |
1043 | GLINT_DYN_CTL_SW_ITR_INDX_M | |
1044 | GLINT_DYN_CTL_INTENA_MSK_M | |
1045 | GLINT_DYN_CTL_SWINT_TRIG_M); |
1046 | |
1047 | usleep_range(min: 1000, max: 2000); |
1048 | return (swic_old == pf->sw_int_count); |
1049 | } |
1050 | |
1051 | /** |
1052 | * ice_self_test - handler function for performing a self-test by ethtool |
1053 | * @netdev: network interface device structure |
1054 | * @eth_test: ethtool_test structure |
1055 | * @data: required by ethtool.self_test |
1056 | * |
1057 | * This function is called after invoking 'ethtool -t devname' command where |
1058 | * devname is the name of the network device on which ethtool should operate. |
1059 | * It performs a set of self-tests to check if a device works properly. |
1060 | */ |
1061 | static void |
1062 | ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, |
1063 | u64 *data) |
1064 | { |
1065 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1066 | bool if_running = netif_running(dev: netdev); |
1067 | struct ice_pf *pf = np->vsi->back; |
1068 | struct device *dev; |
1069 | |
1070 | dev = ice_pf_to_dev(pf); |
1071 | |
1072 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { |
1073 | netdev_info(dev: netdev, format: "offline testing starting\n" ); |
1074 | |
1075 | set_bit(nr: ICE_TESTING, addr: pf->state); |
1076 | |
1077 | if (ice_active_vfs(pf)) { |
1078 | dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n" ); |
1079 | data[ICE_ETH_TEST_REG] = 1; |
1080 | data[ICE_ETH_TEST_EEPROM] = 1; |
1081 | data[ICE_ETH_TEST_INTR] = 1; |
1082 | data[ICE_ETH_TEST_LOOP] = 1; |
1083 | data[ICE_ETH_TEST_LINK] = 1; |
1084 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1085 | clear_bit(nr: ICE_TESTING, addr: pf->state); |
1086 | goto skip_ol_tests; |
1087 | } |
1088 | /* If the device is online then take it offline */ |
1089 | if (if_running) |
1090 | /* indicate we're in test mode */ |
1091 | ice_stop(netdev); |
1092 | |
1093 | data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); |
1094 | data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev); |
1095 | data[ICE_ETH_TEST_INTR] = ice_intr_test(netdev); |
1096 | data[ICE_ETH_TEST_LOOP] = ice_loopback_test(netdev); |
1097 | data[ICE_ETH_TEST_REG] = ice_reg_test(netdev); |
1098 | |
1099 | if (data[ICE_ETH_TEST_LINK] || |
1100 | data[ICE_ETH_TEST_EEPROM] || |
1101 | data[ICE_ETH_TEST_LOOP] || |
1102 | data[ICE_ETH_TEST_INTR] || |
1103 | data[ICE_ETH_TEST_REG]) |
1104 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1105 | |
1106 | clear_bit(nr: ICE_TESTING, addr: pf->state); |
1107 | |
1108 | if (if_running) { |
1109 | int status = ice_open(netdev); |
1110 | |
1111 | if (status) { |
1112 | dev_err(dev, "Could not open device %s, err %d\n" , |
1113 | pf->int_name, status); |
1114 | } |
1115 | } |
1116 | } else { |
1117 | /* Online tests */ |
1118 | netdev_info(dev: netdev, format: "online testing starting\n" ); |
1119 | |
1120 | data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); |
1121 | if (data[ICE_ETH_TEST_LINK]) |
1122 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1123 | |
1124 | /* Offline only tests, not run in online; pass by default */ |
1125 | data[ICE_ETH_TEST_REG] = 0; |
1126 | data[ICE_ETH_TEST_EEPROM] = 0; |
1127 | data[ICE_ETH_TEST_INTR] = 0; |
1128 | data[ICE_ETH_TEST_LOOP] = 0; |
1129 | } |
1130 | |
1131 | skip_ol_tests: |
1132 | netdev_info(dev: netdev, format: "testing finished\n" ); |
1133 | } |
1134 | |
1135 | static void |
1136 | __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data, |
1137 | struct ice_vsi *vsi) |
1138 | { |
1139 | unsigned int i; |
1140 | u8 *p = data; |
1141 | |
1142 | switch (stringset) { |
1143 | case ETH_SS_STATS: |
1144 | for (i = 0; i < ICE_VSI_STATS_LEN; i++) |
1145 | ethtool_sprintf(data: &p, fmt: "%s" , |
1146 | ice_gstrings_vsi_stats[i].stat_string); |
1147 | |
1148 | if (ice_is_port_repr_netdev(netdev)) |
1149 | return; |
1150 | |
1151 | ice_for_each_alloc_txq(vsi, i) { |
1152 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_packets" , i); |
1153 | ethtool_sprintf(data: &p, fmt: "tx_queue_%u_bytes" , i); |
1154 | } |
1155 | |
1156 | ice_for_each_alloc_rxq(vsi, i) { |
1157 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_packets" , i); |
1158 | ethtool_sprintf(data: &p, fmt: "rx_queue_%u_bytes" , i); |
1159 | } |
1160 | |
1161 | if (vsi->type != ICE_VSI_PF) |
1162 | return; |
1163 | |
1164 | for (i = 0; i < ICE_PF_STATS_LEN; i++) |
1165 | ethtool_sprintf(data: &p, fmt: "%s" , |
1166 | ice_gstrings_pf_stats[i].stat_string); |
1167 | |
1168 | for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { |
1169 | ethtool_sprintf(data: &p, fmt: "tx_priority_%u_xon.nic" , i); |
1170 | ethtool_sprintf(data: &p, fmt: "tx_priority_%u_xoff.nic" , i); |
1171 | } |
1172 | for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { |
1173 | ethtool_sprintf(data: &p, fmt: "rx_priority_%u_xon.nic" , i); |
1174 | ethtool_sprintf(data: &p, fmt: "rx_priority_%u_xoff.nic" , i); |
1175 | } |
1176 | break; |
1177 | case ETH_SS_TEST: |
1178 | memcpy(data, ice_gstrings_test, ICE_TEST_LEN * ETH_GSTRING_LEN); |
1179 | break; |
1180 | case ETH_SS_PRIV_FLAGS: |
1181 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) |
1182 | ethtool_sprintf(data: &p, fmt: "%s" , |
1183 | ice_gstrings_priv_flags[i].name); |
1184 | break; |
1185 | default: |
1186 | break; |
1187 | } |
1188 | } |
1189 | |
1190 | static void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
1191 | { |
1192 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1193 | |
1194 | __ice_get_strings(netdev, stringset, data, vsi: np->vsi); |
1195 | } |
1196 | |
1197 | static int |
1198 | ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) |
1199 | { |
1200 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1201 | bool led_active; |
1202 | |
1203 | switch (state) { |
1204 | case ETHTOOL_ID_ACTIVE: |
1205 | led_active = true; |
1206 | break; |
1207 | case ETHTOOL_ID_INACTIVE: |
1208 | led_active = false; |
1209 | break; |
1210 | default: |
1211 | return -EINVAL; |
1212 | } |
1213 | |
1214 | if (ice_aq_set_port_id_led(pi: np->vsi->port_info, is_orig_mode: !led_active, NULL)) |
1215 | return -EIO; |
1216 | |
1217 | return 0; |
1218 | } |
1219 | |
1220 | /** |
1221 | * ice_set_fec_cfg - Set link FEC options |
1222 | * @netdev: network interface device structure |
1223 | * @req_fec: FEC mode to configure |
1224 | */ |
1225 | static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) |
1226 | { |
1227 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1228 | struct ice_aqc_set_phy_cfg_data config = { 0 }; |
1229 | struct ice_vsi *vsi = np->vsi; |
1230 | struct ice_port_info *pi; |
1231 | |
1232 | pi = vsi->port_info; |
1233 | if (!pi) |
1234 | return -EOPNOTSUPP; |
1235 | |
1236 | /* Changing the FEC parameters is not supported if not the PF VSI */ |
1237 | if (vsi->type != ICE_VSI_PF) { |
1238 | netdev_info(dev: netdev, format: "Changing FEC parameters only supported for PF VSI\n" ); |
1239 | return -EOPNOTSUPP; |
1240 | } |
1241 | |
1242 | /* Proceed only if requesting different FEC mode */ |
1243 | if (pi->phy.curr_user_fec_req == req_fec) |
1244 | return 0; |
1245 | |
1246 | /* Copy the current user PHY configuration. The current user PHY |
1247 | * configuration is initialized during probe from PHY capabilities |
1248 | * software mode, and updated on set PHY configuration. |
1249 | */ |
1250 | memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config)); |
1251 | |
1252 | ice_cfg_phy_fec(pi, cfg: &config, fec: req_fec); |
1253 | config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
1254 | |
1255 | if (ice_aq_set_phy_cfg(hw: pi->hw, pi, cfg: &config, NULL)) |
1256 | return -EAGAIN; |
1257 | |
1258 | /* Save requested FEC config */ |
1259 | pi->phy.curr_user_fec_req = req_fec; |
1260 | |
1261 | return 0; |
1262 | } |
1263 | |
1264 | /** |
1265 | * ice_set_fecparam - Set FEC link options |
1266 | * @netdev: network interface device structure |
1267 | * @fecparam: Ethtool structure to retrieve FEC parameters |
1268 | */ |
1269 | static int |
1270 | ice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) |
1271 | { |
1272 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1273 | struct ice_vsi *vsi = np->vsi; |
1274 | enum ice_fec_mode fec; |
1275 | |
1276 | switch (fecparam->fec) { |
1277 | case ETHTOOL_FEC_AUTO: |
1278 | fec = ICE_FEC_AUTO; |
1279 | break; |
1280 | case ETHTOOL_FEC_RS: |
1281 | fec = ICE_FEC_RS; |
1282 | break; |
1283 | case ETHTOOL_FEC_BASER: |
1284 | fec = ICE_FEC_BASER; |
1285 | break; |
1286 | case ETHTOOL_FEC_OFF: |
1287 | case ETHTOOL_FEC_NONE: |
1288 | fec = ICE_FEC_NONE; |
1289 | break; |
1290 | default: |
1291 | dev_warn(ice_pf_to_dev(vsi->back), "Unsupported FEC mode: %d\n" , |
1292 | fecparam->fec); |
1293 | return -EINVAL; |
1294 | } |
1295 | |
1296 | return ice_set_fec_cfg(netdev, req_fec: fec); |
1297 | } |
1298 | |
1299 | /** |
1300 | * ice_get_fecparam - Get link FEC options |
1301 | * @netdev: network interface device structure |
1302 | * @fecparam: Ethtool structure to retrieve FEC parameters |
1303 | */ |
1304 | static int |
1305 | ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) |
1306 | { |
1307 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1308 | struct ice_aqc_get_phy_caps_data *caps; |
1309 | struct ice_link_status *link_info; |
1310 | struct ice_vsi *vsi = np->vsi; |
1311 | struct ice_port_info *pi; |
1312 | int err; |
1313 | |
1314 | pi = vsi->port_info; |
1315 | |
1316 | if (!pi) |
1317 | return -EOPNOTSUPP; |
1318 | link_info = &pi->phy.link_info; |
1319 | |
1320 | /* Set FEC mode based on negotiated link info */ |
1321 | switch (link_info->fec_info) { |
1322 | case ICE_AQ_LINK_25G_KR_FEC_EN: |
1323 | fecparam->active_fec = ETHTOOL_FEC_BASER; |
1324 | break; |
1325 | case ICE_AQ_LINK_25G_RS_528_FEC_EN: |
1326 | case ICE_AQ_LINK_25G_RS_544_FEC_EN: |
1327 | fecparam->active_fec = ETHTOOL_FEC_RS; |
1328 | break; |
1329 | default: |
1330 | fecparam->active_fec = ETHTOOL_FEC_OFF; |
1331 | break; |
1332 | } |
1333 | |
1334 | caps = kzalloc(size: sizeof(*caps), GFP_KERNEL); |
1335 | if (!caps) |
1336 | return -ENOMEM; |
1337 | |
1338 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, |
1339 | caps, NULL); |
1340 | if (err) |
1341 | goto done; |
1342 | |
1343 | /* Set supported/configured FEC modes based on PHY capability */ |
1344 | if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC) |
1345 | fecparam->fec |= ETHTOOL_FEC_AUTO; |
1346 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || |
1347 | caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || |
1348 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN || |
1349 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) |
1350 | fecparam->fec |= ETHTOOL_FEC_BASER; |
1351 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || |
1352 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ || |
1353 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) |
1354 | fecparam->fec |= ETHTOOL_FEC_RS; |
1355 | if (caps->link_fec_options == 0) |
1356 | fecparam->fec |= ETHTOOL_FEC_OFF; |
1357 | |
1358 | done: |
1359 | kfree(objp: caps); |
1360 | return err; |
1361 | } |
1362 | |
1363 | /** |
1364 | * ice_nway_reset - restart autonegotiation |
1365 | * @netdev: network interface device structure |
1366 | */ |
1367 | static int ice_nway_reset(struct net_device *netdev) |
1368 | { |
1369 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1370 | struct ice_vsi *vsi = np->vsi; |
1371 | int err; |
1372 | |
1373 | /* If VSI state is up, then restart autoneg with link up */ |
1374 | if (!test_bit(ICE_DOWN, vsi->back->state)) |
1375 | err = ice_set_link(vsi, ena: true); |
1376 | else |
1377 | err = ice_set_link(vsi, ena: false); |
1378 | |
1379 | return err; |
1380 | } |
1381 | |
1382 | /** |
1383 | * ice_get_priv_flags - report device private flags |
1384 | * @netdev: network interface device structure |
1385 | * |
1386 | * The get string set count and the string set should be matched for each |
1387 | * flag returned. Add new strings for each flag to the ice_gstrings_priv_flags |
1388 | * array. |
1389 | * |
1390 | * Returns a u32 bitmap of flags. |
1391 | */ |
1392 | static u32 ice_get_priv_flags(struct net_device *netdev) |
1393 | { |
1394 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1395 | struct ice_vsi *vsi = np->vsi; |
1396 | struct ice_pf *pf = vsi->back; |
1397 | u32 i, ret_flags = 0; |
1398 | |
1399 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { |
1400 | const struct ice_priv_flag *priv_flag; |
1401 | |
1402 | priv_flag = &ice_gstrings_priv_flags[i]; |
1403 | |
1404 | if (test_bit(priv_flag->bitno, pf->flags)) |
1405 | ret_flags |= BIT(i); |
1406 | } |
1407 | |
1408 | return ret_flags; |
1409 | } |
1410 | |
1411 | /** |
1412 | * ice_set_priv_flags - set private flags |
1413 | * @netdev: network interface device structure |
1414 | * @flags: bit flags to be set |
1415 | */ |
1416 | static int ice_set_priv_flags(struct net_device *netdev, u32 flags) |
1417 | { |
1418 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1419 | DECLARE_BITMAP(change_flags, ICE_PF_FLAGS_NBITS); |
1420 | DECLARE_BITMAP(orig_flags, ICE_PF_FLAGS_NBITS); |
1421 | struct ice_vsi *vsi = np->vsi; |
1422 | struct ice_pf *pf = vsi->back; |
1423 | struct device *dev; |
1424 | int ret = 0; |
1425 | u32 i; |
1426 | |
1427 | if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE)) |
1428 | return -EINVAL; |
1429 | |
1430 | dev = ice_pf_to_dev(pf); |
1431 | set_bit(nr: ICE_FLAG_ETHTOOL_CTXT, addr: pf->flags); |
1432 | |
1433 | bitmap_copy(dst: orig_flags, src: pf->flags, nbits: ICE_PF_FLAGS_NBITS); |
1434 | for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { |
1435 | const struct ice_priv_flag *priv_flag; |
1436 | |
1437 | priv_flag = &ice_gstrings_priv_flags[i]; |
1438 | |
1439 | if (flags & BIT(i)) |
1440 | set_bit(nr: priv_flag->bitno, addr: pf->flags); |
1441 | else |
1442 | clear_bit(nr: priv_flag->bitno, addr: pf->flags); |
1443 | } |
1444 | |
1445 | bitmap_xor(dst: change_flags, src1: pf->flags, src2: orig_flags, nbits: ICE_PF_FLAGS_NBITS); |
1446 | |
1447 | /* Do not allow change to link-down-on-close when Total Port Shutdown |
1448 | * is enabled. |
1449 | */ |
1450 | if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, change_flags) && |
1451 | test_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) { |
1452 | dev_err(dev, "Setting link-down-on-close not supported on this port\n" ); |
1453 | set_bit(nr: ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, addr: pf->flags); |
1454 | ret = -EINVAL; |
1455 | goto ethtool_exit; |
1456 | } |
1457 | |
1458 | if (test_bit(ICE_FLAG_FW_LLDP_AGENT, change_flags)) { |
1459 | if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) { |
1460 | int status; |
1461 | |
1462 | /* Disable FW LLDP engine */ |
1463 | status = ice_cfg_lldp_mib_change(hw: &pf->hw, ena_mib: false); |
1464 | |
1465 | /* If unregistering for LLDP events fails, this is |
1466 | * not an error state, as there shouldn't be any |
1467 | * events to respond to. |
1468 | */ |
1469 | if (status) |
1470 | dev_info(dev, "Failed to unreg for LLDP events\n" ); |
1471 | |
1472 | /* The AQ call to stop the FW LLDP agent will generate |
1473 | * an error if the agent is already stopped. |
1474 | */ |
1475 | status = ice_aq_stop_lldp(hw: &pf->hw, shutdown_lldp_agent: true, persist: true, NULL); |
1476 | if (status) |
1477 | dev_warn(dev, "Fail to stop LLDP agent\n" ); |
1478 | /* Use case for having the FW LLDP agent stopped |
1479 | * will likely not need DCB, so failure to init is |
1480 | * not a concern of ethtool |
1481 | */ |
1482 | status = ice_init_pf_dcb(pf, locked: true); |
1483 | if (status) |
1484 | dev_warn(dev, "Fail to init DCB\n" ); |
1485 | |
1486 | pf->dcbx_cap &= ~DCB_CAP_DCBX_LLD_MANAGED; |
1487 | pf->dcbx_cap |= DCB_CAP_DCBX_HOST; |
1488 | } else { |
1489 | bool dcbx_agent_status; |
1490 | int status; |
1491 | |
1492 | if (ice_get_pfc_mode(pf) == ICE_QOS_MODE_DSCP) { |
1493 | clear_bit(nr: ICE_FLAG_FW_LLDP_AGENT, addr: pf->flags); |
1494 | dev_err(dev, "QoS in L3 DSCP mode, FW Agent not allowed to start\n" ); |
1495 | ret = -EOPNOTSUPP; |
1496 | goto ethtool_exit; |
1497 | } |
1498 | |
1499 | /* Remove rule to direct LLDP packets to default VSI. |
1500 | * The FW LLDP engine will now be consuming them. |
1501 | */ |
1502 | ice_cfg_sw_lldp(vsi, tx: false, create: false); |
1503 | |
1504 | /* AQ command to start FW LLDP agent will return an |
1505 | * error if the agent is already started |
1506 | */ |
1507 | status = ice_aq_start_lldp(hw: &pf->hw, persist: true, NULL); |
1508 | if (status) |
1509 | dev_warn(dev, "Fail to start LLDP Agent\n" ); |
1510 | |
1511 | /* AQ command to start FW DCBX agent will fail if |
1512 | * the agent is already started |
1513 | */ |
1514 | status = ice_aq_start_stop_dcbx(hw: &pf->hw, start_dcbx_agent: true, |
1515 | dcbx_agent_status: &dcbx_agent_status, |
1516 | NULL); |
1517 | if (status) |
1518 | dev_dbg(dev, "Failed to start FW DCBX\n" ); |
1519 | |
1520 | dev_info(dev, "FW DCBX agent is %s\n" , |
1521 | dcbx_agent_status ? "ACTIVE" : "DISABLED" ); |
1522 | |
1523 | /* Failure to configure MIB change or init DCB is not |
1524 | * relevant to ethtool. Print notification that |
1525 | * registration/init failed but do not return error |
1526 | * state to ethtool |
1527 | */ |
1528 | status = ice_init_pf_dcb(pf, locked: true); |
1529 | if (status) |
1530 | dev_dbg(dev, "Fail to init DCB\n" ); |
1531 | |
1532 | /* Register for MIB change events */ |
1533 | status = ice_cfg_lldp_mib_change(hw: &pf->hw, ena_mib: true); |
1534 | if (status) |
1535 | dev_dbg(dev, "Fail to enable MIB change events\n" ); |
1536 | |
1537 | pf->dcbx_cap &= ~DCB_CAP_DCBX_HOST; |
1538 | pf->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED; |
1539 | |
1540 | ice_nway_reset(netdev); |
1541 | } |
1542 | } |
1543 | if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { |
1544 | /* down and up VSI so that changes of Rx cfg are reflected. */ |
1545 | ice_down_up(vsi); |
1546 | } |
1547 | /* don't allow modification of this flag when a single VF is in |
1548 | * promiscuous mode because it's not supported |
1549 | */ |
1550 | if (test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, change_flags) && |
1551 | ice_is_any_vf_in_unicast_promisc(pf)) { |
1552 | dev_err(dev, "Changing vf-true-promisc-support flag while VF(s) are in promiscuous mode not supported\n" ); |
1553 | /* toggle bit back to previous state */ |
1554 | change_bit(nr: ICE_FLAG_VF_TRUE_PROMISC_ENA, addr: pf->flags); |
1555 | ret = -EAGAIN; |
1556 | } |
1557 | |
1558 | if (test_bit(ICE_FLAG_VF_VLAN_PRUNING, change_flags) && |
1559 | ice_has_vfs(pf)) { |
1560 | dev_err(dev, "vf-vlan-pruning: VLAN pruning cannot be changed while VFs are active.\n" ); |
1561 | /* toggle bit back to previous state */ |
1562 | change_bit(nr: ICE_FLAG_VF_VLAN_PRUNING, addr: pf->flags); |
1563 | ret = -EOPNOTSUPP; |
1564 | } |
1565 | ethtool_exit: |
1566 | clear_bit(nr: ICE_FLAG_ETHTOOL_CTXT, addr: pf->flags); |
1567 | return ret; |
1568 | } |
1569 | |
1570 | static int ice_get_sset_count(struct net_device *netdev, int sset) |
1571 | { |
1572 | switch (sset) { |
1573 | case ETH_SS_STATS: |
1574 | /* The number (and order) of strings reported *must* remain |
1575 | * constant for a given netdevice. This function must not |
1576 | * report a different number based on run time parameters |
1577 | * (such as the number of queues in use, or the setting of |
1578 | * a private ethtool flag). This is due to the nature of the |
1579 | * ethtool stats API. |
1580 | * |
1581 | * Userspace programs such as ethtool must make 3 separate |
1582 | * ioctl requests, one for size, one for the strings, and |
1583 | * finally one for the stats. Since these cross into |
1584 | * userspace, changes to the number or size could result in |
1585 | * undefined memory access or incorrect string<->value |
1586 | * correlations for statistics. |
1587 | * |
1588 | * Even if it appears to be safe, changes to the size or |
1589 | * order of strings will suffer from race conditions and are |
1590 | * not safe. |
1591 | */ |
1592 | return ICE_ALL_STATS_LEN(netdev); |
1593 | case ETH_SS_TEST: |
1594 | return ICE_TEST_LEN; |
1595 | case ETH_SS_PRIV_FLAGS: |
1596 | return ICE_PRIV_FLAG_ARRAY_SIZE; |
1597 | default: |
1598 | return -EOPNOTSUPP; |
1599 | } |
1600 | } |
1601 | |
1602 | static void |
1603 | __ice_get_ethtool_stats(struct net_device *netdev, |
1604 | struct ethtool_stats __always_unused *stats, u64 *data, |
1605 | struct ice_vsi *vsi) |
1606 | { |
1607 | struct ice_pf *pf = vsi->back; |
1608 | struct ice_tx_ring *tx_ring; |
1609 | struct ice_rx_ring *rx_ring; |
1610 | unsigned int j; |
1611 | int i = 0; |
1612 | char *p; |
1613 | |
1614 | ice_update_pf_stats(pf); |
1615 | ice_update_vsi_stats(vsi); |
1616 | |
1617 | for (j = 0; j < ICE_VSI_STATS_LEN; j++) { |
1618 | p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset; |
1619 | data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat == |
1620 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1621 | } |
1622 | |
1623 | if (ice_is_port_repr_netdev(netdev)) |
1624 | return; |
1625 | |
1626 | /* populate per queue stats */ |
1627 | rcu_read_lock(); |
1628 | |
1629 | ice_for_each_alloc_txq(vsi, j) { |
1630 | tx_ring = READ_ONCE(vsi->tx_rings[j]); |
1631 | if (tx_ring && tx_ring->ring_stats) { |
1632 | data[i++] = tx_ring->ring_stats->stats.pkts; |
1633 | data[i++] = tx_ring->ring_stats->stats.bytes; |
1634 | } else { |
1635 | data[i++] = 0; |
1636 | data[i++] = 0; |
1637 | } |
1638 | } |
1639 | |
1640 | ice_for_each_alloc_rxq(vsi, j) { |
1641 | rx_ring = READ_ONCE(vsi->rx_rings[j]); |
1642 | if (rx_ring && rx_ring->ring_stats) { |
1643 | data[i++] = rx_ring->ring_stats->stats.pkts; |
1644 | data[i++] = rx_ring->ring_stats->stats.bytes; |
1645 | } else { |
1646 | data[i++] = 0; |
1647 | data[i++] = 0; |
1648 | } |
1649 | } |
1650 | |
1651 | rcu_read_unlock(); |
1652 | |
1653 | if (vsi->type != ICE_VSI_PF) |
1654 | return; |
1655 | |
1656 | for (j = 0; j < ICE_PF_STATS_LEN; j++) { |
1657 | p = (char *)pf + ice_gstrings_pf_stats[j].stat_offset; |
1658 | data[i++] = (ice_gstrings_pf_stats[j].sizeof_stat == |
1659 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1660 | } |
1661 | |
1662 | for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { |
1663 | data[i++] = pf->stats.priority_xon_tx[j]; |
1664 | data[i++] = pf->stats.priority_xoff_tx[j]; |
1665 | } |
1666 | |
1667 | for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) { |
1668 | data[i++] = pf->stats.priority_xon_rx[j]; |
1669 | data[i++] = pf->stats.priority_xoff_rx[j]; |
1670 | } |
1671 | } |
1672 | |
1673 | static void |
1674 | ice_get_ethtool_stats(struct net_device *netdev, |
1675 | struct ethtool_stats __always_unused *stats, u64 *data) |
1676 | { |
1677 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1678 | |
1679 | __ice_get_ethtool_stats(netdev, stats, data, vsi: np->vsi); |
1680 | } |
1681 | |
1682 | #define ICE_PHY_TYPE_LOW_MASK_MIN_1G (ICE_PHY_TYPE_LOW_100BASE_TX | \ |
1683 | ICE_PHY_TYPE_LOW_100M_SGMII) |
1684 | |
1685 | #define ICE_PHY_TYPE_LOW_MASK_MIN_25G (ICE_PHY_TYPE_LOW_MASK_MIN_1G | \ |
1686 | ICE_PHY_TYPE_LOW_1000BASE_T | \ |
1687 | ICE_PHY_TYPE_LOW_1000BASE_SX | \ |
1688 | ICE_PHY_TYPE_LOW_1000BASE_LX | \ |
1689 | ICE_PHY_TYPE_LOW_1000BASE_KX | \ |
1690 | ICE_PHY_TYPE_LOW_1G_SGMII | \ |
1691 | ICE_PHY_TYPE_LOW_2500BASE_T | \ |
1692 | ICE_PHY_TYPE_LOW_2500BASE_X | \ |
1693 | ICE_PHY_TYPE_LOW_2500BASE_KX | \ |
1694 | ICE_PHY_TYPE_LOW_5GBASE_T | \ |
1695 | ICE_PHY_TYPE_LOW_5GBASE_KR | \ |
1696 | ICE_PHY_TYPE_LOW_10GBASE_T | \ |
1697 | ICE_PHY_TYPE_LOW_10G_SFI_DA | \ |
1698 | ICE_PHY_TYPE_LOW_10GBASE_SR | \ |
1699 | ICE_PHY_TYPE_LOW_10GBASE_LR | \ |
1700 | ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 | \ |
1701 | ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | \ |
1702 | ICE_PHY_TYPE_LOW_10G_SFI_C2C) |
1703 | |
1704 | #define ICE_PHY_TYPE_LOW_MASK_100G (ICE_PHY_TYPE_LOW_100GBASE_CR4 | \ |
1705 | ICE_PHY_TYPE_LOW_100GBASE_SR4 | \ |
1706 | ICE_PHY_TYPE_LOW_100GBASE_LR4 | \ |
1707 | ICE_PHY_TYPE_LOW_100GBASE_KR4 | \ |
1708 | ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | \ |
1709 | ICE_PHY_TYPE_LOW_100G_CAUI4 | \ |
1710 | ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | \ |
1711 | ICE_PHY_TYPE_LOW_100G_AUI4 | \ |
1712 | ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 | \ |
1713 | ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 | \ |
1714 | ICE_PHY_TYPE_LOW_100GBASE_CP2 | \ |
1715 | ICE_PHY_TYPE_LOW_100GBASE_SR2 | \ |
1716 | ICE_PHY_TYPE_LOW_100GBASE_DR) |
1717 | |
1718 | #define ICE_PHY_TYPE_HIGH_MASK_100G (ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \ |
1719 | ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC |\ |
1720 | ICE_PHY_TYPE_HIGH_100G_CAUI2 | \ |
1721 | ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \ |
1722 | ICE_PHY_TYPE_HIGH_100G_AUI2) |
1723 | |
1724 | #define ICE_PHY_TYPE_HIGH_MASK_200G (ICE_PHY_TYPE_HIGH_200G_CR4_PAM4 | \ |
1725 | ICE_PHY_TYPE_HIGH_200G_SR4 | \ |
1726 | ICE_PHY_TYPE_HIGH_200G_FR4 | \ |
1727 | ICE_PHY_TYPE_HIGH_200G_LR4 | \ |
1728 | ICE_PHY_TYPE_HIGH_200G_DR4 | \ |
1729 | ICE_PHY_TYPE_HIGH_200G_KR4_PAM4 | \ |
1730 | ICE_PHY_TYPE_HIGH_200G_AUI4_AOC_ACC | \ |
1731 | ICE_PHY_TYPE_HIGH_200G_AUI4) |
1732 | |
1733 | /** |
1734 | * ice_mask_min_supported_speeds |
1735 | * @hw: pointer to the HW structure |
1736 | * @phy_types_high: PHY type high |
1737 | * @phy_types_low: PHY type low to apply minimum supported speeds mask |
1738 | * |
1739 | * Apply minimum supported speeds mask to PHY type low. These are the speeds |
1740 | * for ethtool supported link mode. |
1741 | */ |
1742 | static void |
1743 | ice_mask_min_supported_speeds(struct ice_hw *hw, |
1744 | u64 phy_types_high, u64 *phy_types_low) |
1745 | { |
1746 | /* if QSFP connection with 100G speed, minimum supported speed is 25G */ |
1747 | if ((*phy_types_low & ICE_PHY_TYPE_LOW_MASK_100G) || |
1748 | (phy_types_high & ICE_PHY_TYPE_HIGH_MASK_100G) || |
1749 | (phy_types_high & ICE_PHY_TYPE_HIGH_MASK_200G)) |
1750 | *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_25G; |
1751 | else if (!ice_is_100m_speed_supported(hw)) |
1752 | *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_1G; |
1753 | } |
1754 | |
1755 | /** |
1756 | * ice_linkmode_set_bit - set link mode bit |
1757 | * @phy_to_ethtool: PHY type to ethtool link mode struct to set |
1758 | * @ks: ethtool link ksettings struct to fill out |
1759 | * @req_speeds: speed requested by user |
1760 | * @advert_phy_type: advertised PHY type |
1761 | * @phy_type: PHY type |
1762 | */ |
1763 | static void |
1764 | ice_linkmode_set_bit(const struct ice_phy_type_to_ethtool *phy_to_ethtool, |
1765 | struct ethtool_link_ksettings *ks, u32 req_speeds, |
1766 | u64 advert_phy_type, u32 phy_type) |
1767 | { |
1768 | linkmode_set_bit(nr: phy_to_ethtool->link_mode, addr: ks->link_modes.supported); |
1769 | |
1770 | if (req_speeds & phy_to_ethtool->aq_link_speed || |
1771 | (!req_speeds && advert_phy_type & BIT(phy_type))) |
1772 | linkmode_set_bit(nr: phy_to_ethtool->link_mode, |
1773 | addr: ks->link_modes.advertising); |
1774 | } |
1775 | |
1776 | /** |
1777 | * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes |
1778 | * @netdev: network interface device structure |
1779 | * @ks: ethtool link ksettings struct to fill out |
1780 | */ |
1781 | static void |
1782 | ice_phy_type_to_ethtool(struct net_device *netdev, |
1783 | struct ethtool_link_ksettings *ks) |
1784 | { |
1785 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1786 | struct ice_vsi *vsi = np->vsi; |
1787 | struct ice_pf *pf = vsi->back; |
1788 | u64 advert_phy_type_lo = 0; |
1789 | u64 advert_phy_type_hi = 0; |
1790 | u64 phy_types_high = 0; |
1791 | u64 phy_types_low = 0; |
1792 | u32 req_speeds; |
1793 | u32 i; |
1794 | |
1795 | req_speeds = vsi->port_info->phy.link_info.req_speeds; |
1796 | |
1797 | /* Check if lenient mode is supported and enabled, or in strict mode. |
1798 | * |
1799 | * In lenient mode the Supported link modes are the PHY types without |
1800 | * media. The Advertising link mode is either 1. the user requested |
1801 | * speed, 2. the override PHY mask, or 3. the PHY types with media. |
1802 | * |
1803 | * In strict mode Supported link mode are the PHY type with media, |
1804 | * and Advertising link modes are the media PHY type or the speed |
1805 | * requested by user. |
1806 | */ |
1807 | if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { |
1808 | phy_types_low = le64_to_cpu(pf->nvm_phy_type_lo); |
1809 | phy_types_high = le64_to_cpu(pf->nvm_phy_type_hi); |
1810 | |
1811 | ice_mask_min_supported_speeds(hw: &pf->hw, phy_types_high, |
1812 | phy_types_low: &phy_types_low); |
1813 | /* determine advertised modes based on link override only |
1814 | * if it's supported and if the FW doesn't abstract the |
1815 | * driver from having to account for link overrides |
1816 | */ |
1817 | if (ice_fw_supports_link_override(hw: &pf->hw) && |
1818 | !ice_fw_supports_report_dflt_cfg(hw: &pf->hw)) { |
1819 | struct ice_link_default_override_tlv *ldo; |
1820 | |
1821 | ldo = &pf->link_dflt_override; |
1822 | /* If override enabled and PHY mask set, then |
1823 | * Advertising link mode is the intersection of the PHY |
1824 | * types without media and the override PHY mask. |
1825 | */ |
1826 | if (ldo->options & ICE_LINK_OVERRIDE_EN && |
1827 | (ldo->phy_type_low || ldo->phy_type_high)) { |
1828 | advert_phy_type_lo = |
1829 | le64_to_cpu(pf->nvm_phy_type_lo) & |
1830 | ldo->phy_type_low; |
1831 | advert_phy_type_hi = |
1832 | le64_to_cpu(pf->nvm_phy_type_hi) & |
1833 | ldo->phy_type_high; |
1834 | } |
1835 | } |
1836 | } else { |
1837 | /* strict mode */ |
1838 | phy_types_low = vsi->port_info->phy.phy_type_low; |
1839 | phy_types_high = vsi->port_info->phy.phy_type_high; |
1840 | } |
1841 | |
1842 | /* If Advertising link mode PHY type is not using override PHY type, |
1843 | * then use PHY type with media. |
1844 | */ |
1845 | if (!advert_phy_type_lo && !advert_phy_type_hi) { |
1846 | advert_phy_type_lo = vsi->port_info->phy.phy_type_low; |
1847 | advert_phy_type_hi = vsi->port_info->phy.phy_type_high; |
1848 | } |
1849 | |
1850 | linkmode_zero(dst: ks->link_modes.supported); |
1851 | linkmode_zero(dst: ks->link_modes.advertising); |
1852 | |
1853 | for (i = 0; i < BITS_PER_TYPE(u64); i++) { |
1854 | if (phy_types_low & BIT_ULL(i)) |
1855 | ice_linkmode_set_bit(phy_to_ethtool: &phy_type_low_lkup[i], ks, |
1856 | req_speeds, advert_phy_type: advert_phy_type_lo, |
1857 | phy_type: i); |
1858 | } |
1859 | |
1860 | for (i = 0; i < BITS_PER_TYPE(u64); i++) { |
1861 | if (phy_types_high & BIT_ULL(i)) |
1862 | ice_linkmode_set_bit(phy_to_ethtool: &phy_type_high_lkup[i], ks, |
1863 | req_speeds, advert_phy_type: advert_phy_type_hi, |
1864 | phy_type: i); |
1865 | } |
1866 | } |
1867 | |
1868 | #define TEST_SET_BITS_TIMEOUT 50 |
1869 | #define TEST_SET_BITS_SLEEP_MAX 2000 |
1870 | #define TEST_SET_BITS_SLEEP_MIN 1000 |
1871 | |
1872 | /** |
1873 | * ice_get_settings_link_up - Get Link settings for when link is up |
1874 | * @ks: ethtool ksettings to fill in |
1875 | * @netdev: network interface device structure |
1876 | */ |
1877 | static void |
1878 | ice_get_settings_link_up(struct ethtool_link_ksettings *ks, |
1879 | struct net_device *netdev) |
1880 | { |
1881 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1882 | struct ice_port_info *pi = np->vsi->port_info; |
1883 | struct ice_link_status *link_info; |
1884 | struct ice_vsi *vsi = np->vsi; |
1885 | |
1886 | link_info = &vsi->port_info->phy.link_info; |
1887 | |
1888 | /* Get supported and advertised settings from PHY ability with media */ |
1889 | ice_phy_type_to_ethtool(netdev, ks); |
1890 | |
1891 | switch (link_info->link_speed) { |
1892 | case ICE_AQ_LINK_SPEED_200GB: |
1893 | ks->base.speed = SPEED_200000; |
1894 | break; |
1895 | case ICE_AQ_LINK_SPEED_100GB: |
1896 | ks->base.speed = SPEED_100000; |
1897 | break; |
1898 | case ICE_AQ_LINK_SPEED_50GB: |
1899 | ks->base.speed = SPEED_50000; |
1900 | break; |
1901 | case ICE_AQ_LINK_SPEED_40GB: |
1902 | ks->base.speed = SPEED_40000; |
1903 | break; |
1904 | case ICE_AQ_LINK_SPEED_25GB: |
1905 | ks->base.speed = SPEED_25000; |
1906 | break; |
1907 | case ICE_AQ_LINK_SPEED_20GB: |
1908 | ks->base.speed = SPEED_20000; |
1909 | break; |
1910 | case ICE_AQ_LINK_SPEED_10GB: |
1911 | ks->base.speed = SPEED_10000; |
1912 | break; |
1913 | case ICE_AQ_LINK_SPEED_5GB: |
1914 | ks->base.speed = SPEED_5000; |
1915 | break; |
1916 | case ICE_AQ_LINK_SPEED_2500MB: |
1917 | ks->base.speed = SPEED_2500; |
1918 | break; |
1919 | case ICE_AQ_LINK_SPEED_1000MB: |
1920 | ks->base.speed = SPEED_1000; |
1921 | break; |
1922 | case ICE_AQ_LINK_SPEED_100MB: |
1923 | ks->base.speed = SPEED_100; |
1924 | break; |
1925 | default: |
1926 | netdev_info(dev: netdev, format: "WARNING: Unrecognized link_speed (0x%x).\n" , |
1927 | link_info->link_speed); |
1928 | break; |
1929 | } |
1930 | ks->base.duplex = DUPLEX_FULL; |
1931 | |
1932 | if (link_info->an_info & ICE_AQ_AN_COMPLETED) |
1933 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1934 | Autoneg); |
1935 | |
1936 | /* Set flow control negotiated Rx/Tx pause */ |
1937 | switch (pi->fc.current_mode) { |
1938 | case ICE_FC_FULL: |
1939 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); |
1940 | break; |
1941 | case ICE_FC_TX_PAUSE: |
1942 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); |
1943 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1944 | Asym_Pause); |
1945 | break; |
1946 | case ICE_FC_RX_PAUSE: |
1947 | ethtool_link_ksettings_add_link_mode(ks, lp_advertising, |
1948 | Asym_Pause); |
1949 | break; |
1950 | case ICE_FC_PFC: |
1951 | default: |
1952 | ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause); |
1953 | ethtool_link_ksettings_del_link_mode(ks, lp_advertising, |
1954 | Asym_Pause); |
1955 | break; |
1956 | } |
1957 | } |
1958 | |
1959 | /** |
1960 | * ice_get_settings_link_down - Get the Link settings when link is down |
1961 | * @ks: ethtool ksettings to fill in |
1962 | * @netdev: network interface device structure |
1963 | * |
1964 | * Reports link settings that can be determined when link is down |
1965 | */ |
1966 | static void |
1967 | ice_get_settings_link_down(struct ethtool_link_ksettings *ks, |
1968 | struct net_device *netdev) |
1969 | { |
1970 | /* link is down and the driver needs to fall back on |
1971 | * supported PHY types to figure out what info to display |
1972 | */ |
1973 | ice_phy_type_to_ethtool(netdev, ks); |
1974 | |
1975 | /* With no link, speed and duplex are unknown */ |
1976 | ks->base.speed = SPEED_UNKNOWN; |
1977 | ks->base.duplex = DUPLEX_UNKNOWN; |
1978 | } |
1979 | |
1980 | /** |
1981 | * ice_get_link_ksettings - Get Link Speed and Duplex settings |
1982 | * @netdev: network interface device structure |
1983 | * @ks: ethtool ksettings |
1984 | * |
1985 | * Reports speed/duplex settings based on media_type |
1986 | */ |
1987 | static int |
1988 | ice_get_link_ksettings(struct net_device *netdev, |
1989 | struct ethtool_link_ksettings *ks) |
1990 | { |
1991 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
1992 | struct ice_aqc_get_phy_caps_data *caps; |
1993 | struct ice_link_status *hw_link_info; |
1994 | struct ice_vsi *vsi = np->vsi; |
1995 | int err; |
1996 | |
1997 | ethtool_link_ksettings_zero_link_mode(ks, supported); |
1998 | ethtool_link_ksettings_zero_link_mode(ks, advertising); |
1999 | ethtool_link_ksettings_zero_link_mode(ks, lp_advertising); |
2000 | hw_link_info = &vsi->port_info->phy.link_info; |
2001 | |
2002 | /* set speed and duplex */ |
2003 | if (hw_link_info->link_info & ICE_AQ_LINK_UP) |
2004 | ice_get_settings_link_up(ks, netdev); |
2005 | else |
2006 | ice_get_settings_link_down(ks, netdev); |
2007 | |
2008 | /* set autoneg settings */ |
2009 | ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ? |
2010 | AUTONEG_ENABLE : AUTONEG_DISABLE; |
2011 | |
2012 | /* set media type settings */ |
2013 | switch (vsi->port_info->phy.media_type) { |
2014 | case ICE_MEDIA_FIBER: |
2015 | ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); |
2016 | ks->base.port = PORT_FIBRE; |
2017 | break; |
2018 | case ICE_MEDIA_BASET: |
2019 | ethtool_link_ksettings_add_link_mode(ks, supported, TP); |
2020 | ethtool_link_ksettings_add_link_mode(ks, advertising, TP); |
2021 | ks->base.port = PORT_TP; |
2022 | break; |
2023 | case ICE_MEDIA_BACKPLANE: |
2024 | ethtool_link_ksettings_add_link_mode(ks, supported, Backplane); |
2025 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2026 | Backplane); |
2027 | ks->base.port = PORT_NONE; |
2028 | break; |
2029 | case ICE_MEDIA_DA: |
2030 | ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); |
2031 | ethtool_link_ksettings_add_link_mode(ks, advertising, FIBRE); |
2032 | ks->base.port = PORT_DA; |
2033 | break; |
2034 | default: |
2035 | ks->base.port = PORT_OTHER; |
2036 | break; |
2037 | } |
2038 | |
2039 | /* flow control is symmetric and always supported */ |
2040 | ethtool_link_ksettings_add_link_mode(ks, supported, Pause); |
2041 | |
2042 | caps = kzalloc(size: sizeof(*caps), GFP_KERNEL); |
2043 | if (!caps) |
2044 | return -ENOMEM; |
2045 | |
2046 | err = ice_aq_get_phy_caps(pi: vsi->port_info, qual_mods: false, |
2047 | ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL); |
2048 | if (err) |
2049 | goto done; |
2050 | |
2051 | /* Set the advertised flow control based on the PHY capability */ |
2052 | if ((caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) && |
2053 | (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 if (caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) { |
2058 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2059 | Asym_Pause); |
2060 | } else if (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) { |
2061 | ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); |
2062 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2063 | Asym_Pause); |
2064 | } else { |
2065 | ethtool_link_ksettings_del_link_mode(ks, advertising, Pause); |
2066 | ethtool_link_ksettings_del_link_mode(ks, advertising, |
2067 | Asym_Pause); |
2068 | } |
2069 | |
2070 | /* Set advertised FEC modes based on PHY capability */ |
2071 | ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); |
2072 | |
2073 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || |
2074 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) |
2075 | ethtool_link_ksettings_add_link_mode(ks, advertising, |
2076 | FEC_BASER); |
2077 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || |
2078 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) |
2079 | ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); |
2080 | |
2081 | err = ice_aq_get_phy_caps(pi: vsi->port_info, qual_mods: false, |
2082 | ICE_AQC_REPORT_TOPO_CAP_MEDIA, caps, NULL); |
2083 | if (err) |
2084 | goto done; |
2085 | |
2086 | /* Set supported FEC modes based on PHY capability */ |
2087 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE); |
2088 | |
2089 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || |
2090 | caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN) |
2091 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); |
2092 | if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) |
2093 | ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); |
2094 | |
2095 | /* Set supported and advertised autoneg */ |
2096 | if (ice_is_phy_caps_an_enabled(caps)) { |
2097 | ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); |
2098 | ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg); |
2099 | } |
2100 | |
2101 | done: |
2102 | kfree(objp: caps); |
2103 | return err; |
2104 | } |
2105 | |
2106 | /** |
2107 | * ice_speed_to_aq_link - Get AQ link speed by Ethtool forced speed |
2108 | * @speed: ethtool forced speed |
2109 | */ |
2110 | static u16 ice_speed_to_aq_link(int speed) |
2111 | { |
2112 | int aq_speed; |
2113 | |
2114 | switch (speed) { |
2115 | case SPEED_10: |
2116 | aq_speed = ICE_AQ_LINK_SPEED_10MB; |
2117 | break; |
2118 | case SPEED_100: |
2119 | aq_speed = ICE_AQ_LINK_SPEED_100MB; |
2120 | break; |
2121 | case SPEED_1000: |
2122 | aq_speed = ICE_AQ_LINK_SPEED_1000MB; |
2123 | break; |
2124 | case SPEED_2500: |
2125 | aq_speed = ICE_AQ_LINK_SPEED_2500MB; |
2126 | break; |
2127 | case SPEED_5000: |
2128 | aq_speed = ICE_AQ_LINK_SPEED_5GB; |
2129 | break; |
2130 | case SPEED_10000: |
2131 | aq_speed = ICE_AQ_LINK_SPEED_10GB; |
2132 | break; |
2133 | case SPEED_20000: |
2134 | aq_speed = ICE_AQ_LINK_SPEED_20GB; |
2135 | break; |
2136 | case SPEED_25000: |
2137 | aq_speed = ICE_AQ_LINK_SPEED_25GB; |
2138 | break; |
2139 | case SPEED_40000: |
2140 | aq_speed = ICE_AQ_LINK_SPEED_40GB; |
2141 | break; |
2142 | case SPEED_50000: |
2143 | aq_speed = ICE_AQ_LINK_SPEED_50GB; |
2144 | break; |
2145 | case SPEED_100000: |
2146 | aq_speed = ICE_AQ_LINK_SPEED_100GB; |
2147 | break; |
2148 | default: |
2149 | aq_speed = ICE_AQ_LINK_SPEED_UNKNOWN; |
2150 | break; |
2151 | } |
2152 | return aq_speed; |
2153 | } |
2154 | |
2155 | /** |
2156 | * ice_ksettings_find_adv_link_speed - Find advertising link speed |
2157 | * @ks: ethtool ksettings |
2158 | */ |
2159 | static u16 |
2160 | ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks) |
2161 | { |
2162 | const struct ethtool_forced_speed_map *map; |
2163 | u16 adv_link_speed = 0; |
2164 | |
2165 | for (u32 i = 0; i < ARRAY_SIZE(ice_adv_lnk_speed_maps); i++) { |
2166 | map = ice_adv_lnk_speed_maps + i; |
2167 | if (linkmode_intersects(src1: ks->link_modes.advertising, src2: map->caps)) |
2168 | adv_link_speed |= ice_speed_to_aq_link(speed: map->speed); |
2169 | } |
2170 | |
2171 | return adv_link_speed; |
2172 | } |
2173 | |
2174 | /** |
2175 | * ice_setup_autoneg |
2176 | * @p: port info |
2177 | * @ks: ethtool_link_ksettings |
2178 | * @config: configuration that will be sent down to FW |
2179 | * @autoneg_enabled: autonegotiation is enabled or not |
2180 | * @autoneg_changed: will there a change in autonegotiation |
2181 | * @netdev: network interface device structure |
2182 | * |
2183 | * Setup PHY autonegotiation feature |
2184 | */ |
2185 | static int |
2186 | ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks, |
2187 | struct ice_aqc_set_phy_cfg_data *config, |
2188 | u8 autoneg_enabled, u8 *autoneg_changed, |
2189 | struct net_device *netdev) |
2190 | { |
2191 | int err = 0; |
2192 | |
2193 | *autoneg_changed = 0; |
2194 | |
2195 | /* Check autoneg */ |
2196 | if (autoneg_enabled == AUTONEG_ENABLE) { |
2197 | /* If autoneg was not already enabled */ |
2198 | if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) { |
2199 | /* If autoneg is not supported, return error */ |
2200 | if (!ethtool_link_ksettings_test_link_mode(ks, |
2201 | supported, |
2202 | Autoneg)) { |
2203 | netdev_info(dev: netdev, format: "Autoneg not supported on this phy.\n" ); |
2204 | err = -EINVAL; |
2205 | } else { |
2206 | /* Autoneg is allowed to change */ |
2207 | config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2208 | *autoneg_changed = 1; |
2209 | } |
2210 | } |
2211 | } else { |
2212 | /* If autoneg is currently enabled */ |
2213 | if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) { |
2214 | /* If autoneg is supported 10GBASE_T is the only PHY |
2215 | * that can disable it, so otherwise return error |
2216 | */ |
2217 | if (ethtool_link_ksettings_test_link_mode(ks, |
2218 | supported, |
2219 | Autoneg)) { |
2220 | netdev_info(dev: netdev, format: "Autoneg cannot be disabled on this phy\n" ); |
2221 | err = -EINVAL; |
2222 | } else { |
2223 | /* Autoneg is allowed to change */ |
2224 | config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2225 | *autoneg_changed = 1; |
2226 | } |
2227 | } |
2228 | } |
2229 | |
2230 | return err; |
2231 | } |
2232 | |
2233 | /** |
2234 | * ice_set_phy_type_from_speed - set phy_types based on speeds |
2235 | * and advertised modes |
2236 | * @ks: ethtool link ksettings struct |
2237 | * @phy_type_low: pointer to the lower part of phy_type |
2238 | * @phy_type_high: pointer to the higher part of phy_type |
2239 | * @adv_link_speed: targeted link speeds bitmap |
2240 | */ |
2241 | static void |
2242 | ice_set_phy_type_from_speed(const struct ethtool_link_ksettings *ks, |
2243 | u64 *phy_type_low, u64 *phy_type_high, |
2244 | u16 adv_link_speed) |
2245 | { |
2246 | /* Handle 1000M speed in a special way because ice_update_phy_type |
2247 | * enables all link modes, but having mixed copper and optical |
2248 | * standards is not supported. |
2249 | */ |
2250 | adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB; |
2251 | |
2252 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2253 | 1000baseT_Full)) |
2254 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T | |
2255 | ICE_PHY_TYPE_LOW_1G_SGMII; |
2256 | |
2257 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2258 | 1000baseKX_Full)) |
2259 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX; |
2260 | |
2261 | if (ethtool_link_ksettings_test_link_mode(ks, advertising, |
2262 | 1000baseX_Full)) |
2263 | *phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX | |
2264 | ICE_PHY_TYPE_LOW_1000BASE_LX; |
2265 | |
2266 | ice_update_phy_type(phy_type_low, phy_type_high, link_speeds_bitmap: adv_link_speed); |
2267 | } |
2268 | |
2269 | /** |
2270 | * ice_set_link_ksettings - Set Speed and Duplex |
2271 | * @netdev: network interface device structure |
2272 | * @ks: ethtool ksettings |
2273 | * |
2274 | * Set speed/duplex per media_types advertised/forced |
2275 | */ |
2276 | static int |
2277 | ice_set_link_ksettings(struct net_device *netdev, |
2278 | const struct ethtool_link_ksettings *ks) |
2279 | { |
2280 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2281 | u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT; |
2282 | struct ethtool_link_ksettings copy_ks = *ks; |
2283 | struct ethtool_link_ksettings safe_ks = {}; |
2284 | struct ice_aqc_get_phy_caps_data *phy_caps; |
2285 | struct ice_aqc_set_phy_cfg_data config; |
2286 | u16 adv_link_speed, curr_link_speed; |
2287 | struct ice_pf *pf = np->vsi->back; |
2288 | struct ice_port_info *pi; |
2289 | u8 autoneg_changed = 0; |
2290 | u64 phy_type_high = 0; |
2291 | u64 phy_type_low = 0; |
2292 | bool linkup; |
2293 | int err; |
2294 | |
2295 | pi = np->vsi->port_info; |
2296 | |
2297 | if (!pi) |
2298 | return -EIO; |
2299 | |
2300 | if (pi->phy.media_type != ICE_MEDIA_BASET && |
2301 | pi->phy.media_type != ICE_MEDIA_FIBER && |
2302 | pi->phy.media_type != ICE_MEDIA_BACKPLANE && |
2303 | pi->phy.media_type != ICE_MEDIA_DA && |
2304 | pi->phy.link_info.link_info & ICE_AQ_LINK_UP) |
2305 | return -EOPNOTSUPP; |
2306 | |
2307 | phy_caps = kzalloc(size: sizeof(*phy_caps), GFP_KERNEL); |
2308 | if (!phy_caps) |
2309 | return -ENOMEM; |
2310 | |
2311 | /* Get the PHY capabilities based on media */ |
2312 | if (ice_fw_supports_report_dflt_cfg(hw: pi->hw)) |
2313 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_DFLT_CFG, |
2314 | caps: phy_caps, NULL); |
2315 | else |
2316 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, |
2317 | caps: phy_caps, NULL); |
2318 | if (err) |
2319 | goto done; |
2320 | |
2321 | /* save autoneg out of ksettings */ |
2322 | autoneg = copy_ks.base.autoneg; |
2323 | |
2324 | /* Get link modes supported by hardware.*/ |
2325 | ice_phy_type_to_ethtool(netdev, ks: &safe_ks); |
2326 | |
2327 | /* and check against modes requested by user. |
2328 | * Return an error if unsupported mode was set. |
2329 | */ |
2330 | if (!bitmap_subset(src1: copy_ks.link_modes.advertising, |
2331 | src2: safe_ks.link_modes.supported, |
2332 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS)) { |
2333 | if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) |
2334 | 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" ); |
2335 | err = -EOPNOTSUPP; |
2336 | goto done; |
2337 | } |
2338 | |
2339 | /* get our own copy of the bits to check against */ |
2340 | memset(&safe_ks, 0, sizeof(safe_ks)); |
2341 | safe_ks.base.cmd = copy_ks.base.cmd; |
2342 | safe_ks.base.link_mode_masks_nwords = |
2343 | copy_ks.base.link_mode_masks_nwords; |
2344 | ice_get_link_ksettings(netdev, ks: &safe_ks); |
2345 | |
2346 | /* set autoneg back to what it currently is */ |
2347 | copy_ks.base.autoneg = safe_ks.base.autoneg; |
2348 | /* we don't compare the speed */ |
2349 | copy_ks.base.speed = safe_ks.base.speed; |
2350 | |
2351 | /* If copy_ks.base and safe_ks.base are not the same now, then they are |
2352 | * trying to set something that we do not support. |
2353 | */ |
2354 | if (memcmp(p: ©_ks.base, q: &safe_ks.base, size: sizeof(copy_ks.base))) { |
2355 | err = -EOPNOTSUPP; |
2356 | goto done; |
2357 | } |
2358 | |
2359 | while (test_and_set_bit(nr: ICE_CFG_BUSY, addr: pf->state)) { |
2360 | timeout--; |
2361 | if (!timeout) { |
2362 | err = -EBUSY; |
2363 | goto done; |
2364 | } |
2365 | usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); |
2366 | } |
2367 | |
2368 | /* Copy the current user PHY configuration. The current user PHY |
2369 | * configuration is initialized during probe from PHY capabilities |
2370 | * software mode, and updated on set PHY configuration. |
2371 | */ |
2372 | config = pi->phy.curr_user_phy_cfg; |
2373 | |
2374 | config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; |
2375 | |
2376 | /* Check autoneg */ |
2377 | err = ice_setup_autoneg(p: pi, ks: &safe_ks, config: &config, autoneg_enabled: autoneg, autoneg_changed: &autoneg_changed, |
2378 | netdev); |
2379 | |
2380 | if (err) |
2381 | goto done; |
2382 | |
2383 | /* Call to get the current link speed */ |
2384 | pi->phy.get_link_info = true; |
2385 | err = ice_get_link_status(pi, link_up: &linkup); |
2386 | if (err) |
2387 | goto done; |
2388 | |
2389 | curr_link_speed = pi->phy.curr_user_speed_req; |
2390 | adv_link_speed = ice_ksettings_find_adv_link_speed(ks); |
2391 | |
2392 | /* If speed didn't get set, set it to what it currently is. |
2393 | * This is needed because if advertise is 0 (as it is when autoneg |
2394 | * is disabled) then speed won't get set. |
2395 | */ |
2396 | if (!adv_link_speed) |
2397 | adv_link_speed = curr_link_speed; |
2398 | |
2399 | /* Convert the advertise link speeds to their corresponded PHY_TYPE */ |
2400 | ice_set_phy_type_from_speed(ks, phy_type_low: &phy_type_low, phy_type_high: &phy_type_high, |
2401 | adv_link_speed); |
2402 | |
2403 | if (!autoneg_changed && adv_link_speed == curr_link_speed) { |
2404 | netdev_info(dev: netdev, format: "Nothing changed, exiting without setting anything.\n" ); |
2405 | goto done; |
2406 | } |
2407 | |
2408 | /* save the requested speeds */ |
2409 | pi->phy.link_info.req_speeds = adv_link_speed; |
2410 | |
2411 | /* set link and auto negotiation so changes take effect */ |
2412 | config.caps |= ICE_AQ_PHY_ENA_LINK; |
2413 | |
2414 | /* check if there is a PHY type for the requested advertised speed */ |
2415 | if (!(phy_type_low || phy_type_high)) { |
2416 | 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" ); |
2417 | err = -EOPNOTSUPP; |
2418 | goto done; |
2419 | } |
2420 | |
2421 | /* intersect requested advertised speed PHY types with media PHY types |
2422 | * for set PHY configuration |
2423 | */ |
2424 | config.phy_type_high = cpu_to_le64(phy_type_high) & |
2425 | phy_caps->phy_type_high; |
2426 | config.phy_type_low = cpu_to_le64(phy_type_low) & |
2427 | phy_caps->phy_type_low; |
2428 | |
2429 | if (!(config.phy_type_high || config.phy_type_low)) { |
2430 | /* If there is no intersection and lenient mode is enabled, then |
2431 | * intersect the requested advertised speed with NVM media type |
2432 | * PHY types. |
2433 | */ |
2434 | if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) { |
2435 | config.phy_type_high = cpu_to_le64(phy_type_high) & |
2436 | pf->nvm_phy_type_hi; |
2437 | config.phy_type_low = cpu_to_le64(phy_type_low) & |
2438 | pf->nvm_phy_type_lo; |
2439 | } else { |
2440 | 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" ); |
2441 | err = -EOPNOTSUPP; |
2442 | goto done; |
2443 | } |
2444 | } |
2445 | |
2446 | /* If link is up put link down */ |
2447 | if (pi->phy.link_info.link_info & ICE_AQ_LINK_UP) { |
2448 | /* Tell the OS link is going down, the link will go |
2449 | * back up when fw says it is ready asynchronously |
2450 | */ |
2451 | ice_print_link_msg(vsi: np->vsi, isup: false); |
2452 | netif_carrier_off(dev: netdev); |
2453 | netif_tx_stop_all_queues(dev: netdev); |
2454 | } |
2455 | |
2456 | /* make the aq call */ |
2457 | err = ice_aq_set_phy_cfg(hw: &pf->hw, pi, cfg: &config, NULL); |
2458 | if (err) { |
2459 | netdev_info(dev: netdev, format: "Set phy config failed,\n" ); |
2460 | goto done; |
2461 | } |
2462 | |
2463 | /* Save speed request */ |
2464 | pi->phy.curr_user_speed_req = adv_link_speed; |
2465 | done: |
2466 | kfree(objp: phy_caps); |
2467 | clear_bit(nr: ICE_CFG_BUSY, addr: pf->state); |
2468 | |
2469 | return err; |
2470 | } |
2471 | |
2472 | /** |
2473 | * ice_parse_hdrs - parses headers from RSS hash input |
2474 | * @nfc: ethtool rxnfc command |
2475 | * |
2476 | * This function parses the rxnfc command and returns intended |
2477 | * header types for RSS configuration |
2478 | */ |
2479 | static u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc) |
2480 | { |
2481 | u32 hdrs = ICE_FLOW_SEG_HDR_NONE; |
2482 | |
2483 | switch (nfc->flow_type) { |
2484 | case TCP_V4_FLOW: |
2485 | hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4; |
2486 | break; |
2487 | case UDP_V4_FLOW: |
2488 | hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4; |
2489 | break; |
2490 | case SCTP_V4_FLOW: |
2491 | hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4; |
2492 | break; |
2493 | case TCP_V6_FLOW: |
2494 | hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6; |
2495 | break; |
2496 | case UDP_V6_FLOW: |
2497 | hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6; |
2498 | break; |
2499 | case SCTP_V6_FLOW: |
2500 | hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6; |
2501 | break; |
2502 | default: |
2503 | break; |
2504 | } |
2505 | return hdrs; |
2506 | } |
2507 | |
2508 | #define ICE_FLOW_HASH_FLD_IPV4_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
2509 | #define ICE_FLOW_HASH_FLD_IPV6_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) |
2510 | #define ICE_FLOW_HASH_FLD_IPV4_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
2511 | #define ICE_FLOW_HASH_FLD_IPV6_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) |
2512 | #define ICE_FLOW_HASH_FLD_TCP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT) |
2513 | #define ICE_FLOW_HASH_FLD_TCP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT) |
2514 | #define ICE_FLOW_HASH_FLD_UDP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT) |
2515 | #define ICE_FLOW_HASH_FLD_UDP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT) |
2516 | #define ICE_FLOW_HASH_FLD_SCTP_SRC_PORT \ |
2517 | BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT) |
2518 | #define ICE_FLOW_HASH_FLD_SCTP_DST_PORT \ |
2519 | BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT) |
2520 | |
2521 | /** |
2522 | * ice_parse_hash_flds - parses hash fields from RSS hash input |
2523 | * @nfc: ethtool rxnfc command |
2524 | * |
2525 | * This function parses the rxnfc command and returns intended |
2526 | * hash fields for RSS configuration |
2527 | */ |
2528 | static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc) |
2529 | { |
2530 | u64 hfld = ICE_HASH_INVALID; |
2531 | |
2532 | if (nfc->data & RXH_IP_SRC || nfc->data & RXH_IP_DST) { |
2533 | switch (nfc->flow_type) { |
2534 | case TCP_V4_FLOW: |
2535 | case UDP_V4_FLOW: |
2536 | case SCTP_V4_FLOW: |
2537 | if (nfc->data & RXH_IP_SRC) |
2538 | hfld |= ICE_FLOW_HASH_FLD_IPV4_SA; |
2539 | if (nfc->data & RXH_IP_DST) |
2540 | hfld |= ICE_FLOW_HASH_FLD_IPV4_DA; |
2541 | break; |
2542 | case TCP_V6_FLOW: |
2543 | case UDP_V6_FLOW: |
2544 | case SCTP_V6_FLOW: |
2545 | if (nfc->data & RXH_IP_SRC) |
2546 | hfld |= ICE_FLOW_HASH_FLD_IPV6_SA; |
2547 | if (nfc->data & RXH_IP_DST) |
2548 | hfld |= ICE_FLOW_HASH_FLD_IPV6_DA; |
2549 | break; |
2550 | default: |
2551 | break; |
2552 | } |
2553 | } |
2554 | |
2555 | if (nfc->data & RXH_L4_B_0_1 || nfc->data & RXH_L4_B_2_3) { |
2556 | switch (nfc->flow_type) { |
2557 | case TCP_V4_FLOW: |
2558 | case TCP_V6_FLOW: |
2559 | if (nfc->data & RXH_L4_B_0_1) |
2560 | hfld |= ICE_FLOW_HASH_FLD_TCP_SRC_PORT; |
2561 | if (nfc->data & RXH_L4_B_2_3) |
2562 | hfld |= ICE_FLOW_HASH_FLD_TCP_DST_PORT; |
2563 | break; |
2564 | case UDP_V4_FLOW: |
2565 | case UDP_V6_FLOW: |
2566 | if (nfc->data & RXH_L4_B_0_1) |
2567 | hfld |= ICE_FLOW_HASH_FLD_UDP_SRC_PORT; |
2568 | if (nfc->data & RXH_L4_B_2_3) |
2569 | hfld |= ICE_FLOW_HASH_FLD_UDP_DST_PORT; |
2570 | break; |
2571 | case SCTP_V4_FLOW: |
2572 | case SCTP_V6_FLOW: |
2573 | if (nfc->data & RXH_L4_B_0_1) |
2574 | hfld |= ICE_FLOW_HASH_FLD_SCTP_SRC_PORT; |
2575 | if (nfc->data & RXH_L4_B_2_3) |
2576 | hfld |= ICE_FLOW_HASH_FLD_SCTP_DST_PORT; |
2577 | break; |
2578 | default: |
2579 | break; |
2580 | } |
2581 | } |
2582 | |
2583 | return hfld; |
2584 | } |
2585 | |
2586 | /** |
2587 | * ice_set_rss_hash_opt - Enable/Disable flow types for RSS hash |
2588 | * @vsi: the VSI being configured |
2589 | * @nfc: ethtool rxnfc command |
2590 | * |
2591 | * Returns Success if the flow input set is supported. |
2592 | */ |
2593 | static int |
2594 | (struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) |
2595 | { |
2596 | struct ice_pf *pf = vsi->back; |
2597 | struct device *dev; |
2598 | u64 hashed_flds; |
2599 | int status; |
2600 | u32 hdrs; |
2601 | |
2602 | dev = ice_pf_to_dev(pf); |
2603 | if (ice_is_safe_mode(pf)) { |
2604 | dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n" , |
2605 | vsi->vsi_num); |
2606 | return -EINVAL; |
2607 | } |
2608 | |
2609 | hashed_flds = ice_parse_hash_flds(nfc); |
2610 | if (hashed_flds == ICE_HASH_INVALID) { |
2611 | dev_dbg(dev, "Invalid hash fields, vsi num = %d\n" , |
2612 | vsi->vsi_num); |
2613 | return -EINVAL; |
2614 | } |
2615 | |
2616 | hdrs = ice_parse_hdrs(nfc); |
2617 | if (hdrs == ICE_FLOW_SEG_HDR_NONE) { |
2618 | dev_dbg(dev, "Header type is not valid, vsi num = %d\n" , |
2619 | vsi->vsi_num); |
2620 | return -EINVAL; |
2621 | } |
2622 | |
2623 | status = ice_add_rss_cfg(hw: &pf->hw, vsi_handle: vsi->idx, hashed_flds, addl_hdrs: hdrs); |
2624 | if (status) { |
2625 | dev_dbg(dev, "ice_add_rss_cfg failed, vsi num = %d, error = %d\n" , |
2626 | vsi->vsi_num, status); |
2627 | return status; |
2628 | } |
2629 | |
2630 | return 0; |
2631 | } |
2632 | |
2633 | /** |
2634 | * ice_get_rss_hash_opt - Retrieve hash fields for a given flow-type |
2635 | * @vsi: the VSI being configured |
2636 | * @nfc: ethtool rxnfc command |
2637 | */ |
2638 | static void |
2639 | (struct ice_vsi *vsi, struct ethtool_rxnfc *nfc) |
2640 | { |
2641 | struct ice_pf *pf = vsi->back; |
2642 | struct device *dev; |
2643 | u64 hash_flds; |
2644 | u32 hdrs; |
2645 | |
2646 | dev = ice_pf_to_dev(pf); |
2647 | |
2648 | nfc->data = 0; |
2649 | if (ice_is_safe_mode(pf)) { |
2650 | dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n" , |
2651 | vsi->vsi_num); |
2652 | return; |
2653 | } |
2654 | |
2655 | hdrs = ice_parse_hdrs(nfc); |
2656 | if (hdrs == ICE_FLOW_SEG_HDR_NONE) { |
2657 | dev_dbg(dev, "Header type is not valid, vsi num = %d\n" , |
2658 | vsi->vsi_num); |
2659 | return; |
2660 | } |
2661 | |
2662 | hash_flds = ice_get_rss_cfg(hw: &pf->hw, vsi_handle: vsi->idx, hdrs); |
2663 | if (hash_flds == ICE_HASH_INVALID) { |
2664 | dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n" , |
2665 | vsi->vsi_num); |
2666 | return; |
2667 | } |
2668 | |
2669 | if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_SA || |
2670 | hash_flds & ICE_FLOW_HASH_FLD_IPV6_SA) |
2671 | nfc->data |= (u64)RXH_IP_SRC; |
2672 | |
2673 | if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_DA || |
2674 | hash_flds & ICE_FLOW_HASH_FLD_IPV6_DA) |
2675 | nfc->data |= (u64)RXH_IP_DST; |
2676 | |
2677 | if (hash_flds & ICE_FLOW_HASH_FLD_TCP_SRC_PORT || |
2678 | hash_flds & ICE_FLOW_HASH_FLD_UDP_SRC_PORT || |
2679 | hash_flds & ICE_FLOW_HASH_FLD_SCTP_SRC_PORT) |
2680 | nfc->data |= (u64)RXH_L4_B_0_1; |
2681 | |
2682 | if (hash_flds & ICE_FLOW_HASH_FLD_TCP_DST_PORT || |
2683 | hash_flds & ICE_FLOW_HASH_FLD_UDP_DST_PORT || |
2684 | hash_flds & ICE_FLOW_HASH_FLD_SCTP_DST_PORT) |
2685 | nfc->data |= (u64)RXH_L4_B_2_3; |
2686 | } |
2687 | |
2688 | /** |
2689 | * ice_set_rxnfc - command to set Rx flow rules. |
2690 | * @netdev: network interface device structure |
2691 | * @cmd: ethtool rxnfc command |
2692 | * |
2693 | * Returns 0 for success and negative values for errors |
2694 | */ |
2695 | static int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) |
2696 | { |
2697 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2698 | struct ice_vsi *vsi = np->vsi; |
2699 | |
2700 | switch (cmd->cmd) { |
2701 | case ETHTOOL_SRXCLSRLINS: |
2702 | return ice_add_fdir_ethtool(vsi, cmd); |
2703 | case ETHTOOL_SRXCLSRLDEL: |
2704 | return ice_del_fdir_ethtool(vsi, cmd); |
2705 | case ETHTOOL_SRXFH: |
2706 | return ice_set_rss_hash_opt(vsi, nfc: cmd); |
2707 | default: |
2708 | break; |
2709 | } |
2710 | return -EOPNOTSUPP; |
2711 | } |
2712 | |
2713 | /** |
2714 | * ice_get_rxnfc - command to get Rx flow classification rules |
2715 | * @netdev: network interface device structure |
2716 | * @cmd: ethtool rxnfc command |
2717 | * @rule_locs: buffer to rturn Rx flow classification rules |
2718 | * |
2719 | * Returns Success if the command is supported. |
2720 | */ |
2721 | static int |
2722 | ice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, |
2723 | u32 __always_unused *rule_locs) |
2724 | { |
2725 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2726 | struct ice_vsi *vsi = np->vsi; |
2727 | int ret = -EOPNOTSUPP; |
2728 | struct ice_hw *hw; |
2729 | |
2730 | hw = &vsi->back->hw; |
2731 | |
2732 | switch (cmd->cmd) { |
2733 | case ETHTOOL_GRXRINGS: |
2734 | cmd->data = vsi->rss_size; |
2735 | ret = 0; |
2736 | break; |
2737 | case ETHTOOL_GRXCLSRLCNT: |
2738 | cmd->rule_cnt = hw->fdir_active_fltr; |
2739 | /* report total rule count */ |
2740 | cmd->data = ice_get_fdir_cnt_all(hw); |
2741 | ret = 0; |
2742 | break; |
2743 | case ETHTOOL_GRXCLSRULE: |
2744 | ret = ice_get_ethtool_fdir_entry(hw, cmd); |
2745 | break; |
2746 | case ETHTOOL_GRXCLSRLALL: |
2747 | ret = ice_get_fdir_fltr_ids(hw, cmd, rule_locs: (u32 *)rule_locs); |
2748 | break; |
2749 | case ETHTOOL_GRXFH: |
2750 | ice_get_rss_hash_opt(vsi, nfc: cmd); |
2751 | ret = 0; |
2752 | break; |
2753 | default: |
2754 | break; |
2755 | } |
2756 | |
2757 | return ret; |
2758 | } |
2759 | |
2760 | static void |
2761 | ice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, |
2762 | struct kernel_ethtool_ringparam *kernel_ring, |
2763 | struct netlink_ext_ack *extack) |
2764 | { |
2765 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2766 | struct ice_vsi *vsi = np->vsi; |
2767 | |
2768 | ring->rx_max_pending = ICE_MAX_NUM_DESC; |
2769 | ring->tx_max_pending = ICE_MAX_NUM_DESC; |
2770 | if (vsi->tx_rings && vsi->rx_rings) { |
2771 | ring->rx_pending = vsi->rx_rings[0]->count; |
2772 | ring->tx_pending = vsi->tx_rings[0]->count; |
2773 | } else { |
2774 | ring->rx_pending = 0; |
2775 | ring->tx_pending = 0; |
2776 | } |
2777 | |
2778 | /* Rx mini and jumbo rings are not supported */ |
2779 | ring->rx_mini_max_pending = 0; |
2780 | ring->rx_jumbo_max_pending = 0; |
2781 | ring->rx_mini_pending = 0; |
2782 | ring->rx_jumbo_pending = 0; |
2783 | } |
2784 | |
2785 | static int |
2786 | ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, |
2787 | struct kernel_ethtool_ringparam *kernel_ring, |
2788 | struct netlink_ext_ack *extack) |
2789 | { |
2790 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
2791 | struct ice_tx_ring *xdp_rings = NULL; |
2792 | struct ice_tx_ring *tx_rings = NULL; |
2793 | struct ice_rx_ring *rx_rings = NULL; |
2794 | struct ice_vsi *vsi = np->vsi; |
2795 | struct ice_pf *pf = vsi->back; |
2796 | int i, timeout = 50, err = 0; |
2797 | u16 new_rx_cnt, new_tx_cnt; |
2798 | |
2799 | if (ring->tx_pending > ICE_MAX_NUM_DESC || |
2800 | ring->tx_pending < ICE_MIN_NUM_DESC || |
2801 | ring->rx_pending > ICE_MAX_NUM_DESC || |
2802 | ring->rx_pending < ICE_MIN_NUM_DESC) { |
2803 | netdev_err(dev: netdev, format: "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n" , |
2804 | ring->tx_pending, ring->rx_pending, |
2805 | ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC, |
2806 | ICE_REQ_DESC_MULTIPLE); |
2807 | return -EINVAL; |
2808 | } |
2809 | |
2810 | /* Return if there is no rings (device is reloading) */ |
2811 | if (!vsi->tx_rings || !vsi->rx_rings) |
2812 | return -EBUSY; |
2813 | |
2814 | new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); |
2815 | if (new_tx_cnt != ring->tx_pending) |
2816 | netdev_info(dev: netdev, format: "Requested Tx descriptor count rounded up to %d\n" , |
2817 | new_tx_cnt); |
2818 | new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); |
2819 | if (new_rx_cnt != ring->rx_pending) |
2820 | netdev_info(dev: netdev, format: "Requested Rx descriptor count rounded up to %d\n" , |
2821 | new_rx_cnt); |
2822 | |
2823 | /* if nothing to do return success */ |
2824 | if (new_tx_cnt == vsi->tx_rings[0]->count && |
2825 | new_rx_cnt == vsi->rx_rings[0]->count) { |
2826 | netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n" ); |
2827 | return 0; |
2828 | } |
2829 | |
2830 | /* If there is a AF_XDP UMEM attached to any of Rx rings, |
2831 | * disallow changing the number of descriptors -- regardless |
2832 | * if the netdev is running or not. |
2833 | */ |
2834 | if (ice_xsk_any_rx_ring_ena(vsi)) |
2835 | return -EBUSY; |
2836 | |
2837 | while (test_and_set_bit(nr: ICE_CFG_BUSY, addr: pf->state)) { |
2838 | timeout--; |
2839 | if (!timeout) |
2840 | return -EBUSY; |
2841 | usleep_range(min: 1000, max: 2000); |
2842 | } |
2843 | |
2844 | /* set for the next time the netdev is started */ |
2845 | if (!netif_running(dev: vsi->netdev)) { |
2846 | ice_for_each_alloc_txq(vsi, i) |
2847 | vsi->tx_rings[i]->count = new_tx_cnt; |
2848 | ice_for_each_alloc_rxq(vsi, i) |
2849 | vsi->rx_rings[i]->count = new_rx_cnt; |
2850 | if (ice_is_xdp_ena_vsi(vsi)) |
2851 | ice_for_each_xdp_txq(vsi, i) |
2852 | vsi->xdp_rings[i]->count = new_tx_cnt; |
2853 | vsi->num_tx_desc = (u16)new_tx_cnt; |
2854 | vsi->num_rx_desc = (u16)new_rx_cnt; |
2855 | netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n" ); |
2856 | goto done; |
2857 | } |
2858 | |
2859 | if (new_tx_cnt == vsi->tx_rings[0]->count) |
2860 | goto process_rx; |
2861 | |
2862 | /* alloc updated Tx resources */ |
2863 | netdev_info(dev: netdev, format: "Changing Tx descriptor count from %d to %d\n" , |
2864 | vsi->tx_rings[0]->count, new_tx_cnt); |
2865 | |
2866 | tx_rings = kcalloc(n: vsi->num_txq, size: sizeof(*tx_rings), GFP_KERNEL); |
2867 | if (!tx_rings) { |
2868 | err = -ENOMEM; |
2869 | goto done; |
2870 | } |
2871 | |
2872 | ice_for_each_txq(vsi, i) { |
2873 | /* clone ring and setup updated count */ |
2874 | tx_rings[i] = *vsi->tx_rings[i]; |
2875 | tx_rings[i].count = new_tx_cnt; |
2876 | tx_rings[i].desc = NULL; |
2877 | tx_rings[i].tx_buf = NULL; |
2878 | tx_rings[i].tx_tstamps = &pf->ptp.port.tx; |
2879 | err = ice_setup_tx_ring(tx_ring: &tx_rings[i]); |
2880 | if (err) { |
2881 | while (i--) |
2882 | ice_clean_tx_ring(tx_ring: &tx_rings[i]); |
2883 | kfree(objp: tx_rings); |
2884 | goto done; |
2885 | } |
2886 | } |
2887 | |
2888 | if (!ice_is_xdp_ena_vsi(vsi)) |
2889 | goto process_rx; |
2890 | |
2891 | /* alloc updated XDP resources */ |
2892 | netdev_info(dev: netdev, format: "Changing XDP descriptor count from %d to %d\n" , |
2893 | vsi->xdp_rings[0]->count, new_tx_cnt); |
2894 | |
2895 | xdp_rings = kcalloc(n: vsi->num_xdp_txq, size: sizeof(*xdp_rings), GFP_KERNEL); |
2896 | if (!xdp_rings) { |
2897 | err = -ENOMEM; |
2898 | goto free_tx; |
2899 | } |
2900 | |
2901 | ice_for_each_xdp_txq(vsi, i) { |
2902 | /* clone ring and setup updated count */ |
2903 | xdp_rings[i] = *vsi->xdp_rings[i]; |
2904 | xdp_rings[i].count = new_tx_cnt; |
2905 | xdp_rings[i].desc = NULL; |
2906 | xdp_rings[i].tx_buf = NULL; |
2907 | err = ice_setup_tx_ring(tx_ring: &xdp_rings[i]); |
2908 | if (err) { |
2909 | while (i--) |
2910 | ice_clean_tx_ring(tx_ring: &xdp_rings[i]); |
2911 | kfree(objp: xdp_rings); |
2912 | goto free_tx; |
2913 | } |
2914 | ice_set_ring_xdp(ring: &xdp_rings[i]); |
2915 | } |
2916 | |
2917 | process_rx: |
2918 | if (new_rx_cnt == vsi->rx_rings[0]->count) |
2919 | goto process_link; |
2920 | |
2921 | /* alloc updated Rx resources */ |
2922 | netdev_info(dev: netdev, format: "Changing Rx descriptor count from %d to %d\n" , |
2923 | vsi->rx_rings[0]->count, new_rx_cnt); |
2924 | |
2925 | rx_rings = kcalloc(n: vsi->num_rxq, size: sizeof(*rx_rings), GFP_KERNEL); |
2926 | if (!rx_rings) { |
2927 | err = -ENOMEM; |
2928 | goto done; |
2929 | } |
2930 | |
2931 | ice_for_each_rxq(vsi, i) { |
2932 | /* clone ring and setup updated count */ |
2933 | rx_rings[i] = *vsi->rx_rings[i]; |
2934 | rx_rings[i].count = new_rx_cnt; |
2935 | rx_rings[i].cached_phctime = pf->ptp.cached_phc_time; |
2936 | rx_rings[i].desc = NULL; |
2937 | rx_rings[i].rx_buf = NULL; |
2938 | /* this is to allow wr32 to have something to write to |
2939 | * during early allocation of Rx buffers |
2940 | */ |
2941 | rx_rings[i].tail = vsi->back->hw.hw_addr + PRTGEN_STATUS; |
2942 | |
2943 | err = ice_setup_rx_ring(rx_ring: &rx_rings[i]); |
2944 | if (err) |
2945 | goto rx_unwind; |
2946 | |
2947 | /* allocate Rx buffers */ |
2948 | err = ice_alloc_rx_bufs(rxr: &rx_rings[i], |
2949 | ICE_RX_DESC_UNUSED(&rx_rings[i])); |
2950 | rx_unwind: |
2951 | if (err) { |
2952 | while (i) { |
2953 | i--; |
2954 | ice_free_rx_ring(rx_ring: &rx_rings[i]); |
2955 | } |
2956 | kfree(objp: rx_rings); |
2957 | err = -ENOMEM; |
2958 | goto free_tx; |
2959 | } |
2960 | } |
2961 | |
2962 | process_link: |
2963 | /* Bring interface down, copy in the new ring info, then restore the |
2964 | * interface. if VSI is up, bring it down and then back up |
2965 | */ |
2966 | if (!test_and_set_bit(nr: ICE_VSI_DOWN, addr: vsi->state)) { |
2967 | ice_down(vsi); |
2968 | |
2969 | if (tx_rings) { |
2970 | ice_for_each_txq(vsi, i) { |
2971 | ice_free_tx_ring(tx_ring: vsi->tx_rings[i]); |
2972 | *vsi->tx_rings[i] = tx_rings[i]; |
2973 | } |
2974 | kfree(objp: tx_rings); |
2975 | } |
2976 | |
2977 | if (rx_rings) { |
2978 | ice_for_each_rxq(vsi, i) { |
2979 | ice_free_rx_ring(rx_ring: vsi->rx_rings[i]); |
2980 | /* copy the real tail offset */ |
2981 | rx_rings[i].tail = vsi->rx_rings[i]->tail; |
2982 | /* this is to fake out the allocation routine |
2983 | * into thinking it has to realloc everything |
2984 | * but the recycling logic will let us re-use |
2985 | * the buffers allocated above |
2986 | */ |
2987 | rx_rings[i].next_to_use = 0; |
2988 | rx_rings[i].next_to_clean = 0; |
2989 | rx_rings[i].next_to_alloc = 0; |
2990 | *vsi->rx_rings[i] = rx_rings[i]; |
2991 | } |
2992 | kfree(objp: rx_rings); |
2993 | } |
2994 | |
2995 | if (xdp_rings) { |
2996 | ice_for_each_xdp_txq(vsi, i) { |
2997 | ice_free_tx_ring(tx_ring: vsi->xdp_rings[i]); |
2998 | *vsi->xdp_rings[i] = xdp_rings[i]; |
2999 | } |
3000 | kfree(objp: xdp_rings); |
3001 | } |
3002 | |
3003 | vsi->num_tx_desc = new_tx_cnt; |
3004 | vsi->num_rx_desc = new_rx_cnt; |
3005 | ice_up(vsi); |
3006 | } |
3007 | goto done; |
3008 | |
3009 | free_tx: |
3010 | /* error cleanup if the Rx allocations failed after getting Tx */ |
3011 | if (tx_rings) { |
3012 | ice_for_each_txq(vsi, i) |
3013 | ice_free_tx_ring(tx_ring: &tx_rings[i]); |
3014 | kfree(objp: tx_rings); |
3015 | } |
3016 | |
3017 | done: |
3018 | clear_bit(nr: ICE_CFG_BUSY, addr: pf->state); |
3019 | return err; |
3020 | } |
3021 | |
3022 | /** |
3023 | * ice_get_pauseparam - Get Flow Control status |
3024 | * @netdev: network interface device structure |
3025 | * @pause: ethernet pause (flow control) parameters |
3026 | * |
3027 | * Get requested flow control status from PHY capability. |
3028 | * If autoneg is true, then ethtool will send the ETHTOOL_GSET ioctl which |
3029 | * is handled by ice_get_link_ksettings. ice_get_link_ksettings will report |
3030 | * the negotiated Rx/Tx pause via lp_advertising. |
3031 | */ |
3032 | static void |
3033 | ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) |
3034 | { |
3035 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3036 | struct ice_port_info *pi = np->vsi->port_info; |
3037 | struct ice_aqc_get_phy_caps_data *pcaps; |
3038 | struct ice_dcbx_cfg *dcbx_cfg; |
3039 | int status; |
3040 | |
3041 | /* Initialize pause params */ |
3042 | pause->rx_pause = 0; |
3043 | pause->tx_pause = 0; |
3044 | |
3045 | dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; |
3046 | |
3047 | pcaps = kzalloc(size: sizeof(*pcaps), GFP_KERNEL); |
3048 | if (!pcaps) |
3049 | return; |
3050 | |
3051 | /* Get current PHY config */ |
3052 | status = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_ACTIVE_CFG, caps: pcaps, |
3053 | NULL); |
3054 | if (status) |
3055 | goto out; |
3056 | |
3057 | pause->autoneg = ice_is_phy_caps_an_enabled(caps: pcaps) ? AUTONEG_ENABLE : |
3058 | AUTONEG_DISABLE; |
3059 | |
3060 | if (dcbx_cfg->pfc.pfcena) |
3061 | /* PFC enabled so report LFC as off */ |
3062 | goto out; |
3063 | |
3064 | if (pcaps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) |
3065 | pause->tx_pause = 1; |
3066 | if (pcaps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) |
3067 | pause->rx_pause = 1; |
3068 | |
3069 | out: |
3070 | kfree(objp: pcaps); |
3071 | } |
3072 | |
3073 | /** |
3074 | * ice_set_pauseparam - Set Flow Control parameter |
3075 | * @netdev: network interface device structure |
3076 | * @pause: return Tx/Rx flow control status |
3077 | */ |
3078 | static int |
3079 | ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) |
3080 | { |
3081 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3082 | struct ice_aqc_get_phy_caps_data *pcaps; |
3083 | struct ice_link_status *hw_link_info; |
3084 | struct ice_pf *pf = np->vsi->back; |
3085 | struct ice_dcbx_cfg *dcbx_cfg; |
3086 | struct ice_vsi *vsi = np->vsi; |
3087 | struct ice_hw *hw = &pf->hw; |
3088 | struct ice_port_info *pi; |
3089 | u8 aq_failures; |
3090 | bool link_up; |
3091 | u32 is_an; |
3092 | int err; |
3093 | |
3094 | pi = vsi->port_info; |
3095 | hw_link_info = &pi->phy.link_info; |
3096 | dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg; |
3097 | link_up = hw_link_info->link_info & ICE_AQ_LINK_UP; |
3098 | |
3099 | /* Changing the port's flow control is not supported if this isn't the |
3100 | * PF VSI |
3101 | */ |
3102 | if (vsi->type != ICE_VSI_PF) { |
3103 | netdev_info(dev: netdev, format: "Changing flow control parameters only supported for PF VSI\n" ); |
3104 | return -EOPNOTSUPP; |
3105 | } |
3106 | |
3107 | /* Get pause param reports configured and negotiated flow control pause |
3108 | * when ETHTOOL_GLINKSETTINGS is defined. Since ETHTOOL_GLINKSETTINGS is |
3109 | * defined get pause param pause->autoneg reports SW configured setting, |
3110 | * so compare pause->autoneg with SW configured to prevent the user from |
3111 | * using set pause param to chance autoneg. |
3112 | */ |
3113 | pcaps = kzalloc(size: sizeof(*pcaps), GFP_KERNEL); |
3114 | if (!pcaps) |
3115 | return -ENOMEM; |
3116 | |
3117 | /* Get current PHY config */ |
3118 | err = ice_aq_get_phy_caps(pi, qual_mods: false, ICE_AQC_REPORT_ACTIVE_CFG, caps: pcaps, |
3119 | NULL); |
3120 | if (err) { |
3121 | kfree(objp: pcaps); |
3122 | return err; |
3123 | } |
3124 | |
3125 | is_an = ice_is_phy_caps_an_enabled(caps: pcaps) ? AUTONEG_ENABLE : |
3126 | AUTONEG_DISABLE; |
3127 | |
3128 | kfree(objp: pcaps); |
3129 | |
3130 | if (pause->autoneg != is_an) { |
3131 | netdev_info(dev: netdev, format: "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n" ); |
3132 | return -EOPNOTSUPP; |
3133 | } |
3134 | |
3135 | /* If we have link and don't have autoneg */ |
3136 | if (!test_bit(ICE_DOWN, pf->state) && |
3137 | !(hw_link_info->an_info & ICE_AQ_AN_COMPLETED)) { |
3138 | /* Send message that it might not necessarily work*/ |
3139 | netdev_info(dev: netdev, format: "Autoneg did not complete so changing settings may not result in an actual change.\n" ); |
3140 | } |
3141 | |
3142 | if (dcbx_cfg->pfc.pfcena) { |
3143 | netdev_info(dev: netdev, format: "Priority flow control enabled. Cannot set link flow control.\n" ); |
3144 | return -EOPNOTSUPP; |
3145 | } |
3146 | if (pause->rx_pause && pause->tx_pause) |
3147 | pi->fc.req_mode = ICE_FC_FULL; |
3148 | else if (pause->rx_pause && !pause->tx_pause) |
3149 | pi->fc.req_mode = ICE_FC_RX_PAUSE; |
3150 | else if (!pause->rx_pause && pause->tx_pause) |
3151 | pi->fc.req_mode = ICE_FC_TX_PAUSE; |
3152 | else if (!pause->rx_pause && !pause->tx_pause) |
3153 | pi->fc.req_mode = ICE_FC_NONE; |
3154 | else |
3155 | return -EINVAL; |
3156 | |
3157 | /* Set the FC mode and only restart AN if link is up */ |
3158 | err = ice_set_fc(pi, aq_failures: &aq_failures, ena_auto_link_update: link_up); |
3159 | |
3160 | if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) { |
3161 | netdev_info(dev: netdev, format: "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n" , |
3162 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3163 | err = -EAGAIN; |
3164 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) { |
3165 | netdev_info(dev: netdev, format: "Set fc failed on the set_phy_config call with err %d aq_err %s\n" , |
3166 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3167 | err = -EAGAIN; |
3168 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) { |
3169 | netdev_info(dev: netdev, format: "Set fc failed on the get_link_info call with err %d aq_err %s\n" , |
3170 | err, ice_aq_str(aq_err: hw->adminq.sq_last_status)); |
3171 | err = -EAGAIN; |
3172 | } |
3173 | |
3174 | return err; |
3175 | } |
3176 | |
3177 | /** |
3178 | * ice_get_rxfh_key_size - get the RSS hash key size |
3179 | * @netdev: network interface device structure |
3180 | * |
3181 | * Returns the table size. |
3182 | */ |
3183 | static u32 ice_get_rxfh_key_size(struct net_device __always_unused *netdev) |
3184 | { |
3185 | return ICE_VSIQF_HKEY_ARRAY_SIZE; |
3186 | } |
3187 | |
3188 | /** |
3189 | * ice_get_rxfh_indir_size - get the Rx flow hash indirection table size |
3190 | * @netdev: network interface device structure |
3191 | * |
3192 | * Returns the table size. |
3193 | */ |
3194 | static u32 ice_get_rxfh_indir_size(struct net_device *netdev) |
3195 | { |
3196 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3197 | |
3198 | return np->vsi->rss_table_size; |
3199 | } |
3200 | |
3201 | static int |
3202 | ice_get_rxfh_context(struct net_device *netdev, u32 *indir, |
3203 | u8 *key, u8 *hfunc, u32 ) |
3204 | { |
3205 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3206 | struct ice_vsi *vsi = np->vsi; |
3207 | struct ice_pf *pf = vsi->back; |
3208 | u16 qcount, offset; |
3209 | int err, num_tc, i; |
3210 | u8 *lut; |
3211 | |
3212 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { |
3213 | netdev_warn(dev: netdev, format: "RSS is not supported on this VSI!\n" ); |
3214 | return -EOPNOTSUPP; |
3215 | } |
3216 | |
3217 | if (rss_context && !ice_is_adq_active(pf)) { |
3218 | netdev_err(dev: netdev, format: "RSS context cannot be non-zero when ADQ is not configured.\n" ); |
3219 | return -EINVAL; |
3220 | } |
3221 | |
3222 | qcount = vsi->mqprio_qopt.qopt.count[rss_context]; |
3223 | offset = vsi->mqprio_qopt.qopt.offset[rss_context]; |
3224 | |
3225 | if (rss_context && ice_is_adq_active(pf)) { |
3226 | num_tc = vsi->mqprio_qopt.qopt.num_tc; |
3227 | if (rss_context >= num_tc) { |
3228 | netdev_err(dev: netdev, format: "RSS context:%d > num_tc:%d\n" , |
3229 | rss_context, num_tc); |
3230 | return -EINVAL; |
3231 | } |
3232 | /* Use channel VSI of given TC */ |
3233 | vsi = vsi->tc_map_vsi[rss_context]; |
3234 | } |
3235 | |
3236 | if (hfunc) |
3237 | *hfunc = ETH_RSS_HASH_TOP; |
3238 | |
3239 | if (!indir) |
3240 | return 0; |
3241 | |
3242 | lut = kzalloc(size: vsi->rss_table_size, GFP_KERNEL); |
3243 | if (!lut) |
3244 | return -ENOMEM; |
3245 | |
3246 | err = ice_get_rss_key(vsi, seed: key); |
3247 | if (err) |
3248 | goto out; |
3249 | |
3250 | err = ice_get_rss_lut(vsi, lut, lut_size: vsi->rss_table_size); |
3251 | if (err) |
3252 | goto out; |
3253 | |
3254 | if (ice_is_adq_active(pf)) { |
3255 | for (i = 0; i < vsi->rss_table_size; i++) |
3256 | indir[i] = offset + lut[i] % qcount; |
3257 | goto out; |
3258 | } |
3259 | |
3260 | for (i = 0; i < vsi->rss_table_size; i++) |
3261 | indir[i] = lut[i]; |
3262 | |
3263 | out: |
3264 | kfree(objp: lut); |
3265 | return err; |
3266 | } |
3267 | |
3268 | /** |
3269 | * ice_get_rxfh - get the Rx flow hash indirection table |
3270 | * @netdev: network interface device structure |
3271 | * @indir: indirection table |
3272 | * @key: hash key |
3273 | * @hfunc: hash function |
3274 | * |
3275 | * Reads the indirection table directly from the hardware. |
3276 | */ |
3277 | static int |
3278 | ice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) |
3279 | { |
3280 | return ice_get_rxfh_context(netdev, indir, key, hfunc, rss_context: 0); |
3281 | } |
3282 | |
3283 | /** |
3284 | * ice_set_rxfh - set the Rx flow hash indirection table |
3285 | * @netdev: network interface device structure |
3286 | * @indir: indirection table |
3287 | * @key: hash key |
3288 | * @hfunc: hash function |
3289 | * |
3290 | * Returns -EINVAL if the table specifies an invalid queue ID, otherwise |
3291 | * returns 0 after programming the table. |
3292 | */ |
3293 | static int |
3294 | ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, |
3295 | const u8 hfunc) |
3296 | { |
3297 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3298 | struct ice_vsi *vsi = np->vsi; |
3299 | struct ice_pf *pf = vsi->back; |
3300 | struct device *dev; |
3301 | int err; |
3302 | |
3303 | dev = ice_pf_to_dev(pf); |
3304 | if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) |
3305 | return -EOPNOTSUPP; |
3306 | |
3307 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { |
3308 | /* RSS not supported return error here */ |
3309 | netdev_warn(dev: netdev, format: "RSS is not configured on this VSI!\n" ); |
3310 | return -EIO; |
3311 | } |
3312 | |
3313 | if (ice_is_adq_active(pf)) { |
3314 | netdev_err(dev: netdev, format: "Cannot change RSS params with ADQ configured.\n" ); |
3315 | return -EOPNOTSUPP; |
3316 | } |
3317 | |
3318 | if (key) { |
3319 | if (!vsi->rss_hkey_user) { |
3320 | vsi->rss_hkey_user = |
3321 | devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE, |
3322 | GFP_KERNEL); |
3323 | if (!vsi->rss_hkey_user) |
3324 | return -ENOMEM; |
3325 | } |
3326 | memcpy(vsi->rss_hkey_user, key, ICE_VSIQF_HKEY_ARRAY_SIZE); |
3327 | |
3328 | err = ice_set_rss_key(vsi, seed: vsi->rss_hkey_user); |
3329 | if (err) |
3330 | return err; |
3331 | } |
3332 | |
3333 | if (!vsi->rss_lut_user) { |
3334 | vsi->rss_lut_user = devm_kzalloc(dev, size: vsi->rss_table_size, |
3335 | GFP_KERNEL); |
3336 | if (!vsi->rss_lut_user) |
3337 | return -ENOMEM; |
3338 | } |
3339 | |
3340 | /* Each 32 bits pointed by 'indir' is stored with a lut entry */ |
3341 | if (indir) { |
3342 | int i; |
3343 | |
3344 | for (i = 0; i < vsi->rss_table_size; i++) |
3345 | vsi->rss_lut_user[i] = (u8)(indir[i]); |
3346 | } else { |
3347 | ice_fill_rss_lut(lut: vsi->rss_lut_user, rss_table_size: vsi->rss_table_size, |
3348 | rss_size: vsi->rss_size); |
3349 | } |
3350 | |
3351 | err = ice_set_rss_lut(vsi, lut: vsi->rss_lut_user, lut_size: vsi->rss_table_size); |
3352 | if (err) |
3353 | return err; |
3354 | |
3355 | return 0; |
3356 | } |
3357 | |
3358 | static int |
3359 | ice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) |
3360 | { |
3361 | struct ice_pf *pf = ice_netdev_to_pf(netdev: dev); |
3362 | |
3363 | /* only report timestamping if PTP is enabled */ |
3364 | if (!test_bit(ICE_FLAG_PTP, pf->flags)) |
3365 | return ethtool_op_get_ts_info(dev, eti: info); |
3366 | |
3367 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
3368 | SOF_TIMESTAMPING_RX_SOFTWARE | |
3369 | SOF_TIMESTAMPING_SOFTWARE | |
3370 | SOF_TIMESTAMPING_TX_HARDWARE | |
3371 | SOF_TIMESTAMPING_RX_HARDWARE | |
3372 | SOF_TIMESTAMPING_RAW_HARDWARE; |
3373 | |
3374 | info->phc_index = ice_ptp_clock_index(pf); |
3375 | |
3376 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); |
3377 | |
3378 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); |
3379 | |
3380 | return 0; |
3381 | } |
3382 | |
3383 | /** |
3384 | * ice_get_max_txq - return the maximum number of Tx queues for in a PF |
3385 | * @pf: PF structure |
3386 | */ |
3387 | static int ice_get_max_txq(struct ice_pf *pf) |
3388 | { |
3389 | return min3(pf->num_lan_msix, (u16)num_online_cpus(), |
3390 | (u16)pf->hw.func_caps.common_cap.num_txq); |
3391 | } |
3392 | |
3393 | /** |
3394 | * ice_get_max_rxq - return the maximum number of Rx queues for in a PF |
3395 | * @pf: PF structure |
3396 | */ |
3397 | static int ice_get_max_rxq(struct ice_pf *pf) |
3398 | { |
3399 | return min3(pf->num_lan_msix, (u16)num_online_cpus(), |
3400 | (u16)pf->hw.func_caps.common_cap.num_rxq); |
3401 | } |
3402 | |
3403 | /** |
3404 | * ice_get_combined_cnt - return the current number of combined channels |
3405 | * @vsi: PF VSI pointer |
3406 | * |
3407 | * Go through all queue vectors and count ones that have both Rx and Tx ring |
3408 | * attached |
3409 | */ |
3410 | static u32 ice_get_combined_cnt(struct ice_vsi *vsi) |
3411 | { |
3412 | u32 combined = 0; |
3413 | int q_idx; |
3414 | |
3415 | ice_for_each_q_vector(vsi, q_idx) { |
3416 | struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; |
3417 | |
3418 | if (q_vector->rx.rx_ring && q_vector->tx.tx_ring) |
3419 | combined++; |
3420 | } |
3421 | |
3422 | return combined; |
3423 | } |
3424 | |
3425 | /** |
3426 | * ice_get_channels - get the current and max supported channels |
3427 | * @dev: network interface device structure |
3428 | * @ch: ethtool channel data structure |
3429 | */ |
3430 | static void |
3431 | ice_get_channels(struct net_device *dev, struct ethtool_channels *ch) |
3432 | { |
3433 | struct ice_netdev_priv *np = netdev_priv(dev); |
3434 | struct ice_vsi *vsi = np->vsi; |
3435 | struct ice_pf *pf = vsi->back; |
3436 | |
3437 | /* report maximum channels */ |
3438 | ch->max_rx = ice_get_max_rxq(pf); |
3439 | ch->max_tx = ice_get_max_txq(pf); |
3440 | ch->max_combined = min_t(int, ch->max_rx, ch->max_tx); |
3441 | |
3442 | /* report current channels */ |
3443 | ch->combined_count = ice_get_combined_cnt(vsi); |
3444 | ch->rx_count = vsi->num_rxq - ch->combined_count; |
3445 | ch->tx_count = vsi->num_txq - ch->combined_count; |
3446 | |
3447 | /* report other queues */ |
3448 | ch->other_count = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0; |
3449 | ch->max_other = ch->other_count; |
3450 | } |
3451 | |
3452 | /** |
3453 | * ice_get_valid_rss_size - return valid number of RSS queues |
3454 | * @hw: pointer to the HW structure |
3455 | * @new_size: requested RSS queues |
3456 | */ |
3457 | static int (struct ice_hw *hw, int new_size) |
3458 | { |
3459 | struct ice_hw_common_caps *caps = &hw->func_caps.common_cap; |
3460 | |
3461 | return min_t(int, new_size, BIT(caps->rss_table_entry_width)); |
3462 | } |
3463 | |
3464 | /** |
3465 | * ice_vsi_set_dflt_rss_lut - set default RSS LUT with requested RSS size |
3466 | * @vsi: VSI to reconfigure RSS LUT on |
3467 | * @req_rss_size: requested range of queue numbers for hashing |
3468 | * |
3469 | * Set the VSI's RSS parameters, configure the RSS LUT based on these. |
3470 | */ |
3471 | static int (struct ice_vsi *vsi, int ) |
3472 | { |
3473 | struct ice_pf *pf = vsi->back; |
3474 | struct device *dev; |
3475 | struct ice_hw *hw; |
3476 | int err; |
3477 | u8 *lut; |
3478 | |
3479 | dev = ice_pf_to_dev(pf); |
3480 | hw = &pf->hw; |
3481 | |
3482 | if (!req_rss_size) |
3483 | return -EINVAL; |
3484 | |
3485 | lut = kzalloc(size: vsi->rss_table_size, GFP_KERNEL); |
3486 | if (!lut) |
3487 | return -ENOMEM; |
3488 | |
3489 | /* set RSS LUT parameters */ |
3490 | if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) |
3491 | vsi->rss_size = 1; |
3492 | else |
3493 | vsi->rss_size = ice_get_valid_rss_size(hw, new_size: req_rss_size); |
3494 | |
3495 | /* create/set RSS LUT */ |
3496 | ice_fill_rss_lut(lut, rss_table_size: vsi->rss_table_size, rss_size: vsi->rss_size); |
3497 | err = ice_set_rss_lut(vsi, lut, lut_size: vsi->rss_table_size); |
3498 | if (err) |
3499 | dev_err(dev, "Cannot set RSS lut, err %d aq_err %s\n" , err, |
3500 | ice_aq_str(hw->adminq.sq_last_status)); |
3501 | |
3502 | kfree(objp: lut); |
3503 | return err; |
3504 | } |
3505 | |
3506 | /** |
3507 | * ice_set_channels - set the number channels |
3508 | * @dev: network interface device structure |
3509 | * @ch: ethtool channel data structure |
3510 | */ |
3511 | static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) |
3512 | { |
3513 | struct ice_netdev_priv *np = netdev_priv(dev); |
3514 | struct ice_vsi *vsi = np->vsi; |
3515 | struct ice_pf *pf = vsi->back; |
3516 | int new_rx = 0, new_tx = 0; |
3517 | bool locked = false; |
3518 | u32 curr_combined; |
3519 | int ret = 0; |
3520 | |
3521 | /* do not support changing channels in Safe Mode */ |
3522 | if (ice_is_safe_mode(pf)) { |
3523 | netdev_err(dev, format: "Changing channel in Safe Mode is not supported\n" ); |
3524 | return -EOPNOTSUPP; |
3525 | } |
3526 | /* do not support changing other_count */ |
3527 | if (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U)) |
3528 | return -EINVAL; |
3529 | |
3530 | if (ice_is_adq_active(pf)) { |
3531 | netdev_err(dev, format: "Cannot set channels with ADQ configured.\n" ); |
3532 | return -EOPNOTSUPP; |
3533 | } |
3534 | |
3535 | if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) { |
3536 | netdev_err(dev, format: "Cannot set channels when Flow Director filters are active\n" ); |
3537 | return -EOPNOTSUPP; |
3538 | } |
3539 | |
3540 | curr_combined = ice_get_combined_cnt(vsi); |
3541 | |
3542 | /* these checks are for cases where user didn't specify a particular |
3543 | * value on cmd line but we get non-zero value anyway via |
3544 | * get_channels(); look at ethtool.c in ethtool repository (the user |
3545 | * space part), particularly, do_schannels() routine |
3546 | */ |
3547 | if (ch->rx_count == vsi->num_rxq - curr_combined) |
3548 | ch->rx_count = 0; |
3549 | if (ch->tx_count == vsi->num_txq - curr_combined) |
3550 | ch->tx_count = 0; |
3551 | if (ch->combined_count == curr_combined) |
3552 | ch->combined_count = 0; |
3553 | |
3554 | if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) { |
3555 | netdev_err(dev, format: "Please specify at least 1 Rx and 1 Tx channel\n" ); |
3556 | return -EINVAL; |
3557 | } |
3558 | |
3559 | new_rx = ch->combined_count + ch->rx_count; |
3560 | new_tx = ch->combined_count + ch->tx_count; |
3561 | |
3562 | if (new_rx < vsi->tc_cfg.numtc) { |
3563 | netdev_err(dev, format: "Cannot set less Rx channels, than Traffic Classes you have (%u)\n" , |
3564 | vsi->tc_cfg.numtc); |
3565 | return -EINVAL; |
3566 | } |
3567 | if (new_tx < vsi->tc_cfg.numtc) { |
3568 | netdev_err(dev, format: "Cannot set less Tx channels, than Traffic Classes you have (%u)\n" , |
3569 | vsi->tc_cfg.numtc); |
3570 | return -EINVAL; |
3571 | } |
3572 | if (new_rx > ice_get_max_rxq(pf)) { |
3573 | netdev_err(dev, format: "Maximum allowed Rx channels is %d\n" , |
3574 | ice_get_max_rxq(pf)); |
3575 | return -EINVAL; |
3576 | } |
3577 | if (new_tx > ice_get_max_txq(pf)) { |
3578 | netdev_err(dev, format: "Maximum allowed Tx channels is %d\n" , |
3579 | ice_get_max_txq(pf)); |
3580 | return -EINVAL; |
3581 | } |
3582 | |
3583 | if (pf->adev) { |
3584 | mutex_lock(&pf->adev_mutex); |
3585 | device_lock(dev: &pf->adev->dev); |
3586 | locked = true; |
3587 | if (pf->adev->dev.driver) { |
3588 | netdev_err(dev, format: "Cannot change channels when RDMA is active\n" ); |
3589 | ret = -EBUSY; |
3590 | goto adev_unlock; |
3591 | } |
3592 | } |
3593 | |
3594 | ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked); |
3595 | |
3596 | if (!netif_is_rxfh_configured(dev)) { |
3597 | ret = ice_vsi_set_dflt_rss_lut(vsi, req_rss_size: new_rx); |
3598 | goto adev_unlock; |
3599 | } |
3600 | |
3601 | /* Update rss_size due to change in Rx queues */ |
3602 | vsi->rss_size = ice_get_valid_rss_size(hw: &pf->hw, new_size: new_rx); |
3603 | |
3604 | adev_unlock: |
3605 | if (locked) { |
3606 | device_unlock(dev: &pf->adev->dev); |
3607 | mutex_unlock(lock: &pf->adev_mutex); |
3608 | } |
3609 | return ret; |
3610 | } |
3611 | |
3612 | /** |
3613 | * ice_get_wol - get current Wake on LAN configuration |
3614 | * @netdev: network interface device structure |
3615 | * @wol: Ethtool structure to retrieve WoL settings |
3616 | */ |
3617 | static void ice_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) |
3618 | { |
3619 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3620 | struct ice_pf *pf = np->vsi->back; |
3621 | |
3622 | if (np->vsi->type != ICE_VSI_PF) |
3623 | netdev_warn(dev: netdev, format: "Wake on LAN is not supported on this interface!\n" ); |
3624 | |
3625 | /* Get WoL settings based on the HW capability */ |
3626 | if (ice_is_wol_supported(hw: &pf->hw)) { |
3627 | wol->supported = WAKE_MAGIC; |
3628 | wol->wolopts = pf->wol_ena ? WAKE_MAGIC : 0; |
3629 | } else { |
3630 | wol->supported = 0; |
3631 | wol->wolopts = 0; |
3632 | } |
3633 | } |
3634 | |
3635 | /** |
3636 | * ice_set_wol - set Wake on LAN on supported device |
3637 | * @netdev: network interface device structure |
3638 | * @wol: Ethtool structure to set WoL |
3639 | */ |
3640 | static int ice_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) |
3641 | { |
3642 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3643 | struct ice_vsi *vsi = np->vsi; |
3644 | struct ice_pf *pf = vsi->back; |
3645 | |
3646 | if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(hw: &pf->hw)) |
3647 | return -EOPNOTSUPP; |
3648 | |
3649 | /* only magic packet is supported */ |
3650 | if (wol->wolopts && wol->wolopts != WAKE_MAGIC) |
3651 | return -EOPNOTSUPP; |
3652 | |
3653 | /* Set WoL only if there is a new value */ |
3654 | if (pf->wol_ena != !!wol->wolopts) { |
3655 | pf->wol_ena = !!wol->wolopts; |
3656 | device_set_wakeup_enable(ice_pf_to_dev(pf), enable: pf->wol_ena); |
3657 | netdev_dbg(netdev, "WoL magic packet %sabled\n" , |
3658 | pf->wol_ena ? "en" : "dis" ); |
3659 | } |
3660 | |
3661 | return 0; |
3662 | } |
3663 | |
3664 | /** |
3665 | * ice_get_rc_coalesce - get ITR values for specific ring container |
3666 | * @ec: ethtool structure to fill with driver's coalesce settings |
3667 | * @rc: ring container that the ITR values will come from |
3668 | * |
3669 | * Query the device for ice_ring_container specific ITR values. This is |
3670 | * done per ice_ring_container because each q_vector can have 1 or more rings |
3671 | * and all of said ring(s) will have the same ITR values. |
3672 | * |
3673 | * Returns 0 on success, negative otherwise. |
3674 | */ |
3675 | static int |
3676 | ice_get_rc_coalesce(struct ethtool_coalesce *ec, struct ice_ring_container *rc) |
3677 | { |
3678 | if (!rc->rx_ring) |
3679 | return -EINVAL; |
3680 | |
3681 | switch (rc->type) { |
3682 | case ICE_RX_CONTAINER: |
3683 | ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc); |
3684 | ec->rx_coalesce_usecs = rc->itr_setting; |
3685 | ec->rx_coalesce_usecs_high = rc->rx_ring->q_vector->intrl; |
3686 | break; |
3687 | case ICE_TX_CONTAINER: |
3688 | ec->use_adaptive_tx_coalesce = ITR_IS_DYNAMIC(rc); |
3689 | ec->tx_coalesce_usecs = rc->itr_setting; |
3690 | break; |
3691 | default: |
3692 | dev_dbg(ice_pf_to_dev(rc->rx_ring->vsi->back), "Invalid c_type %d\n" , rc->type); |
3693 | return -EINVAL; |
3694 | } |
3695 | |
3696 | return 0; |
3697 | } |
3698 | |
3699 | /** |
3700 | * ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings |
3701 | * @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings |
3702 | * @ec: coalesce settings to program the device with |
3703 | * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index |
3704 | * |
3705 | * Return 0 on success, and negative under the following conditions: |
3706 | * 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed. |
3707 | * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. |
3708 | */ |
3709 | static int |
3710 | ice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) |
3711 | { |
3712 | if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { |
3713 | if (ice_get_rc_coalesce(ec, |
3714 | rc: &vsi->rx_rings[q_num]->q_vector->rx)) |
3715 | return -EINVAL; |
3716 | if (ice_get_rc_coalesce(ec, |
3717 | rc: &vsi->tx_rings[q_num]->q_vector->tx)) |
3718 | return -EINVAL; |
3719 | } else if (q_num < vsi->num_rxq) { |
3720 | if (ice_get_rc_coalesce(ec, |
3721 | rc: &vsi->rx_rings[q_num]->q_vector->rx)) |
3722 | return -EINVAL; |
3723 | } else if (q_num < vsi->num_txq) { |
3724 | if (ice_get_rc_coalesce(ec, |
3725 | rc: &vsi->tx_rings[q_num]->q_vector->tx)) |
3726 | return -EINVAL; |
3727 | } else { |
3728 | return -EINVAL; |
3729 | } |
3730 | |
3731 | return 0; |
3732 | } |
3733 | |
3734 | /** |
3735 | * __ice_get_coalesce - get ITR/INTRL values for the device |
3736 | * @netdev: pointer to the netdev associated with this query |
3737 | * @ec: ethtool structure to fill with driver's coalesce settings |
3738 | * @q_num: queue number to get the coalesce settings for |
3739 | * |
3740 | * If the caller passes in a negative q_num then we return coalesce settings |
3741 | * based on queue number 0, else use the actual q_num passed in. |
3742 | */ |
3743 | static int |
3744 | __ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, |
3745 | int q_num) |
3746 | { |
3747 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3748 | struct ice_vsi *vsi = np->vsi; |
3749 | |
3750 | if (q_num < 0) |
3751 | q_num = 0; |
3752 | |
3753 | if (ice_get_q_coalesce(vsi, ec, q_num)) |
3754 | return -EINVAL; |
3755 | |
3756 | return 0; |
3757 | } |
3758 | |
3759 | static int ice_get_coalesce(struct net_device *netdev, |
3760 | struct ethtool_coalesce *ec, |
3761 | struct kernel_ethtool_coalesce *kernel_coal, |
3762 | struct netlink_ext_ack *extack) |
3763 | { |
3764 | return __ice_get_coalesce(netdev, ec, q_num: -1); |
3765 | } |
3766 | |
3767 | static int |
3768 | ice_get_per_q_coalesce(struct net_device *netdev, u32 q_num, |
3769 | struct ethtool_coalesce *ec) |
3770 | { |
3771 | return __ice_get_coalesce(netdev, ec, q_num); |
3772 | } |
3773 | |
3774 | /** |
3775 | * ice_set_rc_coalesce - set ITR values for specific ring container |
3776 | * @ec: ethtool structure from user to update ITR settings |
3777 | * @rc: ring container that the ITR values will come from |
3778 | * @vsi: VSI associated to the ring container |
3779 | * |
3780 | * Set specific ITR values. This is done per ice_ring_container because each |
3781 | * q_vector can have 1 or more rings and all of said ring(s) will have the same |
3782 | * ITR values. |
3783 | * |
3784 | * Returns 0 on success, negative otherwise. |
3785 | */ |
3786 | static int |
3787 | ice_set_rc_coalesce(struct ethtool_coalesce *ec, |
3788 | struct ice_ring_container *rc, struct ice_vsi *vsi) |
3789 | { |
3790 | const char *c_type_str = (rc->type == ICE_RX_CONTAINER) ? "rx" : "tx" ; |
3791 | u32 use_adaptive_coalesce, coalesce_usecs; |
3792 | struct ice_pf *pf = vsi->back; |
3793 | u16 itr_setting; |
3794 | |
3795 | if (!rc->rx_ring) |
3796 | return -EINVAL; |
3797 | |
3798 | switch (rc->type) { |
3799 | case ICE_RX_CONTAINER: |
3800 | { |
3801 | struct ice_q_vector *q_vector = rc->rx_ring->q_vector; |
3802 | |
3803 | if (ec->rx_coalesce_usecs_high > ICE_MAX_INTRL || |
3804 | (ec->rx_coalesce_usecs_high && |
3805 | ec->rx_coalesce_usecs_high < pf->hw.intrl_gran)) { |
3806 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs-high valid values are 0 (disabled), %d-%d\n" , |
3807 | c_type_str, pf->hw.intrl_gran, |
3808 | ICE_MAX_INTRL); |
3809 | return -EINVAL; |
3810 | } |
3811 | if (ec->rx_coalesce_usecs_high != q_vector->intrl && |
3812 | (ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce)) { |
3813 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs-high cannot be changed if adaptive-tx or adaptive-rx is enabled\n" , |
3814 | c_type_str); |
3815 | return -EINVAL; |
3816 | } |
3817 | if (ec->rx_coalesce_usecs_high != q_vector->intrl) |
3818 | q_vector->intrl = ec->rx_coalesce_usecs_high; |
3819 | |
3820 | use_adaptive_coalesce = ec->use_adaptive_rx_coalesce; |
3821 | coalesce_usecs = ec->rx_coalesce_usecs; |
3822 | |
3823 | break; |
3824 | } |
3825 | case ICE_TX_CONTAINER: |
3826 | use_adaptive_coalesce = ec->use_adaptive_tx_coalesce; |
3827 | coalesce_usecs = ec->tx_coalesce_usecs; |
3828 | |
3829 | break; |
3830 | default: |
3831 | dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n" , |
3832 | rc->type); |
3833 | return -EINVAL; |
3834 | } |
3835 | |
3836 | itr_setting = rc->itr_setting; |
3837 | if (coalesce_usecs != itr_setting && use_adaptive_coalesce) { |
3838 | netdev_info(dev: vsi->netdev, format: "%s interrupt throttling cannot be changed if adaptive-%s is enabled\n" , |
3839 | c_type_str, c_type_str); |
3840 | return -EINVAL; |
3841 | } |
3842 | |
3843 | if (coalesce_usecs > ICE_ITR_MAX) { |
3844 | netdev_info(dev: vsi->netdev, format: "Invalid value, %s-usecs range is 0-%d\n" , |
3845 | c_type_str, ICE_ITR_MAX); |
3846 | return -EINVAL; |
3847 | } |
3848 | |
3849 | if (use_adaptive_coalesce) { |
3850 | rc->itr_mode = ITR_DYNAMIC; |
3851 | } else { |
3852 | rc->itr_mode = ITR_STATIC; |
3853 | /* store user facing value how it was set */ |
3854 | rc->itr_setting = coalesce_usecs; |
3855 | /* write the change to the register */ |
3856 | ice_write_itr(rc, itr: coalesce_usecs); |
3857 | /* force writes to take effect immediately, the flush shouldn't |
3858 | * be done in the functions above because the intent is for |
3859 | * them to do lazy writes. |
3860 | */ |
3861 | ice_flush(&pf->hw); |
3862 | } |
3863 | |
3864 | return 0; |
3865 | } |
3866 | |
3867 | /** |
3868 | * ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings |
3869 | * @vsi: VSI associated to the queue that need updating |
3870 | * @ec: coalesce settings to program the device with |
3871 | * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index |
3872 | * |
3873 | * Return 0 on success, and negative under the following conditions: |
3874 | * 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed. |
3875 | * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. |
3876 | */ |
3877 | static int |
3878 | ice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) |
3879 | { |
3880 | if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { |
3881 | if (ice_set_rc_coalesce(ec, |
3882 | rc: &vsi->rx_rings[q_num]->q_vector->rx, |
3883 | vsi)) |
3884 | return -EINVAL; |
3885 | |
3886 | if (ice_set_rc_coalesce(ec, |
3887 | rc: &vsi->tx_rings[q_num]->q_vector->tx, |
3888 | vsi)) |
3889 | return -EINVAL; |
3890 | } else if (q_num < vsi->num_rxq) { |
3891 | if (ice_set_rc_coalesce(ec, |
3892 | rc: &vsi->rx_rings[q_num]->q_vector->rx, |
3893 | vsi)) |
3894 | return -EINVAL; |
3895 | } else if (q_num < vsi->num_txq) { |
3896 | if (ice_set_rc_coalesce(ec, |
3897 | rc: &vsi->tx_rings[q_num]->q_vector->tx, |
3898 | vsi)) |
3899 | return -EINVAL; |
3900 | } else { |
3901 | return -EINVAL; |
3902 | } |
3903 | |
3904 | return 0; |
3905 | } |
3906 | |
3907 | /** |
3908 | * ice_print_if_odd_usecs - print message if user tries to set odd [tx|rx]-usecs |
3909 | * @netdev: netdev used for print |
3910 | * @itr_setting: previous user setting |
3911 | * @use_adaptive_coalesce: if adaptive coalesce is enabled or being enabled |
3912 | * @coalesce_usecs: requested value of [tx|rx]-usecs |
3913 | * @c_type_str: either "rx" or "tx" to match user set field of [tx|rx]-usecs |
3914 | */ |
3915 | static void |
3916 | ice_print_if_odd_usecs(struct net_device *netdev, u16 itr_setting, |
3917 | u32 use_adaptive_coalesce, u32 coalesce_usecs, |
3918 | const char *c_type_str) |
3919 | { |
3920 | if (use_adaptive_coalesce) |
3921 | return; |
3922 | |
3923 | if (itr_setting != coalesce_usecs && (coalesce_usecs % 2)) |
3924 | 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" , |
3925 | c_type_str, coalesce_usecs, c_type_str, |
3926 | ITR_REG_ALIGN(coalesce_usecs)); |
3927 | } |
3928 | |
3929 | /** |
3930 | * __ice_set_coalesce - set ITR/INTRL values for the device |
3931 | * @netdev: pointer to the netdev associated with this query |
3932 | * @ec: ethtool structure to fill with driver's coalesce settings |
3933 | * @q_num: queue number to get the coalesce settings for |
3934 | * |
3935 | * If the caller passes in a negative q_num then we set the coalesce settings |
3936 | * for all Tx/Rx queues, else use the actual q_num passed in. |
3937 | */ |
3938 | static int |
3939 | __ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, |
3940 | int q_num) |
3941 | { |
3942 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
3943 | struct ice_vsi *vsi = np->vsi; |
3944 | |
3945 | if (q_num < 0) { |
3946 | struct ice_q_vector *q_vector = vsi->q_vectors[0]; |
3947 | int v_idx; |
3948 | |
3949 | if (q_vector) { |
3950 | ice_print_if_odd_usecs(netdev, itr_setting: q_vector->rx.itr_setting, |
3951 | use_adaptive_coalesce: ec->use_adaptive_rx_coalesce, |
3952 | coalesce_usecs: ec->rx_coalesce_usecs, c_type_str: "rx" ); |
3953 | |
3954 | ice_print_if_odd_usecs(netdev, itr_setting: q_vector->tx.itr_setting, |
3955 | use_adaptive_coalesce: ec->use_adaptive_tx_coalesce, |
3956 | coalesce_usecs: ec->tx_coalesce_usecs, c_type_str: "tx" ); |
3957 | } |
3958 | |
3959 | ice_for_each_q_vector(vsi, v_idx) { |
3960 | /* In some cases if DCB is configured the num_[rx|tx]q |
3961 | * can be less than vsi->num_q_vectors. This check |
3962 | * accounts for that so we don't report a false failure |
3963 | */ |
3964 | if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq) |
3965 | goto set_complete; |
3966 | |
3967 | if (ice_set_q_coalesce(vsi, ec, q_num: v_idx)) |
3968 | return -EINVAL; |
3969 | |
3970 | ice_set_q_vector_intrl(q_vector: vsi->q_vectors[v_idx]); |
3971 | } |
3972 | goto set_complete; |
3973 | } |
3974 | |
3975 | if (ice_set_q_coalesce(vsi, ec, q_num)) |
3976 | return -EINVAL; |
3977 | |
3978 | ice_set_q_vector_intrl(q_vector: vsi->q_vectors[q_num]); |
3979 | |
3980 | set_complete: |
3981 | return 0; |
3982 | } |
3983 | |
3984 | static int ice_set_coalesce(struct net_device *netdev, |
3985 | struct ethtool_coalesce *ec, |
3986 | struct kernel_ethtool_coalesce *kernel_coal, |
3987 | struct netlink_ext_ack *extack) |
3988 | { |
3989 | return __ice_set_coalesce(netdev, ec, q_num: -1); |
3990 | } |
3991 | |
3992 | static int |
3993 | ice_set_per_q_coalesce(struct net_device *netdev, u32 q_num, |
3994 | struct ethtool_coalesce *ec) |
3995 | { |
3996 | return __ice_set_coalesce(netdev, ec, q_num); |
3997 | } |
3998 | |
3999 | static void |
4000 | ice_repr_get_drvinfo(struct net_device *netdev, |
4001 | struct ethtool_drvinfo *drvinfo) |
4002 | { |
4003 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4004 | |
4005 | if (ice_check_vf_ready_for_cfg(vf: repr->vf)) |
4006 | return; |
4007 | |
4008 | __ice_get_drvinfo(netdev, drvinfo, vsi: repr->src_vsi); |
4009 | } |
4010 | |
4011 | static void |
4012 | ice_repr_get_strings(struct net_device *netdev, u32 stringset, u8 *data) |
4013 | { |
4014 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4015 | |
4016 | /* for port representors only ETH_SS_STATS is supported */ |
4017 | if (ice_check_vf_ready_for_cfg(vf: repr->vf) || |
4018 | stringset != ETH_SS_STATS) |
4019 | return; |
4020 | |
4021 | __ice_get_strings(netdev, stringset, data, vsi: repr->src_vsi); |
4022 | } |
4023 | |
4024 | static void |
4025 | ice_repr_get_ethtool_stats(struct net_device *netdev, |
4026 | struct ethtool_stats __always_unused *stats, |
4027 | u64 *data) |
4028 | { |
4029 | struct ice_repr *repr = ice_netdev_to_repr(netdev); |
4030 | |
4031 | if (ice_check_vf_ready_for_cfg(vf: repr->vf)) |
4032 | return; |
4033 | |
4034 | __ice_get_ethtool_stats(netdev, stats, data, vsi: repr->src_vsi); |
4035 | } |
4036 | |
4037 | static int ice_repr_get_sset_count(struct net_device *netdev, int sset) |
4038 | { |
4039 | switch (sset) { |
4040 | case ETH_SS_STATS: |
4041 | return ICE_VSI_STATS_LEN; |
4042 | default: |
4043 | return -EOPNOTSUPP; |
4044 | } |
4045 | } |
4046 | |
4047 | #define ICE_I2C_EEPROM_DEV_ADDR 0xA0 |
4048 | #define ICE_I2C_EEPROM_DEV_ADDR2 0xA2 |
4049 | #define ICE_MODULE_TYPE_SFP 0x03 |
4050 | #define ICE_MODULE_TYPE_QSFP_PLUS 0x0D |
4051 | #define ICE_MODULE_TYPE_QSFP28 0x11 |
4052 | #define ICE_MODULE_SFF_ADDR_MODE 0x04 |
4053 | #define ICE_MODULE_SFF_DIAG_CAPAB 0x40 |
4054 | #define ICE_MODULE_REVISION_ADDR 0x01 |
4055 | #define ICE_MODULE_SFF_8472_COMP 0x5E |
4056 | #define ICE_MODULE_SFF_8472_SWAP 0x5C |
4057 | #define ICE_MODULE_QSFP_MAX_LEN 640 |
4058 | |
4059 | /** |
4060 | * ice_get_module_info - get SFF module type and revision information |
4061 | * @netdev: network interface device structure |
4062 | * @modinfo: module EEPROM size and layout information structure |
4063 | */ |
4064 | static int |
4065 | ice_get_module_info(struct net_device *netdev, |
4066 | struct ethtool_modinfo *modinfo) |
4067 | { |
4068 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
4069 | struct ice_vsi *vsi = np->vsi; |
4070 | struct ice_pf *pf = vsi->back; |
4071 | struct ice_hw *hw = &pf->hw; |
4072 | u8 sff8472_comp = 0; |
4073 | u8 sff8472_swap = 0; |
4074 | u8 sff8636_rev = 0; |
4075 | u8 value = 0; |
4076 | int status; |
4077 | |
4078 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, mem_addr: 0x00, page: 0x00, |
4079 | set_page: 0, data: &value, length: 1, write: 0, NULL); |
4080 | if (status) |
4081 | return status; |
4082 | |
4083 | switch (value) { |
4084 | case ICE_MODULE_TYPE_SFP: |
4085 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4086 | ICE_MODULE_SFF_8472_COMP, page: 0x00, set_page: 0, |
4087 | data: &sff8472_comp, length: 1, write: 0, NULL); |
4088 | if (status) |
4089 | return status; |
4090 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4091 | ICE_MODULE_SFF_8472_SWAP, page: 0x00, set_page: 0, |
4092 | data: &sff8472_swap, length: 1, write: 0, NULL); |
4093 | if (status) |
4094 | return status; |
4095 | |
4096 | if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) { |
4097 | modinfo->type = ETH_MODULE_SFF_8079; |
4098 | modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; |
4099 | } else if (sff8472_comp && |
4100 | (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) { |
4101 | modinfo->type = ETH_MODULE_SFF_8472; |
4102 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; |
4103 | } else { |
4104 | modinfo->type = ETH_MODULE_SFF_8079; |
4105 | modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; |
4106 | } |
4107 | break; |
4108 | case ICE_MODULE_TYPE_QSFP_PLUS: |
4109 | case ICE_MODULE_TYPE_QSFP28: |
4110 | status = ice_aq_sff_eeprom(hw, lport: 0, ICE_I2C_EEPROM_DEV_ADDR, |
4111 | ICE_MODULE_REVISION_ADDR, page: 0x00, set_page: 0, |
4112 | data: &sff8636_rev, length: 1, write: 0, NULL); |
4113 | if (status) |
4114 | return status; |
4115 | /* Check revision compliance */ |
4116 | if (sff8636_rev > 0x02) { |
4117 | /* Module is SFF-8636 compliant */ |
4118 | modinfo->type = ETH_MODULE_SFF_8636; |
4119 | modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; |
4120 | } else { |
4121 | modinfo->type = ETH_MODULE_SFF_8436; |
4122 | modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; |
4123 | } |
4124 | break; |
4125 | default: |
4126 | netdev_warn(dev: netdev, format: "SFF Module Type not recognized.\n" ); |
4127 | return -EINVAL; |
4128 | } |
4129 | return 0; |
4130 | } |
4131 | |
4132 | /** |
4133 | * ice_get_module_eeprom - fill buffer with SFF EEPROM contents |
4134 | * @netdev: network interface device structure |
4135 | * @ee: EEPROM dump request structure |
4136 | * @data: buffer to be filled with EEPROM contents |
4137 | */ |
4138 | static int |
4139 | ice_get_module_eeprom(struct net_device *netdev, |
4140 | struct ethtool_eeprom *ee, u8 *data) |
4141 | { |
4142 | struct ice_netdev_priv *np = netdev_priv(dev: netdev); |
4143 | #define SFF_READ_BLOCK_SIZE 8 |
4144 | u8 value[SFF_READ_BLOCK_SIZE] = { 0 }; |
4145 | u8 addr = ICE_I2C_EEPROM_DEV_ADDR; |
4146 | struct ice_vsi *vsi = np->vsi; |
4147 | struct ice_pf *pf = vsi->back; |
4148 | struct ice_hw *hw = &pf->hw; |
4149 | bool is_sfp = false; |
4150 | unsigned int i, j; |
4151 | u16 offset = 0; |
4152 | u8 page = 0; |
4153 | int status; |
4154 | |
4155 | if (!ee || !ee->len || !data) |
4156 | return -EINVAL; |
4157 | |
4158 | status = ice_aq_sff_eeprom(hw, lport: 0, bus_addr: addr, mem_addr: offset, page, set_page: 0, data: value, length: 1, write: 0, |
4159 | NULL); |
4160 | if (status) |
4161 | return status; |
4162 | |
4163 | if (value[0] == ICE_MODULE_TYPE_SFP) |
4164 | is_sfp = true; |
4165 | |
4166 | memset(data, 0, ee->len); |
4167 | for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) { |
4168 | offset = i + ee->offset; |
4169 | page = 0; |
4170 | |
4171 | /* Check if we need to access the other memory page */ |
4172 | if (is_sfp) { |
4173 | if (offset >= ETH_MODULE_SFF_8079_LEN) { |
4174 | offset -= ETH_MODULE_SFF_8079_LEN; |
4175 | addr = ICE_I2C_EEPROM_DEV_ADDR2; |
4176 | } |
4177 | } else { |
4178 | while (offset >= ETH_MODULE_SFF_8436_LEN) { |
4179 | /* Compute memory page number and offset. */ |
4180 | offset -= ETH_MODULE_SFF_8436_LEN / 2; |
4181 | page++; |
4182 | } |
4183 | } |
4184 | |
4185 | /* Bit 2 of EEPROM address 0x02 declares upper |
4186 | * pages are disabled on QSFP modules. |
4187 | * SFP modules only ever use page 0. |
4188 | */ |
4189 | if (page == 0 || !(data[0x2] & 0x4)) { |
4190 | u32 copy_len; |
4191 | |
4192 | /* If i2c bus is busy due to slow page change or |
4193 | * link management access, call can fail. This is normal. |
4194 | * So we retry this a few times. |
4195 | */ |
4196 | for (j = 0; j < 4; j++) { |
4197 | status = ice_aq_sff_eeprom(hw, lport: 0, bus_addr: addr, mem_addr: offset, page, |
4198 | set_page: !is_sfp, data: value, |
4199 | SFF_READ_BLOCK_SIZE, |
4200 | write: 0, NULL); |
4201 | netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n" , |
4202 | addr, offset, page, is_sfp, |
4203 | value[0], value[1], value[2], value[3], |
4204 | value[4], value[5], value[6], value[7], |
4205 | status); |
4206 | if (status) { |
4207 | usleep_range(min: 1500, max: 2500); |
4208 | memset(value, 0, SFF_READ_BLOCK_SIZE); |
4209 | continue; |
4210 | } |
4211 | break; |
4212 | } |
4213 | |
4214 | /* Make sure we have enough room for the new block */ |
4215 | copy_len = min_t(u32, SFF_READ_BLOCK_SIZE, ee->len - i); |
4216 | memcpy(data + i, value, copy_len); |
4217 | } |
4218 | } |
4219 | return 0; |
4220 | } |
4221 | |
4222 | static const struct ethtool_ops ice_ethtool_ops = { |
4223 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
4224 | ETHTOOL_COALESCE_USE_ADAPTIVE | |
4225 | ETHTOOL_COALESCE_RX_USECS_HIGH, |
4226 | .get_link_ksettings = ice_get_link_ksettings, |
4227 | .set_link_ksettings = ice_set_link_ksettings, |
4228 | .get_drvinfo = ice_get_drvinfo, |
4229 | .get_regs_len = ice_get_regs_len, |
4230 | .get_regs = ice_get_regs, |
4231 | .get_wol = ice_get_wol, |
4232 | .set_wol = ice_set_wol, |
4233 | .get_msglevel = ice_get_msglevel, |
4234 | .set_msglevel = ice_set_msglevel, |
4235 | .self_test = ice_self_test, |
4236 | .get_link = ethtool_op_get_link, |
4237 | .get_eeprom_len = ice_get_eeprom_len, |
4238 | .get_eeprom = ice_get_eeprom, |
4239 | .get_coalesce = ice_get_coalesce, |
4240 | .set_coalesce = ice_set_coalesce, |
4241 | .get_strings = ice_get_strings, |
4242 | .set_phys_id = ice_set_phys_id, |
4243 | .get_ethtool_stats = ice_get_ethtool_stats, |
4244 | .get_priv_flags = ice_get_priv_flags, |
4245 | .set_priv_flags = ice_set_priv_flags, |
4246 | .get_sset_count = ice_get_sset_count, |
4247 | .get_rxnfc = ice_get_rxnfc, |
4248 | .set_rxnfc = ice_set_rxnfc, |
4249 | .get_ringparam = ice_get_ringparam, |
4250 | .set_ringparam = ice_set_ringparam, |
4251 | .nway_reset = ice_nway_reset, |
4252 | .get_pauseparam = ice_get_pauseparam, |
4253 | .set_pauseparam = ice_set_pauseparam, |
4254 | .get_rxfh_key_size = ice_get_rxfh_key_size, |
4255 | .get_rxfh_indir_size = ice_get_rxfh_indir_size, |
4256 | .get_rxfh_context = ice_get_rxfh_context, |
4257 | .get_rxfh = ice_get_rxfh, |
4258 | .set_rxfh = ice_set_rxfh, |
4259 | .get_channels = ice_get_channels, |
4260 | .set_channels = ice_set_channels, |
4261 | .get_ts_info = ice_get_ts_info, |
4262 | .get_per_queue_coalesce = ice_get_per_q_coalesce, |
4263 | .set_per_queue_coalesce = ice_set_per_q_coalesce, |
4264 | .get_fecparam = ice_get_fecparam, |
4265 | .set_fecparam = ice_set_fecparam, |
4266 | .get_module_info = ice_get_module_info, |
4267 | .get_module_eeprom = ice_get_module_eeprom, |
4268 | }; |
4269 | |
4270 | static const struct ethtool_ops ice_ethtool_safe_mode_ops = { |
4271 | .get_link_ksettings = ice_get_link_ksettings, |
4272 | .set_link_ksettings = ice_set_link_ksettings, |
4273 | .get_drvinfo = ice_get_drvinfo, |
4274 | .get_regs_len = ice_get_regs_len, |
4275 | .get_regs = ice_get_regs, |
4276 | .get_wol = ice_get_wol, |
4277 | .set_wol = ice_set_wol, |
4278 | .get_msglevel = ice_get_msglevel, |
4279 | .set_msglevel = ice_set_msglevel, |
4280 | .get_link = ethtool_op_get_link, |
4281 | .get_eeprom_len = ice_get_eeprom_len, |
4282 | .get_eeprom = ice_get_eeprom, |
4283 | .get_strings = ice_get_strings, |
4284 | .get_ethtool_stats = ice_get_ethtool_stats, |
4285 | .get_sset_count = ice_get_sset_count, |
4286 | .get_ringparam = ice_get_ringparam, |
4287 | .set_ringparam = ice_set_ringparam, |
4288 | .nway_reset = ice_nway_reset, |
4289 | .get_channels = ice_get_channels, |
4290 | }; |
4291 | |
4292 | /** |
4293 | * ice_set_ethtool_safe_mode_ops - setup safe mode ethtool ops |
4294 | * @netdev: network interface device structure |
4295 | */ |
4296 | void ice_set_ethtool_safe_mode_ops(struct net_device *netdev) |
4297 | { |
4298 | netdev->ethtool_ops = &ice_ethtool_safe_mode_ops; |
4299 | } |
4300 | |
4301 | static const struct ethtool_ops ice_ethtool_repr_ops = { |
4302 | .get_drvinfo = ice_repr_get_drvinfo, |
4303 | .get_link = ethtool_op_get_link, |
4304 | .get_strings = ice_repr_get_strings, |
4305 | .get_ethtool_stats = ice_repr_get_ethtool_stats, |
4306 | .get_sset_count = ice_repr_get_sset_count, |
4307 | }; |
4308 | |
4309 | /** |
4310 | * ice_set_ethtool_repr_ops - setup VF's port representor ethtool ops |
4311 | * @netdev: network interface device structure |
4312 | */ |
4313 | void ice_set_ethtool_repr_ops(struct net_device *netdev) |
4314 | { |
4315 | netdev->ethtool_ops = &ice_ethtool_repr_ops; |
4316 | } |
4317 | |
4318 | /** |
4319 | * ice_set_ethtool_ops - setup netdev ethtool ops |
4320 | * @netdev: network interface device structure |
4321 | * |
4322 | * setup netdev ethtool ops with ice specific ops |
4323 | */ |
4324 | void ice_set_ethtool_ops(struct net_device *netdev) |
4325 | { |
4326 | netdev->ethtool_ops = &ice_ethtool_ops; |
4327 | } |
4328 | |