1 | /* Broadcom NetXtreme-C/E network driver. |
2 | * |
3 | * Copyright (c) 2014-2016 Broadcom Corporation |
4 | * Copyright (c) 2016-2017 Broadcom Limited |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation. |
9 | */ |
10 | |
11 | #include <linux/bitops.h> |
12 | #include <linux/ctype.h> |
13 | #include <linux/stringify.h> |
14 | #include <linux/ethtool.h> |
15 | #include <linux/ethtool_netlink.h> |
16 | #include <linux/linkmode.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/pci.h> |
19 | #include <linux/etherdevice.h> |
20 | #include <linux/crc32.h> |
21 | #include <linux/firmware.h> |
22 | #include <linux/utsname.h> |
23 | #include <linux/time.h> |
24 | #include <linux/ptp_clock_kernel.h> |
25 | #include <linux/net_tstamp.h> |
26 | #include <linux/timecounter.h> |
27 | #include <net/netlink.h> |
28 | #include "bnxt_hsi.h" |
29 | #include "bnxt.h" |
30 | #include "bnxt_hwrm.h" |
31 | #include "bnxt_ulp.h" |
32 | #include "bnxt_xdp.h" |
33 | #include "bnxt_ptp.h" |
34 | #include "bnxt_ethtool.h" |
35 | #include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ |
36 | #include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ |
37 | #include "bnxt_coredump.h" |
38 | |
39 | #define BNXT_NVM_ERR_MSG(dev, extack, msg) \ |
40 | do { \ |
41 | if (extack) \ |
42 | NL_SET_ERR_MSG_MOD(extack, msg); \ |
43 | netdev_err(dev, "%s\n", msg); \ |
44 | } while (0) |
45 | |
46 | static u32 bnxt_get_msglevel(struct net_device *dev) |
47 | { |
48 | struct bnxt *bp = netdev_priv(dev); |
49 | |
50 | return bp->msg_enable; |
51 | } |
52 | |
53 | static void bnxt_set_msglevel(struct net_device *dev, u32 value) |
54 | { |
55 | struct bnxt *bp = netdev_priv(dev); |
56 | |
57 | bp->msg_enable = value; |
58 | } |
59 | |
60 | static int bnxt_get_coalesce(struct net_device *dev, |
61 | struct ethtool_coalesce *coal, |
62 | struct kernel_ethtool_coalesce *kernel_coal, |
63 | struct netlink_ext_ack *extack) |
64 | { |
65 | struct bnxt *bp = netdev_priv(dev); |
66 | struct bnxt_coal *hw_coal; |
67 | u16 mult; |
68 | |
69 | memset(coal, 0, sizeof(*coal)); |
70 | |
71 | coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM; |
72 | |
73 | hw_coal = &bp->rx_coal; |
74 | mult = hw_coal->bufs_per_record; |
75 | coal->rx_coalesce_usecs = hw_coal->coal_ticks; |
76 | coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; |
77 | coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; |
78 | coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; |
79 | if (hw_coal->flags & |
80 | RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) |
81 | kernel_coal->use_cqe_mode_rx = true; |
82 | |
83 | hw_coal = &bp->tx_coal; |
84 | mult = hw_coal->bufs_per_record; |
85 | coal->tx_coalesce_usecs = hw_coal->coal_ticks; |
86 | coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; |
87 | coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; |
88 | coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; |
89 | if (hw_coal->flags & |
90 | RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) |
91 | kernel_coal->use_cqe_mode_tx = true; |
92 | |
93 | coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int bnxt_set_coalesce(struct net_device *dev, |
99 | struct ethtool_coalesce *coal, |
100 | struct kernel_ethtool_coalesce *kernel_coal, |
101 | struct netlink_ext_ack *extack) |
102 | { |
103 | struct bnxt *bp = netdev_priv(dev); |
104 | bool update_stats = false; |
105 | struct bnxt_coal *hw_coal; |
106 | int rc = 0; |
107 | u16 mult; |
108 | |
109 | if (coal->use_adaptive_rx_coalesce) { |
110 | bp->flags |= BNXT_FLAG_DIM; |
111 | } else { |
112 | if (bp->flags & BNXT_FLAG_DIM) { |
113 | bp->flags &= ~(BNXT_FLAG_DIM); |
114 | goto reset_coalesce; |
115 | } |
116 | } |
117 | |
118 | if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && |
119 | !(bp->coal_cap.cmpl_params & |
120 | RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) |
121 | return -EOPNOTSUPP; |
122 | |
123 | hw_coal = &bp->rx_coal; |
124 | mult = hw_coal->bufs_per_record; |
125 | hw_coal->coal_ticks = coal->rx_coalesce_usecs; |
126 | hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; |
127 | hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; |
128 | hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; |
129 | hw_coal->flags &= |
130 | ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; |
131 | if (kernel_coal->use_cqe_mode_rx) |
132 | hw_coal->flags |= |
133 | RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; |
134 | |
135 | hw_coal = &bp->tx_coal; |
136 | mult = hw_coal->bufs_per_record; |
137 | hw_coal->coal_ticks = coal->tx_coalesce_usecs; |
138 | hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; |
139 | hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; |
140 | hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; |
141 | hw_coal->flags &= |
142 | ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; |
143 | if (kernel_coal->use_cqe_mode_tx) |
144 | hw_coal->flags |= |
145 | RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; |
146 | |
147 | if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { |
148 | u32 stats_ticks = coal->stats_block_coalesce_usecs; |
149 | |
150 | /* Allow 0, which means disable. */ |
151 | if (stats_ticks) |
152 | stats_ticks = clamp_t(u32, stats_ticks, |
153 | BNXT_MIN_STATS_COAL_TICKS, |
154 | BNXT_MAX_STATS_COAL_TICKS); |
155 | stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS); |
156 | bp->stats_coal_ticks = stats_ticks; |
157 | if (bp->stats_coal_ticks) |
158 | bp->current_interval = |
159 | bp->stats_coal_ticks * HZ / 1000000; |
160 | else |
161 | bp->current_interval = BNXT_TIMER_INTERVAL; |
162 | update_stats = true; |
163 | } |
164 | |
165 | reset_coalesce: |
166 | if (test_bit(BNXT_STATE_OPEN, &bp->state)) { |
167 | if (update_stats) { |
168 | bnxt_close_nic(bp, true, false); |
169 | rc = bnxt_open_nic(bp, true, false); |
170 | } else { |
171 | rc = bnxt_hwrm_set_coal(bp); |
172 | } |
173 | } |
174 | |
175 | return rc; |
176 | } |
177 | |
178 | static const char * const bnxt_ring_rx_stats_str[] = { |
179 | "rx_ucast_packets" , |
180 | "rx_mcast_packets" , |
181 | "rx_bcast_packets" , |
182 | "rx_discards" , |
183 | "rx_errors" , |
184 | "rx_ucast_bytes" , |
185 | "rx_mcast_bytes" , |
186 | "rx_bcast_bytes" , |
187 | }; |
188 | |
189 | static const char * const bnxt_ring_tx_stats_str[] = { |
190 | "tx_ucast_packets" , |
191 | "tx_mcast_packets" , |
192 | "tx_bcast_packets" , |
193 | "tx_errors" , |
194 | "tx_discards" , |
195 | "tx_ucast_bytes" , |
196 | "tx_mcast_bytes" , |
197 | "tx_bcast_bytes" , |
198 | }; |
199 | |
200 | static const char * const bnxt_ring_tpa_stats_str[] = { |
201 | "tpa_packets" , |
202 | "tpa_bytes" , |
203 | "tpa_events" , |
204 | "tpa_aborts" , |
205 | }; |
206 | |
207 | static const char * const bnxt_ring_tpa2_stats_str[] = { |
208 | "rx_tpa_eligible_pkt" , |
209 | "rx_tpa_eligible_bytes" , |
210 | "rx_tpa_pkt" , |
211 | "rx_tpa_bytes" , |
212 | "rx_tpa_errors" , |
213 | "rx_tpa_events" , |
214 | }; |
215 | |
216 | static const char * const bnxt_rx_sw_stats_str[] = { |
217 | "rx_l4_csum_errors" , |
218 | "rx_resets" , |
219 | "rx_buf_errors" , |
220 | }; |
221 | |
222 | static const char * const bnxt_cmn_sw_stats_str[] = { |
223 | "missed_irqs" , |
224 | }; |
225 | |
226 | #define BNXT_RX_STATS_ENTRY(counter) \ |
227 | { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) } |
228 | |
229 | #define BNXT_TX_STATS_ENTRY(counter) \ |
230 | { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) } |
231 | |
232 | #define BNXT_RX_STATS_EXT_ENTRY(counter) \ |
233 | { BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) } |
234 | |
235 | #define BNXT_TX_STATS_EXT_ENTRY(counter) \ |
236 | { BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) } |
237 | |
238 | #define BNXT_RX_STATS_EXT_PFC_ENTRY(n) \ |
239 | BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us), \ |
240 | BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions) |
241 | |
242 | #define BNXT_TX_STATS_EXT_PFC_ENTRY(n) \ |
243 | BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us), \ |
244 | BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions) |
245 | |
246 | #define BNXT_RX_STATS_EXT_PFC_ENTRIES \ |
247 | BNXT_RX_STATS_EXT_PFC_ENTRY(0), \ |
248 | BNXT_RX_STATS_EXT_PFC_ENTRY(1), \ |
249 | BNXT_RX_STATS_EXT_PFC_ENTRY(2), \ |
250 | BNXT_RX_STATS_EXT_PFC_ENTRY(3), \ |
251 | BNXT_RX_STATS_EXT_PFC_ENTRY(4), \ |
252 | BNXT_RX_STATS_EXT_PFC_ENTRY(5), \ |
253 | BNXT_RX_STATS_EXT_PFC_ENTRY(6), \ |
254 | BNXT_RX_STATS_EXT_PFC_ENTRY(7) |
255 | |
256 | #define BNXT_TX_STATS_EXT_PFC_ENTRIES \ |
257 | BNXT_TX_STATS_EXT_PFC_ENTRY(0), \ |
258 | BNXT_TX_STATS_EXT_PFC_ENTRY(1), \ |
259 | BNXT_TX_STATS_EXT_PFC_ENTRY(2), \ |
260 | BNXT_TX_STATS_EXT_PFC_ENTRY(3), \ |
261 | BNXT_TX_STATS_EXT_PFC_ENTRY(4), \ |
262 | BNXT_TX_STATS_EXT_PFC_ENTRY(5), \ |
263 | BNXT_TX_STATS_EXT_PFC_ENTRY(6), \ |
264 | BNXT_TX_STATS_EXT_PFC_ENTRY(7) |
265 | |
266 | #define BNXT_RX_STATS_EXT_COS_ENTRY(n) \ |
267 | BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n), \ |
268 | BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n) |
269 | |
270 | #define BNXT_TX_STATS_EXT_COS_ENTRY(n) \ |
271 | BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n), \ |
272 | BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n) |
273 | |
274 | #define BNXT_RX_STATS_EXT_COS_ENTRIES \ |
275 | BNXT_RX_STATS_EXT_COS_ENTRY(0), \ |
276 | BNXT_RX_STATS_EXT_COS_ENTRY(1), \ |
277 | BNXT_RX_STATS_EXT_COS_ENTRY(2), \ |
278 | BNXT_RX_STATS_EXT_COS_ENTRY(3), \ |
279 | BNXT_RX_STATS_EXT_COS_ENTRY(4), \ |
280 | BNXT_RX_STATS_EXT_COS_ENTRY(5), \ |
281 | BNXT_RX_STATS_EXT_COS_ENTRY(6), \ |
282 | BNXT_RX_STATS_EXT_COS_ENTRY(7) \ |
283 | |
284 | #define BNXT_TX_STATS_EXT_COS_ENTRIES \ |
285 | BNXT_TX_STATS_EXT_COS_ENTRY(0), \ |
286 | BNXT_TX_STATS_EXT_COS_ENTRY(1), \ |
287 | BNXT_TX_STATS_EXT_COS_ENTRY(2), \ |
288 | BNXT_TX_STATS_EXT_COS_ENTRY(3), \ |
289 | BNXT_TX_STATS_EXT_COS_ENTRY(4), \ |
290 | BNXT_TX_STATS_EXT_COS_ENTRY(5), \ |
291 | BNXT_TX_STATS_EXT_COS_ENTRY(6), \ |
292 | BNXT_TX_STATS_EXT_COS_ENTRY(7) \ |
293 | |
294 | #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n) \ |
295 | BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n), \ |
296 | BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n) |
297 | |
298 | #define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES \ |
299 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0), \ |
300 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1), \ |
301 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2), \ |
302 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3), \ |
303 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4), \ |
304 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5), \ |
305 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6), \ |
306 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7) |
307 | |
308 | #define BNXT_RX_STATS_PRI_ENTRY(counter, n) \ |
309 | { BNXT_RX_STATS_EXT_OFFSET(counter##_cos0), \ |
310 | __stringify(counter##_pri##n) } |
311 | |
312 | #define BNXT_TX_STATS_PRI_ENTRY(counter, n) \ |
313 | { BNXT_TX_STATS_EXT_OFFSET(counter##_cos0), \ |
314 | __stringify(counter##_pri##n) } |
315 | |
316 | #define BNXT_RX_STATS_PRI_ENTRIES(counter) \ |
317 | BNXT_RX_STATS_PRI_ENTRY(counter, 0), \ |
318 | BNXT_RX_STATS_PRI_ENTRY(counter, 1), \ |
319 | BNXT_RX_STATS_PRI_ENTRY(counter, 2), \ |
320 | BNXT_RX_STATS_PRI_ENTRY(counter, 3), \ |
321 | BNXT_RX_STATS_PRI_ENTRY(counter, 4), \ |
322 | BNXT_RX_STATS_PRI_ENTRY(counter, 5), \ |
323 | BNXT_RX_STATS_PRI_ENTRY(counter, 6), \ |
324 | BNXT_RX_STATS_PRI_ENTRY(counter, 7) |
325 | |
326 | #define BNXT_TX_STATS_PRI_ENTRIES(counter) \ |
327 | BNXT_TX_STATS_PRI_ENTRY(counter, 0), \ |
328 | BNXT_TX_STATS_PRI_ENTRY(counter, 1), \ |
329 | BNXT_TX_STATS_PRI_ENTRY(counter, 2), \ |
330 | BNXT_TX_STATS_PRI_ENTRY(counter, 3), \ |
331 | BNXT_TX_STATS_PRI_ENTRY(counter, 4), \ |
332 | BNXT_TX_STATS_PRI_ENTRY(counter, 5), \ |
333 | BNXT_TX_STATS_PRI_ENTRY(counter, 6), \ |
334 | BNXT_TX_STATS_PRI_ENTRY(counter, 7) |
335 | |
336 | enum { |
337 | RX_TOTAL_DISCARDS, |
338 | TX_TOTAL_DISCARDS, |
339 | RX_NETPOLL_DISCARDS, |
340 | }; |
341 | |
342 | static const char *const bnxt_ring_err_stats_arr[] = { |
343 | "rx_total_l4_csum_errors" , |
344 | "rx_total_resets" , |
345 | "rx_total_buf_errors" , |
346 | "rx_total_oom_discards" , |
347 | "rx_total_netpoll_discards" , |
348 | "rx_total_ring_discards" , |
349 | "tx_total_resets" , |
350 | "tx_total_ring_discards" , |
351 | "total_missed_irqs" , |
352 | }; |
353 | |
354 | #define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str) |
355 | #define NUM_RING_CMN_SW_STATS ARRAY_SIZE(bnxt_cmn_sw_stats_str) |
356 | #define NUM_RING_RX_HW_STATS ARRAY_SIZE(bnxt_ring_rx_stats_str) |
357 | #define NUM_RING_TX_HW_STATS ARRAY_SIZE(bnxt_ring_tx_stats_str) |
358 | |
359 | static const struct { |
360 | long offset; |
361 | char string[ETH_GSTRING_LEN]; |
362 | } bnxt_port_stats_arr[] = { |
363 | BNXT_RX_STATS_ENTRY(rx_64b_frames), |
364 | BNXT_RX_STATS_ENTRY(rx_65b_127b_frames), |
365 | BNXT_RX_STATS_ENTRY(rx_128b_255b_frames), |
366 | BNXT_RX_STATS_ENTRY(rx_256b_511b_frames), |
367 | BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames), |
368 | BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames), |
369 | BNXT_RX_STATS_ENTRY(rx_good_vlan_frames), |
370 | BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames), |
371 | BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames), |
372 | BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames), |
373 | BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames), |
374 | BNXT_RX_STATS_ENTRY(rx_total_frames), |
375 | BNXT_RX_STATS_ENTRY(rx_ucast_frames), |
376 | BNXT_RX_STATS_ENTRY(rx_mcast_frames), |
377 | BNXT_RX_STATS_ENTRY(rx_bcast_frames), |
378 | BNXT_RX_STATS_ENTRY(rx_fcs_err_frames), |
379 | BNXT_RX_STATS_ENTRY(rx_ctrl_frames), |
380 | BNXT_RX_STATS_ENTRY(rx_pause_frames), |
381 | BNXT_RX_STATS_ENTRY(rx_pfc_frames), |
382 | BNXT_RX_STATS_ENTRY(rx_align_err_frames), |
383 | BNXT_RX_STATS_ENTRY(rx_ovrsz_frames), |
384 | BNXT_RX_STATS_ENTRY(rx_jbr_frames), |
385 | BNXT_RX_STATS_ENTRY(rx_mtu_err_frames), |
386 | BNXT_RX_STATS_ENTRY(rx_tagged_frames), |
387 | BNXT_RX_STATS_ENTRY(rx_double_tagged_frames), |
388 | BNXT_RX_STATS_ENTRY(rx_good_frames), |
389 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0), |
390 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1), |
391 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2), |
392 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3), |
393 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4), |
394 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5), |
395 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6), |
396 | BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7), |
397 | BNXT_RX_STATS_ENTRY(rx_undrsz_frames), |
398 | BNXT_RX_STATS_ENTRY(rx_eee_lpi_events), |
399 | BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration), |
400 | BNXT_RX_STATS_ENTRY(rx_bytes), |
401 | BNXT_RX_STATS_ENTRY(rx_runt_bytes), |
402 | BNXT_RX_STATS_ENTRY(rx_runt_frames), |
403 | BNXT_RX_STATS_ENTRY(rx_stat_discard), |
404 | BNXT_RX_STATS_ENTRY(rx_stat_err), |
405 | |
406 | BNXT_TX_STATS_ENTRY(tx_64b_frames), |
407 | BNXT_TX_STATS_ENTRY(tx_65b_127b_frames), |
408 | BNXT_TX_STATS_ENTRY(tx_128b_255b_frames), |
409 | BNXT_TX_STATS_ENTRY(tx_256b_511b_frames), |
410 | BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames), |
411 | BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames), |
412 | BNXT_TX_STATS_ENTRY(tx_good_vlan_frames), |
413 | BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames), |
414 | BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames), |
415 | BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames), |
416 | BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames), |
417 | BNXT_TX_STATS_ENTRY(tx_good_frames), |
418 | BNXT_TX_STATS_ENTRY(tx_total_frames), |
419 | BNXT_TX_STATS_ENTRY(tx_ucast_frames), |
420 | BNXT_TX_STATS_ENTRY(tx_mcast_frames), |
421 | BNXT_TX_STATS_ENTRY(tx_bcast_frames), |
422 | BNXT_TX_STATS_ENTRY(tx_pause_frames), |
423 | BNXT_TX_STATS_ENTRY(tx_pfc_frames), |
424 | BNXT_TX_STATS_ENTRY(tx_jabber_frames), |
425 | BNXT_TX_STATS_ENTRY(tx_fcs_err_frames), |
426 | BNXT_TX_STATS_ENTRY(tx_err), |
427 | BNXT_TX_STATS_ENTRY(tx_fifo_underruns), |
428 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0), |
429 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1), |
430 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2), |
431 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3), |
432 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4), |
433 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5), |
434 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6), |
435 | BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7), |
436 | BNXT_TX_STATS_ENTRY(tx_eee_lpi_events), |
437 | BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration), |
438 | BNXT_TX_STATS_ENTRY(tx_total_collisions), |
439 | BNXT_TX_STATS_ENTRY(tx_bytes), |
440 | BNXT_TX_STATS_ENTRY(tx_xthol_frames), |
441 | BNXT_TX_STATS_ENTRY(tx_stat_discard), |
442 | BNXT_TX_STATS_ENTRY(tx_stat_error), |
443 | }; |
444 | |
445 | static const struct { |
446 | long offset; |
447 | char string[ETH_GSTRING_LEN]; |
448 | } bnxt_port_stats_ext_arr[] = { |
449 | BNXT_RX_STATS_EXT_ENTRY(link_down_events), |
450 | BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events), |
451 | BNXT_RX_STATS_EXT_ENTRY(resume_pause_events), |
452 | BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events), |
453 | BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events), |
454 | BNXT_RX_STATS_EXT_COS_ENTRIES, |
455 | BNXT_RX_STATS_EXT_PFC_ENTRIES, |
456 | BNXT_RX_STATS_EXT_ENTRY(rx_bits), |
457 | BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold), |
458 | BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err), |
459 | BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits), |
460 | BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES, |
461 | BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks), |
462 | BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks), |
463 | BNXT_RX_STATS_EXT_ENTRY(rx_filter_miss), |
464 | }; |
465 | |
466 | static const struct { |
467 | long offset; |
468 | char string[ETH_GSTRING_LEN]; |
469 | } bnxt_tx_port_stats_ext_arr[] = { |
470 | BNXT_TX_STATS_EXT_COS_ENTRIES, |
471 | BNXT_TX_STATS_EXT_PFC_ENTRIES, |
472 | }; |
473 | |
474 | static const struct { |
475 | long base_off; |
476 | char string[ETH_GSTRING_LEN]; |
477 | } bnxt_rx_bytes_pri_arr[] = { |
478 | BNXT_RX_STATS_PRI_ENTRIES(rx_bytes), |
479 | }; |
480 | |
481 | static const struct { |
482 | long base_off; |
483 | char string[ETH_GSTRING_LEN]; |
484 | } bnxt_rx_pkts_pri_arr[] = { |
485 | BNXT_RX_STATS_PRI_ENTRIES(rx_packets), |
486 | }; |
487 | |
488 | static const struct { |
489 | long base_off; |
490 | char string[ETH_GSTRING_LEN]; |
491 | } bnxt_tx_bytes_pri_arr[] = { |
492 | BNXT_TX_STATS_PRI_ENTRIES(tx_bytes), |
493 | }; |
494 | |
495 | static const struct { |
496 | long base_off; |
497 | char string[ETH_GSTRING_LEN]; |
498 | } bnxt_tx_pkts_pri_arr[] = { |
499 | BNXT_TX_STATS_PRI_ENTRIES(tx_packets), |
500 | }; |
501 | |
502 | #define BNXT_NUM_RING_ERR_STATS ARRAY_SIZE(bnxt_ring_err_stats_arr) |
503 | #define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr) |
504 | #define BNXT_NUM_STATS_PRI \ |
505 | (ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \ |
506 | ARRAY_SIZE(bnxt_rx_pkts_pri_arr) + \ |
507 | ARRAY_SIZE(bnxt_tx_bytes_pri_arr) + \ |
508 | ARRAY_SIZE(bnxt_tx_pkts_pri_arr)) |
509 | |
510 | static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp) |
511 | { |
512 | if (BNXT_SUPPORTS_TPA(bp)) { |
513 | if (bp->max_tpa_v2) { |
514 | if (BNXT_CHIP_P5(bp)) |
515 | return BNXT_NUM_TPA_RING_STATS_P5; |
516 | return BNXT_NUM_TPA_RING_STATS_P7; |
517 | } |
518 | return BNXT_NUM_TPA_RING_STATS; |
519 | } |
520 | return 0; |
521 | } |
522 | |
523 | static int bnxt_get_num_ring_stats(struct bnxt *bp) |
524 | { |
525 | int rx, tx, cmn; |
526 | |
527 | rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS + |
528 | bnxt_get_num_tpa_ring_stats(bp); |
529 | tx = NUM_RING_TX_HW_STATS; |
530 | cmn = NUM_RING_CMN_SW_STATS; |
531 | return rx * bp->rx_nr_rings + |
532 | tx * (bp->tx_nr_rings_xdp + bp->tx_nr_rings_per_tc) + |
533 | cmn * bp->cp_nr_rings; |
534 | } |
535 | |
536 | static int bnxt_get_num_stats(struct bnxt *bp) |
537 | { |
538 | int num_stats = bnxt_get_num_ring_stats(bp); |
539 | int len; |
540 | |
541 | num_stats += BNXT_NUM_RING_ERR_STATS; |
542 | |
543 | if (bp->flags & BNXT_FLAG_PORT_STATS) |
544 | num_stats += BNXT_NUM_PORT_STATS; |
545 | |
546 | if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { |
547 | len = min_t(int, bp->fw_rx_stats_ext_size, |
548 | ARRAY_SIZE(bnxt_port_stats_ext_arr)); |
549 | num_stats += len; |
550 | len = min_t(int, bp->fw_tx_stats_ext_size, |
551 | ARRAY_SIZE(bnxt_tx_port_stats_ext_arr)); |
552 | num_stats += len; |
553 | if (bp->pri2cos_valid) |
554 | num_stats += BNXT_NUM_STATS_PRI; |
555 | } |
556 | |
557 | return num_stats; |
558 | } |
559 | |
560 | static int bnxt_get_sset_count(struct net_device *dev, int sset) |
561 | { |
562 | struct bnxt *bp = netdev_priv(dev); |
563 | |
564 | switch (sset) { |
565 | case ETH_SS_STATS: |
566 | return bnxt_get_num_stats(bp); |
567 | case ETH_SS_TEST: |
568 | if (!bp->num_tests) |
569 | return -EOPNOTSUPP; |
570 | return bp->num_tests; |
571 | default: |
572 | return -EOPNOTSUPP; |
573 | } |
574 | } |
575 | |
576 | static bool is_rx_ring(struct bnxt *bp, int ring_num) |
577 | { |
578 | return ring_num < bp->rx_nr_rings; |
579 | } |
580 | |
581 | static bool is_tx_ring(struct bnxt *bp, int ring_num) |
582 | { |
583 | int tx_base = 0; |
584 | |
585 | if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) |
586 | tx_base = bp->rx_nr_rings; |
587 | |
588 | if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings)) |
589 | return true; |
590 | return false; |
591 | } |
592 | |
593 | static void bnxt_get_ethtool_stats(struct net_device *dev, |
594 | struct ethtool_stats *stats, u64 *buf) |
595 | { |
596 | struct bnxt_total_ring_err_stats ring_err_stats = {0}; |
597 | struct bnxt *bp = netdev_priv(dev); |
598 | u64 *curr, *prev; |
599 | u32 tpa_stats; |
600 | u32 i, j = 0; |
601 | |
602 | if (!bp->bnapi) { |
603 | j += bnxt_get_num_ring_stats(bp); |
604 | goto skip_ring_stats; |
605 | } |
606 | |
607 | tpa_stats = bnxt_get_num_tpa_ring_stats(bp); |
608 | for (i = 0; i < bp->cp_nr_rings; i++) { |
609 | struct bnxt_napi *bnapi = bp->bnapi[i]; |
610 | struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; |
611 | u64 *sw_stats = cpr->stats.sw_stats; |
612 | u64 *sw; |
613 | int k; |
614 | |
615 | if (is_rx_ring(bp, ring_num: i)) { |
616 | for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++) |
617 | buf[j] = sw_stats[k]; |
618 | } |
619 | if (is_tx_ring(bp, ring_num: i)) { |
620 | k = NUM_RING_RX_HW_STATS; |
621 | for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; |
622 | j++, k++) |
623 | buf[j] = sw_stats[k]; |
624 | } |
625 | if (!tpa_stats || !is_rx_ring(bp, ring_num: i)) |
626 | goto skip_tpa_ring_stats; |
627 | |
628 | k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS; |
629 | for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS + |
630 | tpa_stats; j++, k++) |
631 | buf[j] = sw_stats[k]; |
632 | |
633 | skip_tpa_ring_stats: |
634 | sw = (u64 *)&cpr->sw_stats.rx; |
635 | if (is_rx_ring(bp, ring_num: i)) { |
636 | for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++) |
637 | buf[j] = sw[k]; |
638 | } |
639 | |
640 | sw = (u64 *)&cpr->sw_stats.cmn; |
641 | for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++) |
642 | buf[j] = sw[k]; |
643 | } |
644 | |
645 | bnxt_get_ring_err_stats(bp, stats: &ring_err_stats); |
646 | |
647 | skip_ring_stats: |
648 | curr = &ring_err_stats.rx_total_l4_csum_errors; |
649 | prev = &bp->ring_err_stats_prev.rx_total_l4_csum_errors; |
650 | for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++, j++, curr++, prev++) |
651 | buf[j] = *curr + *prev; |
652 | |
653 | if (bp->flags & BNXT_FLAG_PORT_STATS) { |
654 | u64 *port_stats = bp->port_stats.sw_stats; |
655 | |
656 | for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) |
657 | buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset); |
658 | } |
659 | if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { |
660 | u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats; |
661 | u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats; |
662 | u32 len; |
663 | |
664 | len = min_t(u32, bp->fw_rx_stats_ext_size, |
665 | ARRAY_SIZE(bnxt_port_stats_ext_arr)); |
666 | for (i = 0; i < len; i++, j++) { |
667 | buf[j] = *(rx_port_stats_ext + |
668 | bnxt_port_stats_ext_arr[i].offset); |
669 | } |
670 | len = min_t(u32, bp->fw_tx_stats_ext_size, |
671 | ARRAY_SIZE(bnxt_tx_port_stats_ext_arr)); |
672 | for (i = 0; i < len; i++, j++) { |
673 | buf[j] = *(tx_port_stats_ext + |
674 | bnxt_tx_port_stats_ext_arr[i].offset); |
675 | } |
676 | if (bp->pri2cos_valid) { |
677 | for (i = 0; i < 8; i++, j++) { |
678 | long n = bnxt_rx_bytes_pri_arr[i].base_off + |
679 | bp->pri2cos_idx[i]; |
680 | |
681 | buf[j] = *(rx_port_stats_ext + n); |
682 | } |
683 | for (i = 0; i < 8; i++, j++) { |
684 | long n = bnxt_rx_pkts_pri_arr[i].base_off + |
685 | bp->pri2cos_idx[i]; |
686 | |
687 | buf[j] = *(rx_port_stats_ext + n); |
688 | } |
689 | for (i = 0; i < 8; i++, j++) { |
690 | long n = bnxt_tx_bytes_pri_arr[i].base_off + |
691 | bp->pri2cos_idx[i]; |
692 | |
693 | buf[j] = *(tx_port_stats_ext + n); |
694 | } |
695 | for (i = 0; i < 8; i++, j++) { |
696 | long n = bnxt_tx_pkts_pri_arr[i].base_off + |
697 | bp->pri2cos_idx[i]; |
698 | |
699 | buf[j] = *(tx_port_stats_ext + n); |
700 | } |
701 | } |
702 | } |
703 | } |
704 | |
705 | static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) |
706 | { |
707 | struct bnxt *bp = netdev_priv(dev); |
708 | static const char * const *str; |
709 | u32 i, j, num_str; |
710 | |
711 | switch (stringset) { |
712 | case ETH_SS_STATS: |
713 | for (i = 0; i < bp->cp_nr_rings; i++) { |
714 | if (is_rx_ring(bp, ring_num: i)) { |
715 | num_str = NUM_RING_RX_HW_STATS; |
716 | for (j = 0; j < num_str; j++) { |
717 | sprintf(buf, fmt: "[%d]: %s" , i, |
718 | bnxt_ring_rx_stats_str[j]); |
719 | buf += ETH_GSTRING_LEN; |
720 | } |
721 | } |
722 | if (is_tx_ring(bp, ring_num: i)) { |
723 | num_str = NUM_RING_TX_HW_STATS; |
724 | for (j = 0; j < num_str; j++) { |
725 | sprintf(buf, fmt: "[%d]: %s" , i, |
726 | bnxt_ring_tx_stats_str[j]); |
727 | buf += ETH_GSTRING_LEN; |
728 | } |
729 | } |
730 | num_str = bnxt_get_num_tpa_ring_stats(bp); |
731 | if (!num_str || !is_rx_ring(bp, ring_num: i)) |
732 | goto skip_tpa_stats; |
733 | |
734 | if (bp->max_tpa_v2) |
735 | str = bnxt_ring_tpa2_stats_str; |
736 | else |
737 | str = bnxt_ring_tpa_stats_str; |
738 | |
739 | for (j = 0; j < num_str; j++) { |
740 | sprintf(buf, fmt: "[%d]: %s" , i, str[j]); |
741 | buf += ETH_GSTRING_LEN; |
742 | } |
743 | skip_tpa_stats: |
744 | if (is_rx_ring(bp, ring_num: i)) { |
745 | num_str = NUM_RING_RX_SW_STATS; |
746 | for (j = 0; j < num_str; j++) { |
747 | sprintf(buf, fmt: "[%d]: %s" , i, |
748 | bnxt_rx_sw_stats_str[j]); |
749 | buf += ETH_GSTRING_LEN; |
750 | } |
751 | } |
752 | num_str = NUM_RING_CMN_SW_STATS; |
753 | for (j = 0; j < num_str; j++) { |
754 | sprintf(buf, fmt: "[%d]: %s" , i, |
755 | bnxt_cmn_sw_stats_str[j]); |
756 | buf += ETH_GSTRING_LEN; |
757 | } |
758 | } |
759 | for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) { |
760 | strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN); |
761 | buf += ETH_GSTRING_LEN; |
762 | } |
763 | |
764 | if (bp->flags & BNXT_FLAG_PORT_STATS) { |
765 | for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { |
766 | strcpy(p: buf, q: bnxt_port_stats_arr[i].string); |
767 | buf += ETH_GSTRING_LEN; |
768 | } |
769 | } |
770 | if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { |
771 | u32 len; |
772 | |
773 | len = min_t(u32, bp->fw_rx_stats_ext_size, |
774 | ARRAY_SIZE(bnxt_port_stats_ext_arr)); |
775 | for (i = 0; i < len; i++) { |
776 | strcpy(p: buf, q: bnxt_port_stats_ext_arr[i].string); |
777 | buf += ETH_GSTRING_LEN; |
778 | } |
779 | len = min_t(u32, bp->fw_tx_stats_ext_size, |
780 | ARRAY_SIZE(bnxt_tx_port_stats_ext_arr)); |
781 | for (i = 0; i < len; i++) { |
782 | strcpy(p: buf, |
783 | q: bnxt_tx_port_stats_ext_arr[i].string); |
784 | buf += ETH_GSTRING_LEN; |
785 | } |
786 | if (bp->pri2cos_valid) { |
787 | for (i = 0; i < 8; i++) { |
788 | strcpy(p: buf, |
789 | q: bnxt_rx_bytes_pri_arr[i].string); |
790 | buf += ETH_GSTRING_LEN; |
791 | } |
792 | for (i = 0; i < 8; i++) { |
793 | strcpy(p: buf, |
794 | q: bnxt_rx_pkts_pri_arr[i].string); |
795 | buf += ETH_GSTRING_LEN; |
796 | } |
797 | for (i = 0; i < 8; i++) { |
798 | strcpy(p: buf, |
799 | q: bnxt_tx_bytes_pri_arr[i].string); |
800 | buf += ETH_GSTRING_LEN; |
801 | } |
802 | for (i = 0; i < 8; i++) { |
803 | strcpy(p: buf, |
804 | q: bnxt_tx_pkts_pri_arr[i].string); |
805 | buf += ETH_GSTRING_LEN; |
806 | } |
807 | } |
808 | } |
809 | break; |
810 | case ETH_SS_TEST: |
811 | if (bp->num_tests) |
812 | memcpy(buf, bp->test_info->string, |
813 | bp->num_tests * ETH_GSTRING_LEN); |
814 | break; |
815 | default: |
816 | netdev_err(dev: bp->dev, format: "bnxt_get_strings invalid request %x\n" , |
817 | stringset); |
818 | break; |
819 | } |
820 | } |
821 | |
822 | static void bnxt_get_ringparam(struct net_device *dev, |
823 | struct ethtool_ringparam *ering, |
824 | struct kernel_ethtool_ringparam *kernel_ering, |
825 | struct netlink_ext_ack *extack) |
826 | { |
827 | struct bnxt *bp = netdev_priv(dev); |
828 | |
829 | if (bp->flags & BNXT_FLAG_AGG_RINGS) { |
830 | ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA; |
831 | ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT; |
832 | kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED; |
833 | } else { |
834 | ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT; |
835 | ering->rx_jumbo_max_pending = 0; |
836 | kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED; |
837 | } |
838 | ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT; |
839 | |
840 | ering->rx_pending = bp->rx_ring_size; |
841 | ering->rx_jumbo_pending = bp->rx_agg_ring_size; |
842 | ering->tx_pending = bp->tx_ring_size; |
843 | } |
844 | |
845 | static int bnxt_set_ringparam(struct net_device *dev, |
846 | struct ethtool_ringparam *ering, |
847 | struct kernel_ethtool_ringparam *kernel_ering, |
848 | struct netlink_ext_ack *extack) |
849 | { |
850 | struct bnxt *bp = netdev_priv(dev); |
851 | |
852 | if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) || |
853 | (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) || |
854 | (ering->tx_pending < BNXT_MIN_TX_DESC_CNT)) |
855 | return -EINVAL; |
856 | |
857 | if (netif_running(dev)) |
858 | bnxt_close_nic(bp, false, false); |
859 | |
860 | bp->rx_ring_size = ering->rx_pending; |
861 | bp->tx_ring_size = ering->tx_pending; |
862 | bnxt_set_ring_params(bp); |
863 | |
864 | if (netif_running(dev)) |
865 | return bnxt_open_nic(bp, false, false); |
866 | |
867 | return 0; |
868 | } |
869 | |
870 | static void bnxt_get_channels(struct net_device *dev, |
871 | struct ethtool_channels *channel) |
872 | { |
873 | struct bnxt *bp = netdev_priv(dev); |
874 | struct bnxt_hw_resc *hw_resc = &bp->hw_resc; |
875 | int max_rx_rings, max_tx_rings, tcs; |
876 | int max_tx_sch_inputs, tx_grps; |
877 | |
878 | /* Get the most up-to-date max_tx_sch_inputs. */ |
879 | if (netif_running(dev) && BNXT_NEW_RM(bp)) |
880 | bnxt_hwrm_func_resc_qcaps(bp, all: false); |
881 | max_tx_sch_inputs = hw_resc->max_tx_sch_inputs; |
882 | |
883 | bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true); |
884 | if (max_tx_sch_inputs) |
885 | max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); |
886 | |
887 | tcs = bp->num_tc; |
888 | tx_grps = max(tcs, 1); |
889 | if (bp->tx_nr_rings_xdp) |
890 | tx_grps++; |
891 | max_tx_rings /= tx_grps; |
892 | channel->max_combined = min_t(int, max_rx_rings, max_tx_rings); |
893 | |
894 | if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) { |
895 | max_rx_rings = 0; |
896 | max_tx_rings = 0; |
897 | } |
898 | if (max_tx_sch_inputs) |
899 | max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs); |
900 | |
901 | if (tcs > 1) |
902 | max_tx_rings /= tcs; |
903 | |
904 | channel->max_rx = max_rx_rings; |
905 | channel->max_tx = max_tx_rings; |
906 | channel->max_other = 0; |
907 | if (bp->flags & BNXT_FLAG_SHARED_RINGS) { |
908 | channel->combined_count = bp->rx_nr_rings; |
909 | if (BNXT_CHIP_TYPE_NITRO_A0(bp)) |
910 | channel->combined_count--; |
911 | } else { |
912 | if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) { |
913 | channel->rx_count = bp->rx_nr_rings; |
914 | channel->tx_count = bp->tx_nr_rings_per_tc; |
915 | } |
916 | } |
917 | } |
918 | |
919 | static int bnxt_set_channels(struct net_device *dev, |
920 | struct ethtool_channels *channel) |
921 | { |
922 | struct bnxt *bp = netdev_priv(dev); |
923 | int req_tx_rings, req_rx_rings, tcs; |
924 | bool sh = false; |
925 | int tx_xdp = 0; |
926 | int rc = 0; |
927 | int tx_cp; |
928 | |
929 | if (channel->other_count) |
930 | return -EINVAL; |
931 | |
932 | if (!channel->combined_count && |
933 | (!channel->rx_count || !channel->tx_count)) |
934 | return -EINVAL; |
935 | |
936 | if (channel->combined_count && |
937 | (channel->rx_count || channel->tx_count)) |
938 | return -EINVAL; |
939 | |
940 | if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count || |
941 | channel->tx_count)) |
942 | return -EINVAL; |
943 | |
944 | if (channel->combined_count) |
945 | sh = true; |
946 | |
947 | tcs = bp->num_tc; |
948 | |
949 | req_tx_rings = sh ? channel->combined_count : channel->tx_count; |
950 | req_rx_rings = sh ? channel->combined_count : channel->rx_count; |
951 | if (bp->tx_nr_rings_xdp) { |
952 | if (!sh) { |
953 | netdev_err(dev, format: "Only combined mode supported when XDP is enabled.\n" ); |
954 | return -EINVAL; |
955 | } |
956 | tx_xdp = req_rx_rings; |
957 | } |
958 | rc = bnxt_check_rings(bp, tx: req_tx_rings, rx: req_rx_rings, sh, tcs, tx_xdp); |
959 | if (rc) { |
960 | netdev_warn(dev, format: "Unable to allocate the requested rings\n" ); |
961 | return rc; |
962 | } |
963 | |
964 | if (bnxt_get_nr_rss_ctxs(bp, rx_rings: req_rx_rings) != |
965 | bnxt_get_nr_rss_ctxs(bp, rx_rings: bp->rx_nr_rings) && |
966 | netif_is_rxfh_configured(dev)) { |
967 | netdev_warn(dev, format: "RSS table size change required, RSS table entries must be default to proceed\n" ); |
968 | return -EINVAL; |
969 | } |
970 | |
971 | bnxt_clear_usr_fltrs(bp, all: true); |
972 | if (netif_running(dev)) { |
973 | if (BNXT_PF(bp)) { |
974 | /* TODO CHIMP_FW: Send message to all VF's |
975 | * before PF unload |
976 | */ |
977 | } |
978 | bnxt_close_nic(bp, true, false); |
979 | } |
980 | |
981 | if (sh) { |
982 | bp->flags |= BNXT_FLAG_SHARED_RINGS; |
983 | bp->rx_nr_rings = channel->combined_count; |
984 | bp->tx_nr_rings_per_tc = channel->combined_count; |
985 | } else { |
986 | bp->flags &= ~BNXT_FLAG_SHARED_RINGS; |
987 | bp->rx_nr_rings = channel->rx_count; |
988 | bp->tx_nr_rings_per_tc = channel->tx_count; |
989 | } |
990 | bp->tx_nr_rings_xdp = tx_xdp; |
991 | bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp; |
992 | if (tcs > 1) |
993 | bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; |
994 | |
995 | tx_cp = bnxt_num_tx_to_cp(bp, tx: bp->tx_nr_rings); |
996 | bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : |
997 | tx_cp + bp->rx_nr_rings; |
998 | |
999 | /* After changing number of rx channels, update NTUPLE feature. */ |
1000 | netdev_update_features(dev); |
1001 | if (netif_running(dev)) { |
1002 | rc = bnxt_open_nic(bp, true, false); |
1003 | if ((!rc) && BNXT_PF(bp)) { |
1004 | /* TODO CHIMP_FW: Send message to all VF's |
1005 | * to renable |
1006 | */ |
1007 | } |
1008 | } else { |
1009 | rc = bnxt_reserve_rings(bp, irq_re_init: true); |
1010 | } |
1011 | |
1012 | return rc; |
1013 | } |
1014 | |
1015 | static u32 bnxt_get_all_fltr_ids_rcu(struct bnxt *bp, struct hlist_head tbl[], |
1016 | int tbl_size, u32 *ids, u32 start, |
1017 | u32 id_cnt) |
1018 | { |
1019 | int i, j = start; |
1020 | |
1021 | if (j >= id_cnt) |
1022 | return j; |
1023 | for (i = 0; i < tbl_size; i++) { |
1024 | struct hlist_head *head; |
1025 | struct bnxt_filter_base *fltr; |
1026 | |
1027 | head = &tbl[i]; |
1028 | hlist_for_each_entry_rcu(fltr, head, hash) { |
1029 | if (!fltr->flags || |
1030 | test_bit(BNXT_FLTR_FW_DELETED, &fltr->state)) |
1031 | continue; |
1032 | ids[j++] = fltr->sw_id; |
1033 | if (j == id_cnt) |
1034 | return j; |
1035 | } |
1036 | } |
1037 | return j; |
1038 | } |
1039 | |
1040 | static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp, |
1041 | struct hlist_head tbl[], |
1042 | int tbl_size, u32 id) |
1043 | { |
1044 | int i; |
1045 | |
1046 | for (i = 0; i < tbl_size; i++) { |
1047 | struct hlist_head *head; |
1048 | struct bnxt_filter_base *fltr; |
1049 | |
1050 | head = &tbl[i]; |
1051 | hlist_for_each_entry_rcu(fltr, head, hash) { |
1052 | if (fltr->flags && fltr->sw_id == id) |
1053 | return fltr; |
1054 | } |
1055 | } |
1056 | return NULL; |
1057 | } |
1058 | |
1059 | static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, |
1060 | u32 *rule_locs) |
1061 | { |
1062 | u32 count; |
1063 | |
1064 | cmd->data = bp->ntp_fltr_count; |
1065 | rcu_read_lock(); |
1066 | count = bnxt_get_all_fltr_ids_rcu(bp, tbl: bp->l2_fltr_hash_tbl, |
1067 | BNXT_L2_FLTR_HASH_SIZE, ids: rule_locs, start: 0, |
1068 | id_cnt: cmd->rule_cnt); |
1069 | cmd->rule_cnt = bnxt_get_all_fltr_ids_rcu(bp, tbl: bp->ntp_fltr_hash_tbl, |
1070 | BNXT_NTP_FLTR_HASH_SIZE, |
1071 | ids: rule_locs, start: count, |
1072 | id_cnt: cmd->rule_cnt); |
1073 | rcu_read_unlock(); |
1074 | |
1075 | return 0; |
1076 | } |
1077 | |
1078 | static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) |
1079 | { |
1080 | struct ethtool_rx_flow_spec *fs = |
1081 | (struct ethtool_rx_flow_spec *)&cmd->fs; |
1082 | struct bnxt_filter_base *fltr_base; |
1083 | struct bnxt_ntuple_filter *fltr; |
1084 | struct bnxt_flow_masks *fmasks; |
1085 | struct flow_keys *fkeys; |
1086 | int rc = -EINVAL; |
1087 | |
1088 | if (fs->location >= bp->max_fltr) |
1089 | return rc; |
1090 | |
1091 | rcu_read_lock(); |
1092 | fltr_base = bnxt_get_one_fltr_rcu(bp, tbl: bp->l2_fltr_hash_tbl, |
1093 | BNXT_L2_FLTR_HASH_SIZE, |
1094 | id: fs->location); |
1095 | if (fltr_base) { |
1096 | struct ethhdr *h_ether = &fs->h_u.ether_spec; |
1097 | struct ethhdr *m_ether = &fs->m_u.ether_spec; |
1098 | struct bnxt_l2_filter *l2_fltr; |
1099 | struct bnxt_l2_key *l2_key; |
1100 | |
1101 | l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base); |
1102 | l2_key = &l2_fltr->l2_key; |
1103 | fs->flow_type = ETHER_FLOW; |
1104 | ether_addr_copy(dst: h_ether->h_dest, src: l2_key->dst_mac_addr); |
1105 | eth_broadcast_addr(addr: m_ether->h_dest); |
1106 | if (l2_key->vlan) { |
1107 | struct ethtool_flow_ext *m_ext = &fs->m_ext; |
1108 | struct ethtool_flow_ext *h_ext = &fs->h_ext; |
1109 | |
1110 | fs->flow_type |= FLOW_EXT; |
1111 | m_ext->vlan_tci = htons(0xfff); |
1112 | h_ext->vlan_tci = htons(l2_key->vlan); |
1113 | } |
1114 | if (fltr_base->flags & BNXT_ACT_RING_DST) |
1115 | fs->ring_cookie = fltr_base->rxq; |
1116 | if (fltr_base->flags & BNXT_ACT_FUNC_DST) |
1117 | fs->ring_cookie = (u64)(fltr_base->vf_idx + 1) << |
1118 | ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; |
1119 | rcu_read_unlock(); |
1120 | return 0; |
1121 | } |
1122 | fltr_base = bnxt_get_one_fltr_rcu(bp, tbl: bp->ntp_fltr_hash_tbl, |
1123 | BNXT_NTP_FLTR_HASH_SIZE, |
1124 | id: fs->location); |
1125 | if (!fltr_base) { |
1126 | rcu_read_unlock(); |
1127 | return rc; |
1128 | } |
1129 | fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base); |
1130 | |
1131 | fkeys = &fltr->fkeys; |
1132 | fmasks = &fltr->fmasks; |
1133 | if (fkeys->basic.n_proto == htons(ETH_P_IP)) { |
1134 | if (fkeys->basic.ip_proto == IPPROTO_ICMP || |
1135 | fkeys->basic.ip_proto == IPPROTO_RAW) { |
1136 | fs->flow_type = IP_USER_FLOW; |
1137 | fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; |
1138 | if (fkeys->basic.ip_proto == IPPROTO_ICMP) |
1139 | fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; |
1140 | else |
1141 | fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW; |
1142 | fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK; |
1143 | } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { |
1144 | fs->flow_type = TCP_V4_FLOW; |
1145 | } else if (fkeys->basic.ip_proto == IPPROTO_UDP) { |
1146 | fs->flow_type = UDP_V4_FLOW; |
1147 | } else { |
1148 | goto fltr_err; |
1149 | } |
1150 | |
1151 | fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; |
1152 | fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src; |
1153 | fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; |
1154 | fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst; |
1155 | if (fs->flow_type == TCP_V4_FLOW || |
1156 | fs->flow_type == UDP_V4_FLOW) { |
1157 | fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; |
1158 | fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src; |
1159 | fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; |
1160 | fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; |
1161 | } |
1162 | } else { |
1163 | if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 || |
1164 | fkeys->basic.ip_proto == IPPROTO_RAW) { |
1165 | fs->flow_type = IPV6_USER_FLOW; |
1166 | if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) |
1167 | fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; |
1168 | else |
1169 | fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW; |
1170 | fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK; |
1171 | } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { |
1172 | fs->flow_type = TCP_V6_FLOW; |
1173 | } else if (fkeys->basic.ip_proto == IPPROTO_UDP) { |
1174 | fs->flow_type = UDP_V6_FLOW; |
1175 | } else { |
1176 | goto fltr_err; |
1177 | } |
1178 | |
1179 | *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = |
1180 | fkeys->addrs.v6addrs.src; |
1181 | *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6src[0] = |
1182 | fmasks->addrs.v6addrs.src; |
1183 | *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = |
1184 | fkeys->addrs.v6addrs.dst; |
1185 | *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] = |
1186 | fmasks->addrs.v6addrs.dst; |
1187 | if (fs->flow_type == TCP_V6_FLOW || |
1188 | fs->flow_type == UDP_V6_FLOW) { |
1189 | fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; |
1190 | fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src; |
1191 | fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; |
1192 | fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst; |
1193 | } |
1194 | } |
1195 | |
1196 | if (fltr->base.flags & BNXT_ACT_DROP) |
1197 | fs->ring_cookie = RX_CLS_FLOW_DISC; |
1198 | else |
1199 | fs->ring_cookie = fltr->base.rxq; |
1200 | rc = 0; |
1201 | |
1202 | fltr_err: |
1203 | rcu_read_unlock(); |
1204 | |
1205 | return rc; |
1206 | } |
1207 | |
1208 | static int bnxt_add_l2_cls_rule(struct bnxt *bp, |
1209 | struct ethtool_rx_flow_spec *fs) |
1210 | { |
1211 | u32 ring = ethtool_get_flow_spec_ring(ring_cookie: fs->ring_cookie); |
1212 | u8 vf = ethtool_get_flow_spec_ring_vf(ring_cookie: fs->ring_cookie); |
1213 | struct ethhdr *h_ether = &fs->h_u.ether_spec; |
1214 | struct ethhdr *m_ether = &fs->m_u.ether_spec; |
1215 | struct bnxt_l2_filter *fltr; |
1216 | struct bnxt_l2_key key; |
1217 | u16 vnic_id; |
1218 | u8 flags; |
1219 | int rc; |
1220 | |
1221 | if (BNXT_CHIP_P5_PLUS(bp)) |
1222 | return -EOPNOTSUPP; |
1223 | |
1224 | if (!is_broadcast_ether_addr(addr: m_ether->h_dest)) |
1225 | return -EINVAL; |
1226 | ether_addr_copy(dst: key.dst_mac_addr, src: h_ether->h_dest); |
1227 | key.vlan = 0; |
1228 | if (fs->flow_type & FLOW_EXT) { |
1229 | struct ethtool_flow_ext *m_ext = &fs->m_ext; |
1230 | struct ethtool_flow_ext *h_ext = &fs->h_ext; |
1231 | |
1232 | if (m_ext->vlan_tci != htons(0xfff) || !h_ext->vlan_tci) |
1233 | return -EINVAL; |
1234 | key.vlan = ntohs(h_ext->vlan_tci); |
1235 | } |
1236 | |
1237 | if (vf) { |
1238 | flags = BNXT_ACT_FUNC_DST; |
1239 | vnic_id = 0xffff; |
1240 | vf--; |
1241 | } else { |
1242 | flags = BNXT_ACT_RING_DST; |
1243 | vnic_id = bp->vnic_info[ring + 1].fw_vnic_id; |
1244 | } |
1245 | fltr = bnxt_alloc_new_l2_filter(bp, key: &key, flags); |
1246 | if (IS_ERR(ptr: fltr)) |
1247 | return PTR_ERR(ptr: fltr); |
1248 | |
1249 | fltr->base.fw_vnic_id = vnic_id; |
1250 | fltr->base.rxq = ring; |
1251 | fltr->base.vf_idx = vf; |
1252 | rc = bnxt_hwrm_l2_filter_alloc(bp, fltr); |
1253 | if (rc) |
1254 | bnxt_del_l2_filter(bp, fltr); |
1255 | else |
1256 | fs->location = fltr->base.sw_id; |
1257 | return rc; |
1258 | } |
1259 | |
1260 | static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, |
1261 | struct ethtool_usrip4_spec *ip_mask) |
1262 | { |
1263 | if (ip_mask->l4_4_bytes || ip_mask->tos || |
1264 | ip_spec->ip_ver != ETH_RX_NFC_IP4 || |
1265 | ip_mask->proto != BNXT_IP_PROTO_FULL_MASK || |
1266 | (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP)) |
1267 | return false; |
1268 | return true; |
1269 | } |
1270 | |
1271 | static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec, |
1272 | struct ethtool_usrip6_spec *ip_mask) |
1273 | { |
1274 | if (ip_mask->l4_4_bytes || ip_mask->tclass || |
1275 | ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK || |
1276 | (ip_spec->l4_proto != IPPROTO_RAW && |
1277 | ip_spec->l4_proto != IPPROTO_ICMPV6)) |
1278 | return false; |
1279 | return true; |
1280 | } |
1281 | |
1282 | static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, |
1283 | struct ethtool_rx_flow_spec *fs) |
1284 | { |
1285 | u8 vf = ethtool_get_flow_spec_ring_vf(ring_cookie: fs->ring_cookie); |
1286 | u32 ring = ethtool_get_flow_spec_ring(ring_cookie: fs->ring_cookie); |
1287 | struct bnxt_ntuple_filter *new_fltr, *fltr; |
1288 | struct bnxt_l2_filter *l2_fltr; |
1289 | struct bnxt_flow_masks *fmasks; |
1290 | u32 flow_type = fs->flow_type; |
1291 | struct flow_keys *fkeys; |
1292 | u32 idx; |
1293 | int rc; |
1294 | |
1295 | if (!bp->vnic_info) |
1296 | return -EAGAIN; |
1297 | |
1298 | if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf) |
1299 | return -EOPNOTSUPP; |
1300 | |
1301 | if (flow_type == IP_USER_FLOW) { |
1302 | if (!bnxt_verify_ntuple_ip4_flow(ip_spec: &fs->h_u.usr_ip4_spec, |
1303 | ip_mask: &fs->m_u.usr_ip4_spec)) |
1304 | return -EOPNOTSUPP; |
1305 | } |
1306 | |
1307 | if (flow_type == IPV6_USER_FLOW) { |
1308 | if (!bnxt_verify_ntuple_ip6_flow(ip_spec: &fs->h_u.usr_ip6_spec, |
1309 | ip_mask: &fs->m_u.usr_ip6_spec)) |
1310 | return -EOPNOTSUPP; |
1311 | } |
1312 | |
1313 | new_fltr = kzalloc(size: sizeof(*new_fltr), GFP_KERNEL); |
1314 | if (!new_fltr) |
1315 | return -ENOMEM; |
1316 | |
1317 | l2_fltr = bp->vnic_info[BNXT_VNIC_DEFAULT].l2_filters[0]; |
1318 | atomic_inc(v: &l2_fltr->refcnt); |
1319 | new_fltr->l2_fltr = l2_fltr; |
1320 | fmasks = &new_fltr->fmasks; |
1321 | fkeys = &new_fltr->fkeys; |
1322 | |
1323 | rc = -EOPNOTSUPP; |
1324 | switch (flow_type) { |
1325 | case IP_USER_FLOW: { |
1326 | struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec; |
1327 | struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec; |
1328 | |
1329 | fkeys->basic.ip_proto = ip_spec->proto; |
1330 | fkeys->basic.n_proto = htons(ETH_P_IP); |
1331 | fkeys->addrs.v4addrs.src = ip_spec->ip4src; |
1332 | fmasks->addrs.v4addrs.src = ip_mask->ip4src; |
1333 | fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; |
1334 | fmasks->addrs.v4addrs.dst = ip_mask->ip4dst; |
1335 | break; |
1336 | } |
1337 | case TCP_V4_FLOW: |
1338 | case UDP_V4_FLOW: { |
1339 | struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec; |
1340 | struct ethtool_tcpip4_spec *ip_mask = &fs->m_u.tcp_ip4_spec; |
1341 | |
1342 | fkeys->basic.ip_proto = IPPROTO_TCP; |
1343 | if (flow_type == UDP_V4_FLOW) |
1344 | fkeys->basic.ip_proto = IPPROTO_UDP; |
1345 | fkeys->basic.n_proto = htons(ETH_P_IP); |
1346 | fkeys->addrs.v4addrs.src = ip_spec->ip4src; |
1347 | fmasks->addrs.v4addrs.src = ip_mask->ip4src; |
1348 | fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; |
1349 | fmasks->addrs.v4addrs.dst = ip_mask->ip4dst; |
1350 | fkeys->ports.src = ip_spec->psrc; |
1351 | fmasks->ports.src = ip_mask->psrc; |
1352 | fkeys->ports.dst = ip_spec->pdst; |
1353 | fmasks->ports.dst = ip_mask->pdst; |
1354 | break; |
1355 | } |
1356 | case IPV6_USER_FLOW: { |
1357 | struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec; |
1358 | struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec; |
1359 | |
1360 | fkeys->basic.ip_proto = ip_spec->l4_proto; |
1361 | fkeys->basic.n_proto = htons(ETH_P_IPV6); |
1362 | fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; |
1363 | fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; |
1364 | fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst; |
1365 | fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst; |
1366 | break; |
1367 | } |
1368 | case TCP_V6_FLOW: |
1369 | case UDP_V6_FLOW: { |
1370 | struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec; |
1371 | struct ethtool_tcpip6_spec *ip_mask = &fs->m_u.tcp_ip6_spec; |
1372 | |
1373 | fkeys->basic.ip_proto = IPPROTO_TCP; |
1374 | if (flow_type == UDP_V6_FLOW) |
1375 | fkeys->basic.ip_proto = IPPROTO_UDP; |
1376 | fkeys->basic.n_proto = htons(ETH_P_IPV6); |
1377 | |
1378 | fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; |
1379 | fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; |
1380 | fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst; |
1381 | fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst; |
1382 | fkeys->ports.src = ip_spec->psrc; |
1383 | fmasks->ports.src = ip_mask->psrc; |
1384 | fkeys->ports.dst = ip_spec->pdst; |
1385 | fmasks->ports.dst = ip_mask->pdst; |
1386 | break; |
1387 | } |
1388 | default: |
1389 | rc = -EOPNOTSUPP; |
1390 | goto ntuple_err; |
1391 | } |
1392 | if (!memcmp(p: &BNXT_FLOW_MASK_NONE, q: fmasks, size: sizeof(*fmasks))) |
1393 | goto ntuple_err; |
1394 | |
1395 | idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL); |
1396 | rcu_read_lock(); |
1397 | fltr = bnxt_lookup_ntp_filter_from_idx(bp, fltr: new_fltr, idx); |
1398 | if (fltr) { |
1399 | rcu_read_unlock(); |
1400 | rc = -EEXIST; |
1401 | goto ntuple_err; |
1402 | } |
1403 | rcu_read_unlock(); |
1404 | |
1405 | new_fltr->base.flags = BNXT_ACT_NO_AGING; |
1406 | if (fs->ring_cookie == RX_CLS_FLOW_DISC) |
1407 | new_fltr->base.flags |= BNXT_ACT_DROP; |
1408 | else |
1409 | new_fltr->base.rxq = ring; |
1410 | __set_bit(BNXT_FLTR_VALID, &new_fltr->base.state); |
1411 | rc = bnxt_insert_ntp_filter(bp, fltr: new_fltr, idx); |
1412 | if (!rc) { |
1413 | rc = bnxt_hwrm_cfa_ntuple_filter_alloc(bp, fltr: new_fltr); |
1414 | if (rc) { |
1415 | bnxt_del_ntp_filter(bp, fltr: new_fltr); |
1416 | return rc; |
1417 | } |
1418 | fs->location = new_fltr->base.sw_id; |
1419 | return 0; |
1420 | } |
1421 | |
1422 | ntuple_err: |
1423 | atomic_dec(v: &l2_fltr->refcnt); |
1424 | kfree(objp: new_fltr); |
1425 | return rc; |
1426 | } |
1427 | |
1428 | static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) |
1429 | { |
1430 | struct ethtool_rx_flow_spec *fs = &cmd->fs; |
1431 | u32 ring, flow_type; |
1432 | int rc; |
1433 | u8 vf; |
1434 | |
1435 | if (!netif_running(dev: bp->dev)) |
1436 | return -EAGAIN; |
1437 | if (!(bp->flags & BNXT_FLAG_RFS)) |
1438 | return -EPERM; |
1439 | if (fs->location != RX_CLS_LOC_ANY) |
1440 | return -EINVAL; |
1441 | |
1442 | flow_type = fs->flow_type; |
1443 | if ((flow_type == IP_USER_FLOW || |
1444 | flow_type == IPV6_USER_FLOW) && |
1445 | !(bp->fw_cap & BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO)) |
1446 | return -EOPNOTSUPP; |
1447 | if (flow_type & (FLOW_MAC_EXT | FLOW_RSS)) |
1448 | return -EINVAL; |
1449 | flow_type &= ~FLOW_EXT; |
1450 | |
1451 | if (fs->ring_cookie == RX_CLS_FLOW_DISC && flow_type != ETHER_FLOW) |
1452 | return bnxt_add_ntuple_cls_rule(bp, fs); |
1453 | |
1454 | ring = ethtool_get_flow_spec_ring(ring_cookie: fs->ring_cookie); |
1455 | vf = ethtool_get_flow_spec_ring_vf(ring_cookie: fs->ring_cookie); |
1456 | if (BNXT_VF(bp) && vf) |
1457 | return -EINVAL; |
1458 | if (BNXT_PF(bp) && vf > bp->pf.active_vfs) |
1459 | return -EINVAL; |
1460 | if (!vf && ring >= bp->rx_nr_rings) |
1461 | return -EINVAL; |
1462 | |
1463 | if (flow_type == ETHER_FLOW) |
1464 | rc = bnxt_add_l2_cls_rule(bp, fs); |
1465 | else |
1466 | rc = bnxt_add_ntuple_cls_rule(bp, fs); |
1467 | return rc; |
1468 | } |
1469 | |
1470 | static int bnxt_srxclsrldel(struct bnxt *bp, struct ethtool_rxnfc *cmd) |
1471 | { |
1472 | struct ethtool_rx_flow_spec *fs = &cmd->fs; |
1473 | struct bnxt_filter_base *fltr_base; |
1474 | struct bnxt_ntuple_filter *fltr; |
1475 | u32 id = fs->location; |
1476 | |
1477 | rcu_read_lock(); |
1478 | fltr_base = bnxt_get_one_fltr_rcu(bp, tbl: bp->l2_fltr_hash_tbl, |
1479 | BNXT_L2_FLTR_HASH_SIZE, id); |
1480 | if (fltr_base) { |
1481 | struct bnxt_l2_filter *l2_fltr; |
1482 | |
1483 | l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base); |
1484 | rcu_read_unlock(); |
1485 | bnxt_hwrm_l2_filter_free(bp, fltr: l2_fltr); |
1486 | bnxt_del_l2_filter(bp, fltr: l2_fltr); |
1487 | return 0; |
1488 | } |
1489 | fltr_base = bnxt_get_one_fltr_rcu(bp, tbl: bp->ntp_fltr_hash_tbl, |
1490 | BNXT_NTP_FLTR_HASH_SIZE, id); |
1491 | if (!fltr_base) { |
1492 | rcu_read_unlock(); |
1493 | return -ENOENT; |
1494 | } |
1495 | |
1496 | fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base); |
1497 | if (!(fltr->base.flags & BNXT_ACT_NO_AGING)) { |
1498 | rcu_read_unlock(); |
1499 | return -EINVAL; |
1500 | } |
1501 | rcu_read_unlock(); |
1502 | bnxt_hwrm_cfa_ntuple_filter_free(bp, fltr); |
1503 | bnxt_del_ntp_filter(bp, fltr); |
1504 | return 0; |
1505 | } |
1506 | |
1507 | static u64 (struct bnxt *bp) |
1508 | { |
1509 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) |
1510 | return RXH_IP_SRC | RXH_IP_DST; |
1511 | return 0; |
1512 | } |
1513 | |
1514 | static u64 (struct bnxt *bp) |
1515 | { |
1516 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) |
1517 | return RXH_IP_SRC | RXH_IP_DST; |
1518 | return 0; |
1519 | } |
1520 | |
1521 | static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) |
1522 | { |
1523 | cmd->data = 0; |
1524 | switch (cmd->flow_type) { |
1525 | case TCP_V4_FLOW: |
1526 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) |
1527 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1528 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1529 | cmd->data |= get_ethtool_ipv4_rss(bp); |
1530 | break; |
1531 | case UDP_V4_FLOW: |
1532 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4) |
1533 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1534 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1535 | fallthrough; |
1536 | case AH_ESP_V4_FLOW: |
1537 | if (bp->rss_hash_cfg & |
1538 | (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | |
1539 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4)) |
1540 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1541 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1542 | fallthrough; |
1543 | case SCTP_V4_FLOW: |
1544 | case AH_V4_FLOW: |
1545 | case ESP_V4_FLOW: |
1546 | case IPV4_FLOW: |
1547 | cmd->data |= get_ethtool_ipv4_rss(bp); |
1548 | break; |
1549 | |
1550 | case TCP_V6_FLOW: |
1551 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) |
1552 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1553 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1554 | cmd->data |= get_ethtool_ipv6_rss(bp); |
1555 | break; |
1556 | case UDP_V6_FLOW: |
1557 | if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6) |
1558 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1559 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1560 | fallthrough; |
1561 | case AH_ESP_V6_FLOW: |
1562 | if (bp->rss_hash_cfg & |
1563 | (VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | |
1564 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6)) |
1565 | cmd->data |= RXH_IP_SRC | RXH_IP_DST | |
1566 | RXH_L4_B_0_1 | RXH_L4_B_2_3; |
1567 | fallthrough; |
1568 | case SCTP_V6_FLOW: |
1569 | case AH_V6_FLOW: |
1570 | case ESP_V6_FLOW: |
1571 | case IPV6_FLOW: |
1572 | cmd->data |= get_ethtool_ipv6_rss(bp); |
1573 | break; |
1574 | } |
1575 | return 0; |
1576 | } |
1577 | |
1578 | #define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) |
1579 | #define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST) |
1580 | |
1581 | static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd) |
1582 | { |
1583 | u32 = bp->rss_hash_cfg; |
1584 | int tuple, rc = 0; |
1585 | |
1586 | if (cmd->data == RXH_4TUPLE) |
1587 | tuple = 4; |
1588 | else if (cmd->data == RXH_2TUPLE) |
1589 | tuple = 2; |
1590 | else if (!cmd->data) |
1591 | tuple = 0; |
1592 | else |
1593 | return -EINVAL; |
1594 | |
1595 | if (cmd->flow_type == TCP_V4_FLOW) { |
1596 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; |
1597 | if (tuple == 4) |
1598 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4; |
1599 | } else if (cmd->flow_type == UDP_V4_FLOW) { |
1600 | if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP)) |
1601 | return -EINVAL; |
1602 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; |
1603 | if (tuple == 4) |
1604 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4; |
1605 | } else if (cmd->flow_type == TCP_V6_FLOW) { |
1606 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; |
1607 | if (tuple == 4) |
1608 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; |
1609 | } else if (cmd->flow_type == UDP_V6_FLOW) { |
1610 | if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP)) |
1611 | return -EINVAL; |
1612 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; |
1613 | if (tuple == 4) |
1614 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; |
1615 | } else if (cmd->flow_type == AH_ESP_V4_FLOW) { |
1616 | if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V4_RSS_CAP) || |
1617 | !(bp->rss_cap & BNXT_RSS_CAP_ESP_V4_RSS_CAP))) |
1618 | return -EINVAL; |
1619 | rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | |
1620 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4); |
1621 | if (tuple == 4) |
1622 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 | |
1623 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4; |
1624 | } else if (cmd->flow_type == AH_ESP_V6_FLOW) { |
1625 | if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V6_RSS_CAP) || |
1626 | !(bp->rss_cap & BNXT_RSS_CAP_ESP_V6_RSS_CAP))) |
1627 | return -EINVAL; |
1628 | rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | |
1629 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6); |
1630 | if (tuple == 4) |
1631 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 | |
1632 | VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6; |
1633 | } else if (tuple == 4) { |
1634 | return -EINVAL; |
1635 | } |
1636 | |
1637 | switch (cmd->flow_type) { |
1638 | case TCP_V4_FLOW: |
1639 | case UDP_V4_FLOW: |
1640 | case SCTP_V4_FLOW: |
1641 | case AH_ESP_V4_FLOW: |
1642 | case AH_V4_FLOW: |
1643 | case ESP_V4_FLOW: |
1644 | case IPV4_FLOW: |
1645 | if (tuple == 2) |
1646 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; |
1647 | else if (!tuple) |
1648 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4; |
1649 | break; |
1650 | |
1651 | case TCP_V6_FLOW: |
1652 | case UDP_V6_FLOW: |
1653 | case SCTP_V6_FLOW: |
1654 | case AH_ESP_V6_FLOW: |
1655 | case AH_V6_FLOW: |
1656 | case ESP_V6_FLOW: |
1657 | case IPV6_FLOW: |
1658 | if (tuple == 2) |
1659 | rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; |
1660 | else if (!tuple) |
1661 | rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6; |
1662 | break; |
1663 | } |
1664 | |
1665 | if (bp->rss_hash_cfg == rss_hash_cfg) |
1666 | return 0; |
1667 | |
1668 | if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA) |
1669 | bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg; |
1670 | bp->rss_hash_cfg = rss_hash_cfg; |
1671 | if (netif_running(dev: bp->dev)) { |
1672 | bnxt_close_nic(bp, false, false); |
1673 | rc = bnxt_open_nic(bp, false, false); |
1674 | } |
1675 | return rc; |
1676 | } |
1677 | |
1678 | static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, |
1679 | u32 *rule_locs) |
1680 | { |
1681 | struct bnxt *bp = netdev_priv(dev); |
1682 | int rc = 0; |
1683 | |
1684 | switch (cmd->cmd) { |
1685 | case ETHTOOL_GRXRINGS: |
1686 | cmd->data = bp->rx_nr_rings; |
1687 | break; |
1688 | |
1689 | case ETHTOOL_GRXCLSRLCNT: |
1690 | cmd->rule_cnt = bp->ntp_fltr_count; |
1691 | cmd->data = bp->max_fltr | RX_CLS_LOC_SPECIAL; |
1692 | break; |
1693 | |
1694 | case ETHTOOL_GRXCLSRLALL: |
1695 | rc = bnxt_grxclsrlall(bp, cmd, rule_locs: (u32 *)rule_locs); |
1696 | break; |
1697 | |
1698 | case ETHTOOL_GRXCLSRULE: |
1699 | rc = bnxt_grxclsrule(bp, cmd); |
1700 | break; |
1701 | |
1702 | case ETHTOOL_GRXFH: |
1703 | rc = bnxt_grxfh(bp, cmd); |
1704 | break; |
1705 | |
1706 | default: |
1707 | rc = -EOPNOTSUPP; |
1708 | break; |
1709 | } |
1710 | |
1711 | return rc; |
1712 | } |
1713 | |
1714 | static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
1715 | { |
1716 | struct bnxt *bp = netdev_priv(dev); |
1717 | int rc; |
1718 | |
1719 | switch (cmd->cmd) { |
1720 | case ETHTOOL_SRXFH: |
1721 | rc = bnxt_srxfh(bp, cmd); |
1722 | break; |
1723 | |
1724 | case ETHTOOL_SRXCLSRLINS: |
1725 | rc = bnxt_srxclsrlins(bp, cmd); |
1726 | break; |
1727 | |
1728 | case ETHTOOL_SRXCLSRLDEL: |
1729 | rc = bnxt_srxclsrldel(bp, cmd); |
1730 | break; |
1731 | |
1732 | default: |
1733 | rc = -EOPNOTSUPP; |
1734 | break; |
1735 | } |
1736 | return rc; |
1737 | } |
1738 | |
1739 | u32 bnxt_get_rxfh_indir_size(struct net_device *dev) |
1740 | { |
1741 | struct bnxt *bp = netdev_priv(dev); |
1742 | |
1743 | if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) |
1744 | return bnxt_get_nr_rss_ctxs(bp, rx_rings: bp->rx_nr_rings) * |
1745 | BNXT_RSS_TABLE_ENTRIES_P5; |
1746 | return HW_HASH_INDEX_SIZE; |
1747 | } |
1748 | |
1749 | static u32 bnxt_get_rxfh_key_size(struct net_device *dev) |
1750 | { |
1751 | return HW_HASH_KEY_SIZE; |
1752 | } |
1753 | |
1754 | static int bnxt_get_rxfh(struct net_device *dev, |
1755 | struct ethtool_rxfh_param *rxfh) |
1756 | { |
1757 | struct bnxt *bp = netdev_priv(dev); |
1758 | struct bnxt_vnic_info *vnic; |
1759 | u32 i, tbl_size; |
1760 | |
1761 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
1762 | |
1763 | if (!bp->vnic_info) |
1764 | return 0; |
1765 | |
1766 | vnic = &bp->vnic_info[BNXT_VNIC_DEFAULT]; |
1767 | if (rxfh->indir && bp->rss_indir_tbl) { |
1768 | tbl_size = bnxt_get_rxfh_indir_size(dev); |
1769 | for (i = 0; i < tbl_size; i++) |
1770 | rxfh->indir[i] = bp->rss_indir_tbl[i]; |
1771 | } |
1772 | |
1773 | if (rxfh->key && vnic->rss_hash_key) |
1774 | memcpy(rxfh->key, vnic->rss_hash_key, HW_HASH_KEY_SIZE); |
1775 | |
1776 | return 0; |
1777 | } |
1778 | |
1779 | static int bnxt_set_rxfh(struct net_device *dev, |
1780 | struct ethtool_rxfh_param *rxfh, |
1781 | struct netlink_ext_ack *extack) |
1782 | { |
1783 | struct bnxt *bp = netdev_priv(dev); |
1784 | int rc = 0; |
1785 | |
1786 | if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) |
1787 | return -EOPNOTSUPP; |
1788 | |
1789 | if (rxfh->key) { |
1790 | memcpy(bp->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE); |
1791 | bp->rss_hash_key_updated = true; |
1792 | } |
1793 | |
1794 | if (rxfh->indir) { |
1795 | u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev); |
1796 | |
1797 | for (i = 0; i < tbl_size; i++) |
1798 | bp->rss_indir_tbl[i] = rxfh->indir[i]; |
1799 | pad = bp->rss_indir_tbl_entries - tbl_size; |
1800 | if (pad) |
1801 | memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16)); |
1802 | } |
1803 | bnxt_clear_usr_fltrs(bp, all: false); |
1804 | if (netif_running(dev: bp->dev)) { |
1805 | bnxt_close_nic(bp, false, false); |
1806 | rc = bnxt_open_nic(bp, false, false); |
1807 | } |
1808 | return rc; |
1809 | } |
1810 | |
1811 | static void bnxt_get_drvinfo(struct net_device *dev, |
1812 | struct ethtool_drvinfo *info) |
1813 | { |
1814 | struct bnxt *bp = netdev_priv(dev); |
1815 | |
1816 | strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); |
1817 | strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version)); |
1818 | strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); |
1819 | info->n_stats = bnxt_get_num_stats(bp); |
1820 | info->testinfo_len = bp->num_tests; |
1821 | /* TODO CHIMP_FW: eeprom dump details */ |
1822 | info->eedump_len = 0; |
1823 | /* TODO CHIMP FW: reg dump details */ |
1824 | info->regdump_len = 0; |
1825 | } |
1826 | |
1827 | static int bnxt_get_regs_len(struct net_device *dev) |
1828 | { |
1829 | struct bnxt *bp = netdev_priv(dev); |
1830 | int reg_len; |
1831 | |
1832 | if (!BNXT_PF(bp)) |
1833 | return -EOPNOTSUPP; |
1834 | |
1835 | reg_len = BNXT_PXP_REG_LEN; |
1836 | |
1837 | if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED) |
1838 | reg_len += sizeof(struct pcie_ctx_hw_stats); |
1839 | |
1840 | return reg_len; |
1841 | } |
1842 | |
1843 | static void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs, |
1844 | void *_p) |
1845 | { |
1846 | struct pcie_ctx_hw_stats *hw_pcie_stats; |
1847 | struct hwrm_pcie_qstats_input *req; |
1848 | struct bnxt *bp = netdev_priv(dev); |
1849 | dma_addr_t hw_pcie_stats_addr; |
1850 | int rc; |
1851 | |
1852 | regs->version = 0; |
1853 | bnxt_dbg_hwrm_rd_reg(bp, reg_off: 0, BNXT_PXP_REG_LEN / 4, reg_buf: _p); |
1854 | |
1855 | if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)) |
1856 | return; |
1857 | |
1858 | if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS)) |
1859 | return; |
1860 | |
1861 | hw_pcie_stats = hwrm_req_dma_slice(bp, req, size: sizeof(*hw_pcie_stats), |
1862 | dma: &hw_pcie_stats_addr); |
1863 | if (!hw_pcie_stats) { |
1864 | hwrm_req_drop(bp, req); |
1865 | return; |
1866 | } |
1867 | |
1868 | regs->version = 1; |
1869 | hwrm_req_hold(bp, req); /* hold on to slice */ |
1870 | req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats)); |
1871 | req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr); |
1872 | rc = hwrm_req_send(bp, req); |
1873 | if (!rc) { |
1874 | __le64 *src = (__le64 *)hw_pcie_stats; |
1875 | u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN); |
1876 | int i; |
1877 | |
1878 | for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++) |
1879 | dst[i] = le64_to_cpu(src[i]); |
1880 | } |
1881 | hwrm_req_drop(bp, req); |
1882 | } |
1883 | |
1884 | static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
1885 | { |
1886 | struct bnxt *bp = netdev_priv(dev); |
1887 | |
1888 | wol->supported = 0; |
1889 | wol->wolopts = 0; |
1890 | memset(&wol->sopass, 0, sizeof(wol->sopass)); |
1891 | if (bp->flags & BNXT_FLAG_WOL_CAP) { |
1892 | wol->supported = WAKE_MAGIC; |
1893 | if (bp->wol) |
1894 | wol->wolopts = WAKE_MAGIC; |
1895 | } |
1896 | } |
1897 | |
1898 | static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
1899 | { |
1900 | struct bnxt *bp = netdev_priv(dev); |
1901 | |
1902 | if (wol->wolopts & ~WAKE_MAGIC) |
1903 | return -EINVAL; |
1904 | |
1905 | if (wol->wolopts & WAKE_MAGIC) { |
1906 | if (!(bp->flags & BNXT_FLAG_WOL_CAP)) |
1907 | return -EINVAL; |
1908 | if (!bp->wol) { |
1909 | if (bnxt_hwrm_alloc_wol_fltr(bp)) |
1910 | return -EBUSY; |
1911 | bp->wol = 1; |
1912 | } |
1913 | } else { |
1914 | if (bp->wol) { |
1915 | if (bnxt_hwrm_free_wol_fltr(bp)) |
1916 | return -EBUSY; |
1917 | bp->wol = 0; |
1918 | } |
1919 | } |
1920 | return 0; |
1921 | } |
1922 | |
1923 | /* TODO: support 25GB, 40GB, 50GB with different cable type */ |
1924 | void _bnxt_fw_to_linkmode(unsigned long *mode, u16 fw_speeds) |
1925 | { |
1926 | linkmode_zero(dst: mode); |
1927 | |
1928 | if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB) |
1929 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_100baseT_Full_BIT, addr: mode); |
1930 | if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB) |
1931 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Full_BIT, addr: mode); |
1932 | if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB) |
1933 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_2500baseX_Full_BIT, addr: mode); |
1934 | if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB) |
1935 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, addr: mode); |
1936 | if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB) |
1937 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, addr: mode); |
1938 | } |
1939 | |
1940 | enum bnxt_media_type { |
1941 | BNXT_MEDIA_UNKNOWN = 0, |
1942 | BNXT_MEDIA_TP, |
1943 | BNXT_MEDIA_CR, |
1944 | BNXT_MEDIA_SR, |
1945 | BNXT_MEDIA_LR_ER_FR, |
1946 | BNXT_MEDIA_KR, |
1947 | BNXT_MEDIA_KX, |
1948 | BNXT_MEDIA_X, |
1949 | __BNXT_MEDIA_END, |
1950 | }; |
1951 | |
1952 | static const enum bnxt_media_type bnxt_phy_types[] = { |
1953 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASECR] = BNXT_MEDIA_CR, |
1954 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR4] = BNXT_MEDIA_KR, |
1955 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASELR] = BNXT_MEDIA_LR_ER_FR, |
1956 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASESR] = BNXT_MEDIA_SR, |
1957 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR2] = BNXT_MEDIA_KR, |
1958 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKX] = BNXT_MEDIA_KX, |
1959 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASEKR] = BNXT_MEDIA_KR, |
1960 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASET] = BNXT_MEDIA_TP, |
1961 | [PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE] = BNXT_MEDIA_TP, |
1962 | [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_L] = BNXT_MEDIA_CR, |
1963 | [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_S] = BNXT_MEDIA_CR, |
1964 | [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASECR_CA_N] = BNXT_MEDIA_CR, |
1965 | [PORT_PHY_QCFG_RESP_PHY_TYPE_25G_BASESR] = BNXT_MEDIA_SR, |
1966 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR4] = BNXT_MEDIA_CR, |
1967 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR4] = BNXT_MEDIA_SR, |
1968 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR4] = BNXT_MEDIA_LR_ER_FR, |
1969 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER4] = BNXT_MEDIA_LR_ER_FR, |
1970 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR10] = BNXT_MEDIA_SR, |
1971 | [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASECR4] = BNXT_MEDIA_CR, |
1972 | [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASESR4] = BNXT_MEDIA_SR, |
1973 | [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASELR4] = BNXT_MEDIA_LR_ER_FR, |
1974 | [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_BASEER4] = BNXT_MEDIA_LR_ER_FR, |
1975 | [PORT_PHY_QCFG_RESP_PHY_TYPE_40G_ACTIVE_CABLE] = BNXT_MEDIA_SR, |
1976 | [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASET] = BNXT_MEDIA_TP, |
1977 | [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASESX] = BNXT_MEDIA_X, |
1978 | [PORT_PHY_QCFG_RESP_PHY_TYPE_1G_BASECX] = BNXT_MEDIA_X, |
1979 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR4] = BNXT_MEDIA_CR, |
1980 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4] = BNXT_MEDIA_SR, |
1981 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4] = BNXT_MEDIA_LR_ER_FR, |
1982 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4] = BNXT_MEDIA_LR_ER_FR, |
1983 | [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASECR] = BNXT_MEDIA_CR, |
1984 | [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASESR] = BNXT_MEDIA_SR, |
1985 | [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASELR] = BNXT_MEDIA_LR_ER_FR, |
1986 | [PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASEER] = BNXT_MEDIA_LR_ER_FR, |
1987 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR2] = BNXT_MEDIA_CR, |
1988 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] = BNXT_MEDIA_SR, |
1989 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] = BNXT_MEDIA_LR_ER_FR, |
1990 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] = BNXT_MEDIA_LR_ER_FR, |
1991 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] = BNXT_MEDIA_CR, |
1992 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] = BNXT_MEDIA_SR, |
1993 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] = BNXT_MEDIA_LR_ER_FR, |
1994 | [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] = BNXT_MEDIA_LR_ER_FR, |
1995 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] = BNXT_MEDIA_CR, |
1996 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] = BNXT_MEDIA_SR, |
1997 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] = BNXT_MEDIA_LR_ER_FR, |
1998 | [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] = BNXT_MEDIA_LR_ER_FR, |
1999 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] = BNXT_MEDIA_CR, |
2000 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] = BNXT_MEDIA_SR, |
2001 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] = BNXT_MEDIA_LR_ER_FR, |
2002 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] = BNXT_MEDIA_LR_ER_FR, |
2003 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] = BNXT_MEDIA_CR, |
2004 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] = BNXT_MEDIA_SR, |
2005 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] = BNXT_MEDIA_LR_ER_FR, |
2006 | [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] = BNXT_MEDIA_LR_ER_FR, |
2007 | }; |
2008 | |
2009 | static enum bnxt_media_type |
2010 | bnxt_get_media(struct bnxt_link_info *link_info) |
2011 | { |
2012 | switch (link_info->media_type) { |
2013 | case PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP: |
2014 | return BNXT_MEDIA_TP; |
2015 | case PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC: |
2016 | return BNXT_MEDIA_CR; |
2017 | default: |
2018 | if (link_info->phy_type < ARRAY_SIZE(bnxt_phy_types)) |
2019 | return bnxt_phy_types[link_info->phy_type]; |
2020 | return BNXT_MEDIA_UNKNOWN; |
2021 | } |
2022 | } |
2023 | |
2024 | enum bnxt_link_speed_indices { |
2025 | BNXT_LINK_SPEED_UNKNOWN = 0, |
2026 | BNXT_LINK_SPEED_100MB_IDX, |
2027 | BNXT_LINK_SPEED_1GB_IDX, |
2028 | BNXT_LINK_SPEED_10GB_IDX, |
2029 | BNXT_LINK_SPEED_25GB_IDX, |
2030 | BNXT_LINK_SPEED_40GB_IDX, |
2031 | BNXT_LINK_SPEED_50GB_IDX, |
2032 | BNXT_LINK_SPEED_100GB_IDX, |
2033 | BNXT_LINK_SPEED_200GB_IDX, |
2034 | BNXT_LINK_SPEED_400GB_IDX, |
2035 | __BNXT_LINK_SPEED_END |
2036 | }; |
2037 | |
2038 | static enum bnxt_link_speed_indices bnxt_fw_speed_idx(u16 speed) |
2039 | { |
2040 | switch (speed) { |
2041 | case BNXT_LINK_SPEED_100MB: return BNXT_LINK_SPEED_100MB_IDX; |
2042 | case BNXT_LINK_SPEED_1GB: return BNXT_LINK_SPEED_1GB_IDX; |
2043 | case BNXT_LINK_SPEED_10GB: return BNXT_LINK_SPEED_10GB_IDX; |
2044 | case BNXT_LINK_SPEED_25GB: return BNXT_LINK_SPEED_25GB_IDX; |
2045 | case BNXT_LINK_SPEED_40GB: return BNXT_LINK_SPEED_40GB_IDX; |
2046 | case BNXT_LINK_SPEED_50GB: |
2047 | case BNXT_LINK_SPEED_50GB_PAM4: |
2048 | return BNXT_LINK_SPEED_50GB_IDX; |
2049 | case BNXT_LINK_SPEED_100GB: |
2050 | case BNXT_LINK_SPEED_100GB_PAM4: |
2051 | case BNXT_LINK_SPEED_100GB_PAM4_112: |
2052 | return BNXT_LINK_SPEED_100GB_IDX; |
2053 | case BNXT_LINK_SPEED_200GB: |
2054 | case BNXT_LINK_SPEED_200GB_PAM4: |
2055 | case BNXT_LINK_SPEED_200GB_PAM4_112: |
2056 | return BNXT_LINK_SPEED_200GB_IDX; |
2057 | case BNXT_LINK_SPEED_400GB: |
2058 | case BNXT_LINK_SPEED_400GB_PAM4: |
2059 | case BNXT_LINK_SPEED_400GB_PAM4_112: |
2060 | return BNXT_LINK_SPEED_400GB_IDX; |
2061 | default: return BNXT_LINK_SPEED_UNKNOWN; |
2062 | } |
2063 | } |
2064 | |
2065 | static const enum ethtool_link_mode_bit_indices |
2066 | bnxt_link_modes[__BNXT_LINK_SPEED_END][BNXT_SIG_MODE_MAX][__BNXT_MEDIA_END] = { |
2067 | [BNXT_LINK_SPEED_100MB_IDX] = { |
2068 | { |
2069 | [BNXT_MEDIA_TP] = ETHTOOL_LINK_MODE_100baseT_Full_BIT, |
2070 | }, |
2071 | }, |
2072 | [BNXT_LINK_SPEED_1GB_IDX] = { |
2073 | { |
2074 | [BNXT_MEDIA_TP] = ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
2075 | /* historically baseT, but DAC is more correctly baseX */ |
2076 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
2077 | [BNXT_MEDIA_KX] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, |
2078 | [BNXT_MEDIA_X] = ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
2079 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, |
2080 | }, |
2081 | }, |
2082 | [BNXT_LINK_SPEED_10GB_IDX] = { |
2083 | { |
2084 | [BNXT_MEDIA_TP] = ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
2085 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, |
2086 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, |
2087 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, |
2088 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, |
2089 | [BNXT_MEDIA_KX] = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, |
2090 | }, |
2091 | }, |
2092 | [BNXT_LINK_SPEED_25GB_IDX] = { |
2093 | { |
2094 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, |
2095 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, |
2096 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, |
2097 | }, |
2098 | }, |
2099 | [BNXT_LINK_SPEED_40GB_IDX] = { |
2100 | { |
2101 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, |
2102 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, |
2103 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, |
2104 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, |
2105 | }, |
2106 | }, |
2107 | [BNXT_LINK_SPEED_50GB_IDX] = { |
2108 | [BNXT_SIG_MODE_NRZ] = { |
2109 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, |
2110 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, |
2111 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, |
2112 | }, |
2113 | [BNXT_SIG_MODE_PAM4] = { |
2114 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, |
2115 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, |
2116 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, |
2117 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, |
2118 | }, |
2119 | }, |
2120 | [BNXT_LINK_SPEED_100GB_IDX] = { |
2121 | [BNXT_SIG_MODE_NRZ] = { |
2122 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, |
2123 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, |
2124 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, |
2125 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, |
2126 | }, |
2127 | [BNXT_SIG_MODE_PAM4] = { |
2128 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, |
2129 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, |
2130 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, |
2131 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, |
2132 | }, |
2133 | [BNXT_SIG_MODE_PAM4_112] = { |
2134 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, |
2135 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, |
2136 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, |
2137 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, |
2138 | }, |
2139 | }, |
2140 | [BNXT_LINK_SPEED_200GB_IDX] = { |
2141 | [BNXT_SIG_MODE_PAM4] = { |
2142 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, |
2143 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, |
2144 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, |
2145 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, |
2146 | }, |
2147 | [BNXT_SIG_MODE_PAM4_112] = { |
2148 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, |
2149 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, |
2150 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, |
2151 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, |
2152 | }, |
2153 | }, |
2154 | [BNXT_LINK_SPEED_400GB_IDX] = { |
2155 | [BNXT_SIG_MODE_PAM4] = { |
2156 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, |
2157 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, |
2158 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, |
2159 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, |
2160 | }, |
2161 | [BNXT_SIG_MODE_PAM4_112] = { |
2162 | [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, |
2163 | [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, |
2164 | [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, |
2165 | [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, |
2166 | }, |
2167 | }, |
2168 | }; |
2169 | |
2170 | #define BNXT_LINK_MODE_UNKNOWN -1 |
2171 | |
2172 | static enum ethtool_link_mode_bit_indices |
2173 | bnxt_get_link_mode(struct bnxt_link_info *link_info) |
2174 | { |
2175 | enum ethtool_link_mode_bit_indices link_mode; |
2176 | enum bnxt_link_speed_indices speed; |
2177 | enum bnxt_media_type media; |
2178 | u8 sig_mode; |
2179 | |
2180 | if (link_info->phy_link_status != BNXT_LINK_LINK) |
2181 | return BNXT_LINK_MODE_UNKNOWN; |
2182 | |
2183 | media = bnxt_get_media(link_info); |
2184 | if (BNXT_AUTO_MODE(link_info->auto_mode)) { |
2185 | speed = bnxt_fw_speed_idx(speed: link_info->link_speed); |
2186 | sig_mode = link_info->active_fec_sig_mode & |
2187 | PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK; |
2188 | } else { |
2189 | speed = bnxt_fw_speed_idx(speed: link_info->req_link_speed); |
2190 | sig_mode = link_info->req_signal_mode; |
2191 | } |
2192 | if (sig_mode >= BNXT_SIG_MODE_MAX) |
2193 | return BNXT_LINK_MODE_UNKNOWN; |
2194 | |
2195 | /* Note ETHTOOL_LINK_MODE_10baseT_Half_BIT == 0 is a legal Linux |
2196 | * link mode, but since no such devices exist, the zeroes in the |
2197 | * map can be conveniently used to represent unknown link modes. |
2198 | */ |
2199 | link_mode = bnxt_link_modes[speed][sig_mode][media]; |
2200 | if (!link_mode) |
2201 | return BNXT_LINK_MODE_UNKNOWN; |
2202 | |
2203 | switch (link_mode) { |
2204 | case ETHTOOL_LINK_MODE_100baseT_Full_BIT: |
2205 | if (~link_info->duplex & BNXT_LINK_DUPLEX_FULL) |
2206 | link_mode = ETHTOOL_LINK_MODE_100baseT_Half_BIT; |
2207 | break; |
2208 | case ETHTOOL_LINK_MODE_1000baseT_Full_BIT: |
2209 | if (~link_info->duplex & BNXT_LINK_DUPLEX_FULL) |
2210 | link_mode = ETHTOOL_LINK_MODE_1000baseT_Half_BIT; |
2211 | break; |
2212 | default: |
2213 | break; |
2214 | } |
2215 | |
2216 | return link_mode; |
2217 | } |
2218 | |
2219 | static void bnxt_get_ethtool_modes(struct bnxt_link_info *link_info, |
2220 | struct ethtool_link_ksettings *lk_ksettings) |
2221 | { |
2222 | struct bnxt *bp = container_of(link_info, struct bnxt, link_info); |
2223 | |
2224 | if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) { |
2225 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Pause_BIT, |
2226 | addr: lk_ksettings->link_modes.supported); |
2227 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Asym_Pause_BIT, |
2228 | addr: lk_ksettings->link_modes.supported); |
2229 | } |
2230 | |
2231 | if (link_info->support_auto_speeds || link_info->support_auto_speeds2 || |
2232 | link_info->support_pam4_auto_speeds) |
2233 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Autoneg_BIT, |
2234 | addr: lk_ksettings->link_modes.supported); |
2235 | |
2236 | if (~link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) |
2237 | return; |
2238 | |
2239 | if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_RX) |
2240 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Pause_BIT, |
2241 | addr: lk_ksettings->link_modes.advertising); |
2242 | if (hweight8(link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) == 1) |
2243 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Asym_Pause_BIT, |
2244 | addr: lk_ksettings->link_modes.advertising); |
2245 | if (link_info->lp_pause & BNXT_LINK_PAUSE_RX) |
2246 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Pause_BIT, |
2247 | addr: lk_ksettings->link_modes.lp_advertising); |
2248 | if (hweight8(link_info->lp_pause & BNXT_LINK_PAUSE_BOTH) == 1) |
2249 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Asym_Pause_BIT, |
2250 | addr: lk_ksettings->link_modes.lp_advertising); |
2251 | } |
2252 | |
2253 | static const u16 bnxt_nrz_speed_masks[] = { |
2254 | [BNXT_LINK_SPEED_100MB_IDX] = BNXT_LINK_SPEED_MSK_100MB, |
2255 | [BNXT_LINK_SPEED_1GB_IDX] = BNXT_LINK_SPEED_MSK_1GB, |
2256 | [BNXT_LINK_SPEED_10GB_IDX] = BNXT_LINK_SPEED_MSK_10GB, |
2257 | [BNXT_LINK_SPEED_25GB_IDX] = BNXT_LINK_SPEED_MSK_25GB, |
2258 | [BNXT_LINK_SPEED_40GB_IDX] = BNXT_LINK_SPEED_MSK_40GB, |
2259 | [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEED_MSK_50GB, |
2260 | [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEED_MSK_100GB, |
2261 | [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */ |
2262 | }; |
2263 | |
2264 | static const u16 bnxt_pam4_speed_masks[] = { |
2265 | [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_50GB, |
2266 | [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_100GB, |
2267 | [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_200GB, |
2268 | [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */ |
2269 | }; |
2270 | |
2271 | static const u16 bnxt_nrz_speeds2_masks[] = { |
2272 | [BNXT_LINK_SPEED_1GB_IDX] = BNXT_LINK_SPEEDS2_MSK_1GB, |
2273 | [BNXT_LINK_SPEED_10GB_IDX] = BNXT_LINK_SPEEDS2_MSK_10GB, |
2274 | [BNXT_LINK_SPEED_25GB_IDX] = BNXT_LINK_SPEEDS2_MSK_25GB, |
2275 | [BNXT_LINK_SPEED_40GB_IDX] = BNXT_LINK_SPEEDS2_MSK_40GB, |
2276 | [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB, |
2277 | [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB, |
2278 | [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */ |
2279 | }; |
2280 | |
2281 | static const u16 bnxt_pam4_speeds2_masks[] = { |
2282 | [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB_PAM4, |
2283 | [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4, |
2284 | [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4, |
2285 | [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4, |
2286 | }; |
2287 | |
2288 | static const u16 bnxt_pam4_112_speeds2_masks[] = { |
2289 | [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112, |
2290 | [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112, |
2291 | [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112, |
2292 | }; |
2293 | |
2294 | static enum bnxt_link_speed_indices |
2295 | bnxt_encoding_speed_idx(u8 sig_mode, u16 phy_flags, u16 speed_msk) |
2296 | { |
2297 | const u16 *speeds; |
2298 | int idx, len; |
2299 | |
2300 | switch (sig_mode) { |
2301 | case BNXT_SIG_MODE_NRZ: |
2302 | if (phy_flags & BNXT_PHY_FL_SPEEDS2) { |
2303 | speeds = bnxt_nrz_speeds2_masks; |
2304 | len = ARRAY_SIZE(bnxt_nrz_speeds2_masks); |
2305 | } else { |
2306 | speeds = bnxt_nrz_speed_masks; |
2307 | len = ARRAY_SIZE(bnxt_nrz_speed_masks); |
2308 | } |
2309 | break; |
2310 | case BNXT_SIG_MODE_PAM4: |
2311 | if (phy_flags & BNXT_PHY_FL_SPEEDS2) { |
2312 | speeds = bnxt_pam4_speeds2_masks; |
2313 | len = ARRAY_SIZE(bnxt_pam4_speeds2_masks); |
2314 | } else { |
2315 | speeds = bnxt_pam4_speed_masks; |
2316 | len = ARRAY_SIZE(bnxt_pam4_speed_masks); |
2317 | } |
2318 | break; |
2319 | case BNXT_SIG_MODE_PAM4_112: |
2320 | speeds = bnxt_pam4_112_speeds2_masks; |
2321 | len = ARRAY_SIZE(bnxt_pam4_112_speeds2_masks); |
2322 | break; |
2323 | default: |
2324 | return BNXT_LINK_SPEED_UNKNOWN; |
2325 | } |
2326 | |
2327 | for (idx = 0; idx < len; idx++) { |
2328 | if (speeds[idx] == speed_msk) |
2329 | return idx; |
2330 | } |
2331 | |
2332 | return BNXT_LINK_SPEED_UNKNOWN; |
2333 | } |
2334 | |
2335 | #define BNXT_FW_SPEED_MSK_BITS 16 |
2336 | |
2337 | static void |
2338 | __bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media, |
2339 | u8 sig_mode, u16 phy_flags, unsigned long *et_mask) |
2340 | { |
2341 | enum ethtool_link_mode_bit_indices link_mode; |
2342 | enum bnxt_link_speed_indices speed; |
2343 | u8 bit; |
2344 | |
2345 | for_each_set_bit(bit, &fw_mask, BNXT_FW_SPEED_MSK_BITS) { |
2346 | speed = bnxt_encoding_speed_idx(sig_mode, phy_flags, speed_msk: 1 << bit); |
2347 | if (!speed) |
2348 | continue; |
2349 | |
2350 | link_mode = bnxt_link_modes[speed][sig_mode][media]; |
2351 | if (!link_mode) |
2352 | continue; |
2353 | |
2354 | linkmode_set_bit(nr: link_mode, addr: et_mask); |
2355 | } |
2356 | } |
2357 | |
2358 | static void |
2359 | bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media, |
2360 | u8 sig_mode, u16 phy_flags, unsigned long *et_mask) |
2361 | { |
2362 | if (media) { |
2363 | __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, |
2364 | et_mask); |
2365 | return; |
2366 | } |
2367 | |
2368 | /* list speeds for all media if unknown */ |
2369 | for (media = 1; media < __BNXT_MEDIA_END; media++) |
2370 | __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags, |
2371 | et_mask); |
2372 | } |
2373 | |
2374 | static void |
2375 | bnxt_get_all_ethtool_support_speeds(struct bnxt_link_info *link_info, |
2376 | enum bnxt_media_type media, |
2377 | struct ethtool_link_ksettings *lk_ksettings) |
2378 | { |
2379 | struct bnxt *bp = container_of(link_info, struct bnxt, link_info); |
2380 | u16 sp_nrz, sp_pam4, sp_pam4_112 = 0; |
2381 | u16 phy_flags = bp->phy_flags; |
2382 | |
2383 | if (phy_flags & BNXT_PHY_FL_SPEEDS2) { |
2384 | sp_nrz = link_info->support_speeds2; |
2385 | sp_pam4 = link_info->support_speeds2; |
2386 | sp_pam4_112 = link_info->support_speeds2; |
2387 | } else { |
2388 | sp_nrz = link_info->support_speeds; |
2389 | sp_pam4 = link_info->support_pam4_speeds; |
2390 | } |
2391 | bnxt_get_ethtool_speeds(fw_mask: sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags, |
2392 | et_mask: lk_ksettings->link_modes.supported); |
2393 | bnxt_get_ethtool_speeds(fw_mask: sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags, |
2394 | et_mask: lk_ksettings->link_modes.supported); |
2395 | bnxt_get_ethtool_speeds(fw_mask: sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112, |
2396 | phy_flags, et_mask: lk_ksettings->link_modes.supported); |
2397 | } |
2398 | |
2399 | static void |
2400 | bnxt_get_all_ethtool_adv_speeds(struct bnxt_link_info *link_info, |
2401 | enum bnxt_media_type media, |
2402 | struct ethtool_link_ksettings *lk_ksettings) |
2403 | { |
2404 | struct bnxt *bp = container_of(link_info, struct bnxt, link_info); |
2405 | u16 sp_nrz, sp_pam4, sp_pam4_112 = 0; |
2406 | u16 phy_flags = bp->phy_flags; |
2407 | |
2408 | sp_nrz = link_info->advertising; |
2409 | if (phy_flags & BNXT_PHY_FL_SPEEDS2) { |
2410 | sp_pam4 = link_info->advertising; |
2411 | sp_pam4_112 = link_info->advertising; |
2412 | } else { |
2413 | sp_pam4 = link_info->advertising_pam4; |
2414 | } |
2415 | bnxt_get_ethtool_speeds(fw_mask: sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags, |
2416 | et_mask: lk_ksettings->link_modes.advertising); |
2417 | bnxt_get_ethtool_speeds(fw_mask: sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags, |
2418 | et_mask: lk_ksettings->link_modes.advertising); |
2419 | bnxt_get_ethtool_speeds(fw_mask: sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112, |
2420 | phy_flags, et_mask: lk_ksettings->link_modes.advertising); |
2421 | } |
2422 | |
2423 | static void |
2424 | bnxt_get_all_ethtool_lp_speeds(struct bnxt_link_info *link_info, |
2425 | enum bnxt_media_type media, |
2426 | struct ethtool_link_ksettings *lk_ksettings) |
2427 | { |
2428 | struct bnxt *bp = container_of(link_info, struct bnxt, link_info); |
2429 | u16 phy_flags = bp->phy_flags; |
2430 | |
2431 | bnxt_get_ethtool_speeds(fw_mask: link_info->lp_auto_link_speeds, media, |
2432 | BNXT_SIG_MODE_NRZ, phy_flags, |
2433 | et_mask: lk_ksettings->link_modes.lp_advertising); |
2434 | bnxt_get_ethtool_speeds(fw_mask: link_info->lp_auto_pam4_link_speeds, media, |
2435 | BNXT_SIG_MODE_PAM4, phy_flags, |
2436 | et_mask: lk_ksettings->link_modes.lp_advertising); |
2437 | } |
2438 | |
2439 | static void bnxt_update_speed(u32 *delta, bool installed_media, u16 *speeds, |
2440 | u16 speed_msk, const unsigned long *et_mask, |
2441 | enum ethtool_link_mode_bit_indices mode) |
2442 | { |
2443 | bool mode_desired = linkmode_test_bit(nr: mode, addr: et_mask); |
2444 | |
2445 | if (!mode) |
2446 | return; |
2447 | |
2448 | /* enabled speeds for installed media should override */ |
2449 | if (installed_media && mode_desired) { |
2450 | *speeds |= speed_msk; |
2451 | *delta |= speed_msk; |
2452 | return; |
2453 | } |
2454 | |
2455 | /* many to one mapping, only allow one change per fw_speed bit */ |
2456 | if (!(*delta & speed_msk) && (mode_desired == !(*speeds & speed_msk))) { |
2457 | *speeds ^= speed_msk; |
2458 | *delta |= speed_msk; |
2459 | } |
2460 | } |
2461 | |
2462 | static void bnxt_set_ethtool_speeds(struct bnxt_link_info *link_info, |
2463 | const unsigned long *et_mask) |
2464 | { |
2465 | struct bnxt *bp = container_of(link_info, struct bnxt, link_info); |
2466 | u16 const *sp_msks, *sp_pam4_msks, *sp_pam4_112_msks; |
2467 | enum bnxt_media_type media = bnxt_get_media(link_info); |
2468 | u16 *adv, *adv_pam4, *adv_pam4_112 = NULL; |
2469 | u32 delta_pam4_112 = 0; |
2470 | u32 delta_pam4 = 0; |
2471 | u32 delta_nrz = 0; |
2472 | int i, m; |
2473 | |
2474 | adv = &link_info->advertising; |
2475 | if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) { |
2476 | adv_pam4 = &link_info->advertising; |
2477 | adv_pam4_112 = &link_info->advertising; |
2478 | sp_msks = bnxt_nrz_speeds2_masks; |
2479 | sp_pam4_msks = bnxt_pam4_speeds2_masks; |
2480 | sp_pam4_112_msks = bnxt_pam4_112_speeds2_masks; |
2481 | } else { |
2482 | adv_pam4 = &link_info->advertising_pam4; |
2483 | sp_msks = bnxt_nrz_speed_masks; |
2484 | sp_pam4_msks = bnxt_pam4_speed_masks; |
2485 | } |
2486 | for (i = 1; i < __BNXT_LINK_SPEED_END; i++) { |
2487 | /* accept any legal media from user */ |
2488 | for (m = 1; m < __BNXT_MEDIA_END; m++) { |
2489 | bnxt_update_speed(delta: &delta_nrz, installed_media: m == media, |
2490 | speeds: adv, speed_msk: sp_msks[i], et_mask, |
2491 | mode: bnxt_link_modes[i][BNXT_SIG_MODE_NRZ][m]); |
2492 | bnxt_update_speed(delta: &delta_pam4, installed_media: m == media, |
2493 | speeds: adv_pam4, speed_msk: sp_pam4_msks[i], et_mask, |
2494 | mode: bnxt_link_modes[i][BNXT_SIG_MODE_PAM4][m]); |
2495 | if (!adv_pam4_112) |
2496 | continue; |
2497 | |
2498 | bnxt_update_speed(delta: &delta_pam4_112, installed_media: m == media, |
2499 | speeds: adv_pam4_112, speed_msk: sp_pam4_112_msks[i], et_mask, |
2500 | mode: bnxt_link_modes[i][BNXT_SIG_MODE_PAM4_112][m]); |
2501 | } |
2502 | } |
2503 | } |
2504 | |
2505 | static void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info, |
2506 | struct ethtool_link_ksettings *lk_ksettings) |
2507 | { |
2508 | u16 fec_cfg = link_info->fec_cfg; |
2509 | |
2510 | if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) { |
2511 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_NONE_BIT, |
2512 | addr: lk_ksettings->link_modes.advertising); |
2513 | return; |
2514 | } |
2515 | if (fec_cfg & BNXT_FEC_ENC_BASE_R) |
2516 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_BASER_BIT, |
2517 | addr: lk_ksettings->link_modes.advertising); |
2518 | if (fec_cfg & BNXT_FEC_ENC_RS) |
2519 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_RS_BIT, |
2520 | addr: lk_ksettings->link_modes.advertising); |
2521 | if (fec_cfg & BNXT_FEC_ENC_LLRS) |
2522 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_LLRS_BIT, |
2523 | addr: lk_ksettings->link_modes.advertising); |
2524 | } |
2525 | |
2526 | static void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info, |
2527 | struct ethtool_link_ksettings *lk_ksettings) |
2528 | { |
2529 | u16 fec_cfg = link_info->fec_cfg; |
2530 | |
2531 | if (fec_cfg & BNXT_FEC_NONE) { |
2532 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_NONE_BIT, |
2533 | addr: lk_ksettings->link_modes.supported); |
2534 | return; |
2535 | } |
2536 | if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP) |
2537 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_BASER_BIT, |
2538 | addr: lk_ksettings->link_modes.supported); |
2539 | if (fec_cfg & BNXT_FEC_ENC_RS_CAP) |
2540 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_RS_BIT, |
2541 | addr: lk_ksettings->link_modes.supported); |
2542 | if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP) |
2543 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_LLRS_BIT, |
2544 | addr: lk_ksettings->link_modes.supported); |
2545 | } |
2546 | |
2547 | u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) |
2548 | { |
2549 | switch (fw_link_speed) { |
2550 | case BNXT_LINK_SPEED_100MB: |
2551 | return SPEED_100; |
2552 | case BNXT_LINK_SPEED_1GB: |
2553 | return SPEED_1000; |
2554 | case BNXT_LINK_SPEED_2_5GB: |
2555 | return SPEED_2500; |
2556 | case BNXT_LINK_SPEED_10GB: |
2557 | return SPEED_10000; |
2558 | case BNXT_LINK_SPEED_20GB: |
2559 | return SPEED_20000; |
2560 | case BNXT_LINK_SPEED_25GB: |
2561 | return SPEED_25000; |
2562 | case BNXT_LINK_SPEED_40GB: |
2563 | return SPEED_40000; |
2564 | case BNXT_LINK_SPEED_50GB: |
2565 | case BNXT_LINK_SPEED_50GB_PAM4: |
2566 | return SPEED_50000; |
2567 | case BNXT_LINK_SPEED_100GB: |
2568 | case BNXT_LINK_SPEED_100GB_PAM4: |
2569 | case BNXT_LINK_SPEED_100GB_PAM4_112: |
2570 | return SPEED_100000; |
2571 | case BNXT_LINK_SPEED_200GB: |
2572 | case BNXT_LINK_SPEED_200GB_PAM4: |
2573 | case BNXT_LINK_SPEED_200GB_PAM4_112: |
2574 | return SPEED_200000; |
2575 | case BNXT_LINK_SPEED_400GB: |
2576 | case BNXT_LINK_SPEED_400GB_PAM4: |
2577 | case BNXT_LINK_SPEED_400GB_PAM4_112: |
2578 | return SPEED_400000; |
2579 | default: |
2580 | return SPEED_UNKNOWN; |
2581 | } |
2582 | } |
2583 | |
2584 | static void bnxt_get_default_speeds(struct ethtool_link_ksettings *lk_ksettings, |
2585 | struct bnxt_link_info *link_info) |
2586 | { |
2587 | struct ethtool_link_settings *base = &lk_ksettings->base; |
2588 | |
2589 | if (link_info->link_state == BNXT_LINK_STATE_UP) { |
2590 | base->speed = bnxt_fw_to_ethtool_speed(fw_link_speed: link_info->link_speed); |
2591 | base->duplex = DUPLEX_HALF; |
2592 | if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) |
2593 | base->duplex = DUPLEX_FULL; |
2594 | lk_ksettings->lanes = link_info->active_lanes; |
2595 | } else if (!link_info->autoneg) { |
2596 | base->speed = bnxt_fw_to_ethtool_speed(fw_link_speed: link_info->req_link_speed); |
2597 | base->duplex = DUPLEX_HALF; |
2598 | if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) |
2599 | base->duplex = DUPLEX_FULL; |
2600 | } |
2601 | } |
2602 | |
2603 | static int bnxt_get_link_ksettings(struct net_device *dev, |
2604 | struct ethtool_link_ksettings *lk_ksettings) |
2605 | { |
2606 | struct ethtool_link_settings *base = &lk_ksettings->base; |
2607 | enum ethtool_link_mode_bit_indices link_mode; |
2608 | struct bnxt *bp = netdev_priv(dev); |
2609 | struct bnxt_link_info *link_info; |
2610 | enum bnxt_media_type media; |
2611 | |
2612 | ethtool_link_ksettings_zero_link_mode(lk_ksettings, lp_advertising); |
2613 | ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); |
2614 | ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); |
2615 | base->duplex = DUPLEX_UNKNOWN; |
2616 | base->speed = SPEED_UNKNOWN; |
2617 | link_info = &bp->link_info; |
2618 | |
2619 | mutex_lock(&bp->link_lock); |
2620 | bnxt_get_ethtool_modes(link_info, lk_ksettings); |
2621 | media = bnxt_get_media(link_info); |
2622 | bnxt_get_all_ethtool_support_speeds(link_info, media, lk_ksettings); |
2623 | bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings); |
2624 | link_mode = bnxt_get_link_mode(link_info); |
2625 | if (link_mode != BNXT_LINK_MODE_UNKNOWN) |
2626 | ethtool_params_from_link_mode(link_ksettings: lk_ksettings, link_mode); |
2627 | else |
2628 | bnxt_get_default_speeds(lk_ksettings, link_info); |
2629 | |
2630 | if (link_info->autoneg) { |
2631 | bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings); |
2632 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Autoneg_BIT, |
2633 | addr: lk_ksettings->link_modes.advertising); |
2634 | base->autoneg = AUTONEG_ENABLE; |
2635 | bnxt_get_all_ethtool_adv_speeds(link_info, media, lk_ksettings); |
2636 | if (link_info->phy_link_status == BNXT_LINK_LINK) |
2637 | bnxt_get_all_ethtool_lp_speeds(link_info, media, |
2638 | lk_ksettings); |
2639 | } else { |
2640 | base->autoneg = AUTONEG_DISABLE; |
2641 | } |
2642 | |
2643 | base->port = PORT_NONE; |
2644 | if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { |
2645 | base->port = PORT_TP; |
2646 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_TP_BIT, |
2647 | addr: lk_ksettings->link_modes.supported); |
2648 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_TP_BIT, |
2649 | addr: lk_ksettings->link_modes.advertising); |
2650 | } else { |
2651 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FIBRE_BIT, |
2652 | addr: lk_ksettings->link_modes.supported); |
2653 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FIBRE_BIT, |
2654 | addr: lk_ksettings->link_modes.advertising); |
2655 | |
2656 | if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) |
2657 | base->port = PORT_DA; |
2658 | else |
2659 | base->port = PORT_FIBRE; |
2660 | } |
2661 | base->phy_address = link_info->phy_addr; |
2662 | mutex_unlock(lock: &bp->link_lock); |
2663 | |
2664 | return 0; |
2665 | } |
2666 | |
2667 | static int |
2668 | bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes) |
2669 | { |
2670 | struct bnxt *bp = netdev_priv(dev); |
2671 | struct bnxt_link_info *link_info = &bp->link_info; |
2672 | u16 support_pam4_spds = link_info->support_pam4_speeds; |
2673 | u16 support_spds2 = link_info->support_speeds2; |
2674 | u16 support_spds = link_info->support_speeds; |
2675 | u8 sig_mode = BNXT_SIG_MODE_NRZ; |
2676 | u32 lanes_needed = 1; |
2677 | u16 fw_speed = 0; |
2678 | |
2679 | switch (ethtool_speed) { |
2680 | case SPEED_100: |
2681 | if (support_spds & BNXT_LINK_SPEED_MSK_100MB) |
2682 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB; |
2683 | break; |
2684 | case SPEED_1000: |
2685 | if ((support_spds & BNXT_LINK_SPEED_MSK_1GB) || |
2686 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_1GB)) |
2687 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; |
2688 | break; |
2689 | case SPEED_2500: |
2690 | if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB) |
2691 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB; |
2692 | break; |
2693 | case SPEED_10000: |
2694 | if ((support_spds & BNXT_LINK_SPEED_MSK_10GB) || |
2695 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_10GB)) |
2696 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; |
2697 | break; |
2698 | case SPEED_20000: |
2699 | if (support_spds & BNXT_LINK_SPEED_MSK_20GB) { |
2700 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB; |
2701 | lanes_needed = 2; |
2702 | } |
2703 | break; |
2704 | case SPEED_25000: |
2705 | if ((support_spds & BNXT_LINK_SPEED_MSK_25GB) || |
2706 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_25GB)) |
2707 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; |
2708 | break; |
2709 | case SPEED_40000: |
2710 | if ((support_spds & BNXT_LINK_SPEED_MSK_40GB) || |
2711 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_40GB)) { |
2712 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; |
2713 | lanes_needed = 4; |
2714 | } |
2715 | break; |
2716 | case SPEED_50000: |
2717 | if (((support_spds & BNXT_LINK_SPEED_MSK_50GB) || |
2718 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB)) && |
2719 | lanes != 1) { |
2720 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; |
2721 | lanes_needed = 2; |
2722 | } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) { |
2723 | fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; |
2724 | sig_mode = BNXT_SIG_MODE_PAM4; |
2725 | } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB_PAM4) { |
2726 | fw_speed = BNXT_LINK_SPEED_50GB_PAM4; |
2727 | sig_mode = BNXT_SIG_MODE_PAM4; |
2728 | } |
2729 | break; |
2730 | case SPEED_100000: |
2731 | if (((support_spds & BNXT_LINK_SPEED_MSK_100GB) || |
2732 | (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB)) && |
2733 | lanes != 2 && lanes != 1) { |
2734 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; |
2735 | lanes_needed = 4; |
2736 | } else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) { |
2737 | fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; |
2738 | sig_mode = BNXT_SIG_MODE_PAM4; |
2739 | lanes_needed = 2; |
2740 | } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4) && |
2741 | lanes != 1) { |
2742 | fw_speed = BNXT_LINK_SPEED_100GB_PAM4; |
2743 | sig_mode = BNXT_SIG_MODE_PAM4; |
2744 | lanes_needed = 2; |
2745 | } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112) { |
2746 | fw_speed = BNXT_LINK_SPEED_100GB_PAM4_112; |
2747 | sig_mode = BNXT_SIG_MODE_PAM4_112; |
2748 | } |
2749 | break; |
2750 | case SPEED_200000: |
2751 | if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) { |
2752 | fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; |
2753 | sig_mode = BNXT_SIG_MODE_PAM4; |
2754 | lanes_needed = 4; |
2755 | } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4) && |
2756 | lanes != 2) { |
2757 | fw_speed = BNXT_LINK_SPEED_200GB_PAM4; |
2758 | sig_mode = BNXT_SIG_MODE_PAM4; |
2759 | lanes_needed = 4; |
2760 | } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112) { |
2761 | fw_speed = BNXT_LINK_SPEED_200GB_PAM4_112; |
2762 | sig_mode = BNXT_SIG_MODE_PAM4_112; |
2763 | lanes_needed = 2; |
2764 | } |
2765 | break; |
2766 | case SPEED_400000: |
2767 | if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4) && |
2768 | lanes != 4) { |
2769 | fw_speed = BNXT_LINK_SPEED_400GB_PAM4; |
2770 | sig_mode = BNXT_SIG_MODE_PAM4; |
2771 | lanes_needed = 8; |
2772 | } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112) { |
2773 | fw_speed = BNXT_LINK_SPEED_400GB_PAM4_112; |
2774 | sig_mode = BNXT_SIG_MODE_PAM4_112; |
2775 | lanes_needed = 4; |
2776 | } |
2777 | break; |
2778 | } |
2779 | |
2780 | if (!fw_speed) { |
2781 | netdev_err(dev, format: "unsupported speed!\n" ); |
2782 | return -EINVAL; |
2783 | } |
2784 | |
2785 | if (lanes && lanes != lanes_needed) { |
2786 | netdev_err(dev, format: "unsupported number of lanes for speed\n" ); |
2787 | return -EINVAL; |
2788 | } |
2789 | |
2790 | if (link_info->req_link_speed == fw_speed && |
2791 | link_info->req_signal_mode == sig_mode && |
2792 | link_info->autoneg == 0) |
2793 | return -EALREADY; |
2794 | |
2795 | link_info->req_link_speed = fw_speed; |
2796 | link_info->req_signal_mode = sig_mode; |
2797 | link_info->req_duplex = BNXT_LINK_DUPLEX_FULL; |
2798 | link_info->autoneg = 0; |
2799 | link_info->advertising = 0; |
2800 | link_info->advertising_pam4 = 0; |
2801 | |
2802 | return 0; |
2803 | } |
2804 | |
2805 | u16 bnxt_get_fw_auto_link_speeds(const unsigned long *mode) |
2806 | { |
2807 | u16 fw_speed_mask = 0; |
2808 | |
2809 | if (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Full_BIT, addr: mode) || |
2810 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Half_BIT, addr: mode)) |
2811 | fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB; |
2812 | |
2813 | if (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Full_BIT, addr: mode) || |
2814 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Half_BIT, addr: mode)) |
2815 | fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB; |
2816 | |
2817 | if (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, addr: mode)) |
2818 | fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB; |
2819 | |
2820 | if (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, addr: mode)) |
2821 | fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB; |
2822 | |
2823 | return fw_speed_mask; |
2824 | } |
2825 | |
2826 | static int bnxt_set_link_ksettings(struct net_device *dev, |
2827 | const struct ethtool_link_ksettings *lk_ksettings) |
2828 | { |
2829 | struct bnxt *bp = netdev_priv(dev); |
2830 | struct bnxt_link_info *link_info = &bp->link_info; |
2831 | const struct ethtool_link_settings *base = &lk_ksettings->base; |
2832 | bool set_pause = false; |
2833 | u32 speed, lanes = 0; |
2834 | int rc = 0; |
2835 | |
2836 | if (!BNXT_PHY_CFG_ABLE(bp)) |
2837 | return -EOPNOTSUPP; |
2838 | |
2839 | mutex_lock(&bp->link_lock); |
2840 | if (base->autoneg == AUTONEG_ENABLE) { |
2841 | bnxt_set_ethtool_speeds(link_info, |
2842 | et_mask: lk_ksettings->link_modes.advertising); |
2843 | link_info->autoneg |= BNXT_AUTONEG_SPEED; |
2844 | if (!link_info->advertising && !link_info->advertising_pam4) { |
2845 | link_info->advertising = link_info->support_auto_speeds; |
2846 | link_info->advertising_pam4 = |
2847 | link_info->support_pam4_auto_speeds; |
2848 | } |
2849 | /* any change to autoneg will cause link change, therefore the |
2850 | * driver should put back the original pause setting in autoneg |
2851 | */ |
2852 | if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) |
2853 | set_pause = true; |
2854 | } else { |
2855 | u8 phy_type = link_info->phy_type; |
2856 | |
2857 | if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || |
2858 | phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || |
2859 | link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { |
2860 | netdev_err(dev, format: "10GBase-T devices must autoneg\n" ); |
2861 | rc = -EINVAL; |
2862 | goto set_setting_exit; |
2863 | } |
2864 | if (base->duplex == DUPLEX_HALF) { |
2865 | netdev_err(dev, format: "HALF DUPLEX is not supported!\n" ); |
2866 | rc = -EINVAL; |
2867 | goto set_setting_exit; |
2868 | } |
2869 | speed = base->speed; |
2870 | lanes = lk_ksettings->lanes; |
2871 | rc = bnxt_force_link_speed(dev, ethtool_speed: speed, lanes); |
2872 | if (rc) { |
2873 | if (rc == -EALREADY) |
2874 | rc = 0; |
2875 | goto set_setting_exit; |
2876 | } |
2877 | } |
2878 | |
2879 | if (netif_running(dev)) |
2880 | rc = bnxt_hwrm_set_link_setting(bp, set_pause, false); |
2881 | |
2882 | set_setting_exit: |
2883 | mutex_unlock(lock: &bp->link_lock); |
2884 | return rc; |
2885 | } |
2886 | |
2887 | static int bnxt_get_fecparam(struct net_device *dev, |
2888 | struct ethtool_fecparam *fec) |
2889 | { |
2890 | struct bnxt *bp = netdev_priv(dev); |
2891 | struct bnxt_link_info *link_info; |
2892 | u8 active_fec; |
2893 | u16 fec_cfg; |
2894 | |
2895 | link_info = &bp->link_info; |
2896 | fec_cfg = link_info->fec_cfg; |
2897 | active_fec = link_info->active_fec_sig_mode & |
2898 | PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK; |
2899 | if (fec_cfg & BNXT_FEC_NONE) { |
2900 | fec->fec = ETHTOOL_FEC_NONE; |
2901 | fec->active_fec = ETHTOOL_FEC_NONE; |
2902 | return 0; |
2903 | } |
2904 | if (fec_cfg & BNXT_FEC_AUTONEG) |
2905 | fec->fec |= ETHTOOL_FEC_AUTO; |
2906 | if (fec_cfg & BNXT_FEC_ENC_BASE_R) |
2907 | fec->fec |= ETHTOOL_FEC_BASER; |
2908 | if (fec_cfg & BNXT_FEC_ENC_RS) |
2909 | fec->fec |= ETHTOOL_FEC_RS; |
2910 | if (fec_cfg & BNXT_FEC_ENC_LLRS) |
2911 | fec->fec |= ETHTOOL_FEC_LLRS; |
2912 | |
2913 | switch (active_fec) { |
2914 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE: |
2915 | fec->active_fec |= ETHTOOL_FEC_BASER; |
2916 | break; |
2917 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE: |
2918 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE: |
2919 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE: |
2920 | fec->active_fec |= ETHTOOL_FEC_RS; |
2921 | break; |
2922 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE: |
2923 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE: |
2924 | fec->active_fec |= ETHTOOL_FEC_LLRS; |
2925 | break; |
2926 | case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE: |
2927 | fec->active_fec |= ETHTOOL_FEC_OFF; |
2928 | break; |
2929 | } |
2930 | return 0; |
2931 | } |
2932 | |
2933 | static void bnxt_get_fec_stats(struct net_device *dev, |
2934 | struct ethtool_fec_stats *fec_stats) |
2935 | { |
2936 | struct bnxt *bp = netdev_priv(dev); |
2937 | u64 *rx; |
2938 | |
2939 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) |
2940 | return; |
2941 | |
2942 | rx = bp->rx_port_stats_ext.sw_stats; |
2943 | fec_stats->corrected_bits.total = |
2944 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits)); |
2945 | |
2946 | if (bp->fw_rx_stats_ext_size <= BNXT_RX_STATS_EXT_NUM_LEGACY) |
2947 | return; |
2948 | |
2949 | fec_stats->corrected_blocks.total = |
2950 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_corrected_blocks)); |
2951 | fec_stats->uncorrectable_blocks.total = |
2952 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_uncorrectable_blocks)); |
2953 | } |
2954 | |
2955 | static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info, |
2956 | u32 fec) |
2957 | { |
2958 | u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE; |
2959 | |
2960 | if (fec & ETHTOOL_FEC_BASER) |
2961 | fw_fec |= BNXT_FEC_BASE_R_ON(link_info); |
2962 | else if (fec & ETHTOOL_FEC_RS) |
2963 | fw_fec |= BNXT_FEC_RS_ON(link_info); |
2964 | else if (fec & ETHTOOL_FEC_LLRS) |
2965 | fw_fec |= BNXT_FEC_LLRS_ON; |
2966 | return fw_fec; |
2967 | } |
2968 | |
2969 | static int bnxt_set_fecparam(struct net_device *dev, |
2970 | struct ethtool_fecparam *fecparam) |
2971 | { |
2972 | struct hwrm_port_phy_cfg_input *req; |
2973 | struct bnxt *bp = netdev_priv(dev); |
2974 | struct bnxt_link_info *link_info; |
2975 | u32 new_cfg, fec = fecparam->fec; |
2976 | u16 fec_cfg; |
2977 | int rc; |
2978 | |
2979 | link_info = &bp->link_info; |
2980 | fec_cfg = link_info->fec_cfg; |
2981 | if (fec_cfg & BNXT_FEC_NONE) |
2982 | return -EOPNOTSUPP; |
2983 | |
2984 | if (fec & ETHTOOL_FEC_OFF) { |
2985 | new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE | |
2986 | BNXT_FEC_ALL_OFF(link_info); |
2987 | goto apply_fec; |
2988 | } |
2989 | if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) || |
2990 | ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) || |
2991 | ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) || |
2992 | ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP))) |
2993 | return -EINVAL; |
2994 | |
2995 | if (fec & ETHTOOL_FEC_AUTO) { |
2996 | if (!link_info->autoneg) |
2997 | return -EINVAL; |
2998 | new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE; |
2999 | } else { |
3000 | new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec); |
3001 | } |
3002 | |
3003 | apply_fec: |
3004 | rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); |
3005 | if (rc) |
3006 | return rc; |
3007 | req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); |
3008 | rc = hwrm_req_send(bp, req); |
3009 | /* update current settings */ |
3010 | if (!rc) { |
3011 | mutex_lock(&bp->link_lock); |
3012 | bnxt_update_link(bp, chng_link_state: false); |
3013 | mutex_unlock(lock: &bp->link_lock); |
3014 | } |
3015 | return rc; |
3016 | } |
3017 | |
3018 | static void bnxt_get_pauseparam(struct net_device *dev, |
3019 | struct ethtool_pauseparam *epause) |
3020 | { |
3021 | struct bnxt *bp = netdev_priv(dev); |
3022 | struct bnxt_link_info *link_info = &bp->link_info; |
3023 | |
3024 | if (BNXT_VF(bp)) |
3025 | return; |
3026 | epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL); |
3027 | epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX); |
3028 | epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX); |
3029 | } |
3030 | |
3031 | static void bnxt_get_pause_stats(struct net_device *dev, |
3032 | struct ethtool_pause_stats *epstat) |
3033 | { |
3034 | struct bnxt *bp = netdev_priv(dev); |
3035 | u64 *rx, *tx; |
3036 | |
3037 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) |
3038 | return; |
3039 | |
3040 | rx = bp->port_stats.sw_stats; |
3041 | tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; |
3042 | |
3043 | epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames); |
3044 | epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames); |
3045 | } |
3046 | |
3047 | static int bnxt_set_pauseparam(struct net_device *dev, |
3048 | struct ethtool_pauseparam *epause) |
3049 | { |
3050 | int rc = 0; |
3051 | struct bnxt *bp = netdev_priv(dev); |
3052 | struct bnxt_link_info *link_info = &bp->link_info; |
3053 | |
3054 | if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) |
3055 | return -EOPNOTSUPP; |
3056 | |
3057 | mutex_lock(&bp->link_lock); |
3058 | if (epause->autoneg) { |
3059 | if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { |
3060 | rc = -EINVAL; |
3061 | goto pause_exit; |
3062 | } |
3063 | |
3064 | link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; |
3065 | link_info->req_flow_ctrl = 0; |
3066 | } else { |
3067 | /* when transition from auto pause to force pause, |
3068 | * force a link change |
3069 | */ |
3070 | if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) |
3071 | link_info->force_link_chng = true; |
3072 | link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; |
3073 | link_info->req_flow_ctrl = 0; |
3074 | } |
3075 | if (epause->rx_pause) |
3076 | link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX; |
3077 | |
3078 | if (epause->tx_pause) |
3079 | link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; |
3080 | |
3081 | if (netif_running(dev)) |
3082 | rc = bnxt_hwrm_set_pause(bp); |
3083 | |
3084 | pause_exit: |
3085 | mutex_unlock(lock: &bp->link_lock); |
3086 | return rc; |
3087 | } |
3088 | |
3089 | static u32 bnxt_get_link(struct net_device *dev) |
3090 | { |
3091 | struct bnxt *bp = netdev_priv(dev); |
3092 | |
3093 | /* TODO: handle MF, VF, driver close case */ |
3094 | return BNXT_LINK_IS_UP(bp); |
3095 | } |
3096 | |
3097 | int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, |
3098 | struct hwrm_nvm_get_dev_info_output *nvm_dev_info) |
3099 | { |
3100 | struct hwrm_nvm_get_dev_info_output *resp; |
3101 | struct hwrm_nvm_get_dev_info_input *req; |
3102 | int rc; |
3103 | |
3104 | if (BNXT_VF(bp)) |
3105 | return -EOPNOTSUPP; |
3106 | |
3107 | rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO); |
3108 | if (rc) |
3109 | return rc; |
3110 | |
3111 | resp = hwrm_req_hold(bp, req); |
3112 | rc = hwrm_req_send(bp, req); |
3113 | if (!rc) |
3114 | memcpy(nvm_dev_info, resp, sizeof(*resp)); |
3115 | hwrm_req_drop(bp, req); |
3116 | return rc; |
3117 | } |
3118 | |
3119 | static void bnxt_print_admin_err(struct bnxt *bp) |
3120 | { |
3121 | netdev_info(dev: bp->dev, format: "PF does not have admin privileges to flash or reset the device\n" ); |
3122 | } |
3123 | |
3124 | int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, |
3125 | u16 ext, u16 *index, u32 *item_length, |
3126 | u32 *data_length); |
3127 | |
3128 | int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, |
3129 | u16 dir_ordinal, u16 dir_ext, u16 dir_attr, |
3130 | u32 dir_item_len, const u8 *data, |
3131 | size_t data_len) |
3132 | { |
3133 | struct bnxt *bp = netdev_priv(dev); |
3134 | struct hwrm_nvm_write_input *req; |
3135 | int rc; |
3136 | |
3137 | rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE); |
3138 | if (rc) |
3139 | return rc; |
3140 | |
3141 | if (data_len && data) { |
3142 | dma_addr_t dma_handle; |
3143 | u8 *kmem; |
3144 | |
3145 | kmem = hwrm_req_dma_slice(bp, req, size: data_len, dma: &dma_handle); |
3146 | if (!kmem) { |
3147 | hwrm_req_drop(bp, req); |
3148 | return -ENOMEM; |
3149 | } |
3150 | |
3151 | req->dir_data_length = cpu_to_le32(data_len); |
3152 | |
3153 | memcpy(kmem, data, data_len); |
3154 | req->host_src_addr = cpu_to_le64(dma_handle); |
3155 | } |
3156 | |
3157 | hwrm_req_timeout(bp, req, timeout: bp->hwrm_cmd_max_timeout); |
3158 | req->dir_type = cpu_to_le16(dir_type); |
3159 | req->dir_ordinal = cpu_to_le16(dir_ordinal); |
3160 | req->dir_ext = cpu_to_le16(dir_ext); |
3161 | req->dir_attr = cpu_to_le16(dir_attr); |
3162 | req->dir_item_length = cpu_to_le32(dir_item_len); |
3163 | rc = hwrm_req_send(bp, req); |
3164 | |
3165 | if (rc == -EACCES) |
3166 | bnxt_print_admin_err(bp); |
3167 | return rc; |
3168 | } |
3169 | |
3170 | int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, |
3171 | u8 self_reset, u8 flags) |
3172 | { |
3173 | struct bnxt *bp = netdev_priv(dev); |
3174 | struct hwrm_fw_reset_input *req; |
3175 | int rc; |
3176 | |
3177 | if (!bnxt_hwrm_reset_permitted(bp)) { |
3178 | netdev_warn(dev: bp->dev, format: "Reset denied by firmware, it may be inhibited by remote driver" ); |
3179 | return -EPERM; |
3180 | } |
3181 | |
3182 | rc = hwrm_req_init(bp, req, HWRM_FW_RESET); |
3183 | if (rc) |
3184 | return rc; |
3185 | |
3186 | req->embedded_proc_type = proc_type; |
3187 | req->selfrst_status = self_reset; |
3188 | req->flags = flags; |
3189 | |
3190 | if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) { |
3191 | rc = hwrm_req_send_silent(bp, req); |
3192 | } else { |
3193 | rc = hwrm_req_send(bp, req); |
3194 | if (rc == -EACCES) |
3195 | bnxt_print_admin_err(bp); |
3196 | } |
3197 | return rc; |
3198 | } |
3199 | |
3200 | static int bnxt_firmware_reset(struct net_device *dev, |
3201 | enum bnxt_nvm_directory_type dir_type) |
3202 | { |
3203 | u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE; |
3204 | u8 proc_type, flags = 0; |
3205 | |
3206 | /* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */ |
3207 | /* (e.g. when firmware isn't already running) */ |
3208 | switch (dir_type) { |
3209 | case BNX_DIR_TYPE_CHIMP_PATCH: |
3210 | case BNX_DIR_TYPE_BOOTCODE: |
3211 | case BNX_DIR_TYPE_BOOTCODE_2: |
3212 | proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT; |
3213 | /* Self-reset ChiMP upon next PCIe reset: */ |
3214 | self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; |
3215 | break; |
3216 | case BNX_DIR_TYPE_APE_FW: |
3217 | case BNX_DIR_TYPE_APE_PATCH: |
3218 | proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT; |
3219 | /* Self-reset APE upon next PCIe reset: */ |
3220 | self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST; |
3221 | break; |
3222 | case BNX_DIR_TYPE_KONG_FW: |
3223 | case BNX_DIR_TYPE_KONG_PATCH: |
3224 | proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL; |
3225 | break; |
3226 | case BNX_DIR_TYPE_BONO_FW: |
3227 | case BNX_DIR_TYPE_BONO_PATCH: |
3228 | proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE; |
3229 | break; |
3230 | default: |
3231 | return -EINVAL; |
3232 | } |
3233 | |
3234 | return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags); |
3235 | } |
3236 | |
3237 | static int bnxt_firmware_reset_chip(struct net_device *dev) |
3238 | { |
3239 | struct bnxt *bp = netdev_priv(dev); |
3240 | u8 flags = 0; |
3241 | |
3242 | if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) |
3243 | flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; |
3244 | |
3245 | return bnxt_hwrm_firmware_reset(dev, |
3246 | FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, |
3247 | FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, |
3248 | flags); |
3249 | } |
3250 | |
3251 | static int bnxt_firmware_reset_ap(struct net_device *dev) |
3252 | { |
3253 | return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP, |
3254 | FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE, |
3255 | flags: 0); |
3256 | } |
3257 | |
3258 | static int bnxt_flash_firmware(struct net_device *dev, |
3259 | u16 dir_type, |
3260 | const u8 *fw_data, |
3261 | size_t fw_size) |
3262 | { |
3263 | int rc = 0; |
3264 | u16 code_type; |
3265 | u32 stored_crc; |
3266 | u32 calculated_crc; |
3267 | struct bnxt_fw_header * = (struct bnxt_fw_header *)fw_data; |
3268 | |
3269 | switch (dir_type) { |
3270 | case BNX_DIR_TYPE_BOOTCODE: |
3271 | case BNX_DIR_TYPE_BOOTCODE_2: |
3272 | code_type = CODE_BOOT; |
3273 | break; |
3274 | case BNX_DIR_TYPE_CHIMP_PATCH: |
3275 | code_type = CODE_CHIMP_PATCH; |
3276 | break; |
3277 | case BNX_DIR_TYPE_APE_FW: |
3278 | code_type = CODE_MCTP_PASSTHRU; |
3279 | break; |
3280 | case BNX_DIR_TYPE_APE_PATCH: |
3281 | code_type = CODE_APE_PATCH; |
3282 | break; |
3283 | case BNX_DIR_TYPE_KONG_FW: |
3284 | code_type = CODE_KONG_FW; |
3285 | break; |
3286 | case BNX_DIR_TYPE_KONG_PATCH: |
3287 | code_type = CODE_KONG_PATCH; |
3288 | break; |
3289 | case BNX_DIR_TYPE_BONO_FW: |
3290 | code_type = CODE_BONO_FW; |
3291 | break; |
3292 | case BNX_DIR_TYPE_BONO_PATCH: |
3293 | code_type = CODE_BONO_PATCH; |
3294 | break; |
3295 | default: |
3296 | netdev_err(dev, format: "Unsupported directory entry type: %u\n" , |
3297 | dir_type); |
3298 | return -EINVAL; |
3299 | } |
3300 | if (fw_size < sizeof(struct bnxt_fw_header)) { |
3301 | netdev_err(dev, format: "Invalid firmware file size: %u\n" , |
3302 | (unsigned int)fw_size); |
3303 | return -EINVAL; |
3304 | } |
3305 | if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) { |
3306 | netdev_err(dev, format: "Invalid firmware signature: %08X\n" , |
3307 | le32_to_cpu(header->signature)); |
3308 | return -EINVAL; |
3309 | } |
3310 | if (header->code_type != code_type) { |
3311 | netdev_err(dev, format: "Expected firmware type: %d, read: %d\n" , |
3312 | code_type, header->code_type); |
3313 | return -EINVAL; |
3314 | } |
3315 | if (header->device != DEVICE_CUMULUS_FAMILY) { |
3316 | netdev_err(dev, format: "Expected firmware device family %d, read: %d\n" , |
3317 | DEVICE_CUMULUS_FAMILY, header->device); |
3318 | return -EINVAL; |
3319 | } |
3320 | /* Confirm the CRC32 checksum of the file: */ |
3321 | stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - |
3322 | sizeof(stored_crc))); |
3323 | calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); |
3324 | if (calculated_crc != stored_crc) { |
3325 | netdev_err(dev, format: "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n" , |
3326 | (unsigned long)stored_crc, |
3327 | (unsigned long)calculated_crc); |
3328 | return -EINVAL; |
3329 | } |
3330 | rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, |
3331 | dir_ext: 0, dir_attr: 0, dir_item_len: 0, data: fw_data, data_len: fw_size); |
3332 | if (rc == 0) /* Firmware update successful */ |
3333 | rc = bnxt_firmware_reset(dev, dir_type); |
3334 | |
3335 | return rc; |
3336 | } |
3337 | |
3338 | static int bnxt_flash_microcode(struct net_device *dev, |
3339 | u16 dir_type, |
3340 | const u8 *fw_data, |
3341 | size_t fw_size) |
3342 | { |
3343 | struct bnxt_ucode_trailer *trailer; |
3344 | u32 calculated_crc; |
3345 | u32 stored_crc; |
3346 | int rc = 0; |
3347 | |
3348 | if (fw_size < sizeof(struct bnxt_ucode_trailer)) { |
3349 | netdev_err(dev, format: "Invalid microcode file size: %u\n" , |
3350 | (unsigned int)fw_size); |
3351 | return -EINVAL; |
3352 | } |
3353 | trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size - |
3354 | sizeof(*trailer))); |
3355 | if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) { |
3356 | netdev_err(dev, format: "Invalid microcode trailer signature: %08X\n" , |
3357 | le32_to_cpu(trailer->sig)); |
3358 | return -EINVAL; |
3359 | } |
3360 | if (le16_to_cpu(trailer->dir_type) != dir_type) { |
3361 | netdev_err(dev, format: "Expected microcode type: %d, read: %d\n" , |
3362 | dir_type, le16_to_cpu(trailer->dir_type)); |
3363 | return -EINVAL; |
3364 | } |
3365 | if (le16_to_cpu(trailer->trailer_length) < |
3366 | sizeof(struct bnxt_ucode_trailer)) { |
3367 | netdev_err(dev, format: "Invalid microcode trailer length: %d\n" , |
3368 | le16_to_cpu(trailer->trailer_length)); |
3369 | return -EINVAL; |
3370 | } |
3371 | |
3372 | /* Confirm the CRC32 checksum of the file: */ |
3373 | stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size - |
3374 | sizeof(stored_crc))); |
3375 | calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc)); |
3376 | if (calculated_crc != stored_crc) { |
3377 | netdev_err(dev, |
3378 | format: "CRC32 (%08lX) does not match calculated: %08lX\n" , |
3379 | (unsigned long)stored_crc, |
3380 | (unsigned long)calculated_crc); |
3381 | return -EINVAL; |
3382 | } |
3383 | rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, |
3384 | dir_ext: 0, dir_attr: 0, dir_item_len: 0, data: fw_data, data_len: fw_size); |
3385 | |
3386 | return rc; |
3387 | } |
3388 | |
3389 | static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type) |
3390 | { |
3391 | switch (dir_type) { |
3392 | case BNX_DIR_TYPE_CHIMP_PATCH: |
3393 | case BNX_DIR_TYPE_BOOTCODE: |
3394 | case BNX_DIR_TYPE_BOOTCODE_2: |
3395 | case BNX_DIR_TYPE_APE_FW: |
3396 | case BNX_DIR_TYPE_APE_PATCH: |
3397 | case BNX_DIR_TYPE_KONG_FW: |
3398 | case BNX_DIR_TYPE_KONG_PATCH: |
3399 | case BNX_DIR_TYPE_BONO_FW: |
3400 | case BNX_DIR_TYPE_BONO_PATCH: |
3401 | return true; |
3402 | } |
3403 | |
3404 | return false; |
3405 | } |
3406 | |
3407 | static bool bnxt_dir_type_is_other_exec_format(u16 dir_type) |
3408 | { |
3409 | switch (dir_type) { |
3410 | case BNX_DIR_TYPE_AVS: |
3411 | case BNX_DIR_TYPE_EXP_ROM_MBA: |
3412 | case BNX_DIR_TYPE_PCIE: |
3413 | case BNX_DIR_TYPE_TSCF_UCODE: |
3414 | case BNX_DIR_TYPE_EXT_PHY: |
3415 | case BNX_DIR_TYPE_CCM: |
3416 | case BNX_DIR_TYPE_ISCSI_BOOT: |
3417 | case BNX_DIR_TYPE_ISCSI_BOOT_IPV6: |
3418 | case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6: |
3419 | return true; |
3420 | } |
3421 | |
3422 | return false; |
3423 | } |
3424 | |
3425 | static bool bnxt_dir_type_is_executable(u16 dir_type) |
3426 | { |
3427 | return bnxt_dir_type_is_ape_bin_format(dir_type) || |
3428 | bnxt_dir_type_is_other_exec_format(dir_type); |
3429 | } |
3430 | |
3431 | static int bnxt_flash_firmware_from_file(struct net_device *dev, |
3432 | u16 dir_type, |
3433 | const char *filename) |
3434 | { |
3435 | const struct firmware *fw; |
3436 | int rc; |
3437 | |
3438 | rc = request_firmware(fw: &fw, name: filename, device: &dev->dev); |
3439 | if (rc != 0) { |
3440 | netdev_err(dev, format: "Error %d requesting firmware file: %s\n" , |
3441 | rc, filename); |
3442 | return rc; |
3443 | } |
3444 | if (bnxt_dir_type_is_ape_bin_format(dir_type)) |
3445 | rc = bnxt_flash_firmware(dev, dir_type, fw_data: fw->data, fw_size: fw->size); |
3446 | else if (bnxt_dir_type_is_other_exec_format(dir_type)) |
3447 | rc = bnxt_flash_microcode(dev, dir_type, fw_data: fw->data, fw_size: fw->size); |
3448 | else |
3449 | rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST, |
3450 | dir_ext: 0, dir_attr: 0, dir_item_len: 0, data: fw->data, data_len: fw->size); |
3451 | release_firmware(fw); |
3452 | return rc; |
3453 | } |
3454 | |
3455 | #define MSG_INTEGRITY_ERR "PKG install error : Data integrity on NVM" |
3456 | #define MSG_INVALID_PKG "PKG install error : Invalid package" |
3457 | #define MSG_AUTHENTICATION_ERR "PKG install error : Authentication error" |
3458 | #define MSG_INVALID_DEV "PKG install error : Invalid device" |
3459 | #define MSG_INTERNAL_ERR "PKG install error : Internal error" |
3460 | #define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram" |
3461 | #define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram" |
3462 | #define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error" |
3463 | #define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected" |
3464 | #define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure" |
3465 | |
3466 | static int nvm_update_err_to_stderr(struct net_device *dev, u8 result, |
3467 | struct netlink_ext_ack *extack) |
3468 | { |
3469 | switch (result) { |
3470 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER: |
3471 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER: |
3472 | case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR: |
3473 | case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR: |
3474 | case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND: |
3475 | case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED: |
3476 | BNXT_NVM_ERR_MSG(dev, extack, MSG_INTEGRITY_ERR); |
3477 | return -EINVAL; |
3478 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE: |
3479 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER: |
3480 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE: |
3481 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM: |
3482 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH: |
3483 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST: |
3484 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER: |
3485 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM: |
3486 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM: |
3487 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH: |
3488 | case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE: |
3489 | case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM: |
3490 | case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM: |
3491 | BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_PKG); |
3492 | return -ENOPKG; |
3493 | case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR: |
3494 | BNXT_NVM_ERR_MSG(dev, extack, MSG_AUTHENTICATION_ERR); |
3495 | return -EPERM; |
3496 | case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV: |
3497 | case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID: |
3498 | case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR: |
3499 | case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID: |
3500 | case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM: |
3501 | BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_DEV); |
3502 | return -EOPNOTSUPP; |
3503 | default: |
3504 | BNXT_NVM_ERR_MSG(dev, extack, MSG_INTERNAL_ERR); |
3505 | return -EIO; |
3506 | } |
3507 | } |
3508 | |
3509 | #define BNXT_PKG_DMA_SIZE 0x40000 |
3510 | #define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) |
3511 | #define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) |
3512 | |
3513 | static int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size, |
3514 | struct netlink_ext_ack *extack) |
3515 | { |
3516 | u32 item_len; |
3517 | int rc; |
3518 | |
3519 | rc = bnxt_find_nvram_item(dev, type: BNX_DIR_TYPE_UPDATE, |
3520 | BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL, |
3521 | item_length: &item_len, NULL); |
3522 | if (rc) { |
3523 | BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); |
3524 | return rc; |
3525 | } |
3526 | |
3527 | if (fw_size > item_len) { |
3528 | rc = bnxt_flash_nvram(dev, dir_type: BNX_DIR_TYPE_UPDATE, |
3529 | BNX_DIR_ORDINAL_FIRST, dir_ext: 0, dir_attr: 1, |
3530 | round_up(fw_size, 4096), NULL, data_len: 0); |
3531 | if (rc) { |
3532 | BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR); |
3533 | return rc; |
3534 | } |
3535 | } |
3536 | return 0; |
3537 | } |
3538 | |
3539 | int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, |
3540 | u32 install_type, struct netlink_ext_ack *extack) |
3541 | { |
3542 | struct hwrm_nvm_install_update_input *install; |
3543 | struct hwrm_nvm_install_update_output *resp; |
3544 | struct hwrm_nvm_modify_input *modify; |
3545 | struct bnxt *bp = netdev_priv(dev); |
3546 | bool defrag_attempted = false; |
3547 | dma_addr_t dma_handle; |
3548 | u8 *kmem = NULL; |
3549 | u32 modify_len; |
3550 | u32 item_len; |
3551 | u8 cmd_err; |
3552 | u16 index; |
3553 | int rc; |
3554 | |
3555 | /* resize before flashing larger image than available space */ |
3556 | rc = bnxt_resize_update_entry(dev, fw_size: fw->size, extack); |
3557 | if (rc) |
3558 | return rc; |
3559 | |
3560 | bnxt_hwrm_fw_set_time(bp); |
3561 | |
3562 | rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY); |
3563 | if (rc) |
3564 | return rc; |
3565 | |
3566 | /* Try allocating a large DMA buffer first. Older fw will |
3567 | * cause excessive NVRAM erases when using small blocks. |
3568 | */ |
3569 | modify_len = roundup_pow_of_two(fw->size); |
3570 | modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); |
3571 | while (1) { |
3572 | kmem = hwrm_req_dma_slice(bp, req: modify, size: modify_len, dma: &dma_handle); |
3573 | if (!kmem && modify_len > PAGE_SIZE) |
3574 | modify_len /= 2; |
3575 | else |
3576 | break; |
3577 | } |
3578 | if (!kmem) { |
3579 | hwrm_req_drop(bp, req: modify); |
3580 | return -ENOMEM; |
3581 | } |
3582 | |
3583 | rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE); |
3584 | if (rc) { |
3585 | hwrm_req_drop(bp, req: modify); |
3586 | return rc; |
3587 | } |
3588 | |
3589 | hwrm_req_timeout(bp, req: modify, timeout: bp->hwrm_cmd_max_timeout); |
3590 | hwrm_req_timeout(bp, req: install, timeout: bp->hwrm_cmd_max_timeout); |
3591 | |
3592 | hwrm_req_hold(bp, req: modify); |
3593 | modify->host_src_addr = cpu_to_le64(dma_handle); |
3594 | |
3595 | resp = hwrm_req_hold(bp, req: install); |
3596 | if ((install_type & 0xffff) == 0) |
3597 | install_type >>= 16; |
3598 | install->install_type = cpu_to_le32(install_type); |
3599 | |
3600 | do { |
3601 | u32 copied = 0, len = modify_len; |
3602 | |
3603 | rc = bnxt_find_nvram_item(dev, type: BNX_DIR_TYPE_UPDATE, |
3604 | BNX_DIR_ORDINAL_FIRST, |
3605 | BNX_DIR_EXT_NONE, |
3606 | index: &index, item_length: &item_len, NULL); |
3607 | if (rc) { |
3608 | BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR); |
3609 | break; |
3610 | } |
3611 | if (fw->size > item_len) { |
3612 | BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_SPACE_ERR); |
3613 | rc = -EFBIG; |
3614 | break; |
3615 | } |
3616 | |
3617 | modify->dir_idx = cpu_to_le16(index); |
3618 | |
3619 | if (fw->size > modify_len) |
3620 | modify->flags = BNXT_NVM_MORE_FLAG; |
3621 | while (copied < fw->size) { |
3622 | u32 balance = fw->size - copied; |
3623 | |
3624 | if (balance <= modify_len) { |
3625 | len = balance; |
3626 | if (copied) |
3627 | modify->flags |= BNXT_NVM_LAST_FLAG; |
3628 | } |
3629 | memcpy(kmem, fw->data + copied, len); |
3630 | modify->len = cpu_to_le32(len); |
3631 | modify->offset = cpu_to_le32(copied); |
3632 | rc = hwrm_req_send(bp, req: modify); |
3633 | if (rc) |
3634 | goto pkg_abort; |
3635 | copied += len; |
3636 | } |
3637 | |
3638 | rc = hwrm_req_send_silent(bp, req: install); |
3639 | if (!rc) |
3640 | break; |
3641 | |
3642 | if (defrag_attempted) { |
3643 | /* We have tried to defragment already in the previous |
3644 | * iteration. Return with the result for INSTALL_UPDATE |
3645 | */ |
3646 | break; |
3647 | } |
3648 | |
3649 | cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; |
3650 | |
3651 | switch (cmd_err) { |
3652 | case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK: |
3653 | BNXT_NVM_ERR_MSG(dev, extack, MSG_ANTI_ROLLBACK_ERR); |
3654 | rc = -EALREADY; |
3655 | break; |
3656 | case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR: |
3657 | install->flags = |
3658 | cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); |
3659 | |
3660 | rc = hwrm_req_send_silent(bp, req: install); |
3661 | if (!rc) |
3662 | break; |
3663 | |
3664 | cmd_err = ((struct hwrm_err_output *)resp)->cmd_err; |
3665 | |
3666 | if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { |
3667 | /* FW has cleared NVM area, driver will create |
3668 | * UPDATE directory and try the flash again |
3669 | */ |
3670 | defrag_attempted = true; |
3671 | install->flags = 0; |
3672 | rc = bnxt_flash_nvram(dev: bp->dev, |
3673 | dir_type: BNX_DIR_TYPE_UPDATE, |
3674 | BNX_DIR_ORDINAL_FIRST, |
3675 | dir_ext: 0, dir_attr: 0, dir_item_len: item_len, NULL, data_len: 0); |
3676 | if (!rc) |
3677 | break; |
3678 | } |
3679 | fallthrough; |
3680 | default: |
3681 | BNXT_NVM_ERR_MSG(dev, extack, MSG_GENERIC_FAILURE_ERR); |
3682 | } |
3683 | } while (defrag_attempted && !rc); |
3684 | |
3685 | pkg_abort: |
3686 | hwrm_req_drop(bp, req: modify); |
3687 | hwrm_req_drop(bp, req: install); |
3688 | |
3689 | if (resp->result) { |
3690 | netdev_err(dev, format: "PKG install error = %d, problem_item = %d\n" , |
3691 | (s8)resp->result, (int)resp->problem_item); |
3692 | rc = nvm_update_err_to_stderr(dev, result: resp->result, extack); |
3693 | } |
3694 | if (rc == -EACCES) |
3695 | bnxt_print_admin_err(bp); |
3696 | return rc; |
3697 | } |
3698 | |
3699 | static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, |
3700 | u32 install_type, struct netlink_ext_ack *extack) |
3701 | { |
3702 | const struct firmware *fw; |
3703 | int rc; |
3704 | |
3705 | rc = request_firmware(fw: &fw, name: filename, device: &dev->dev); |
3706 | if (rc != 0) { |
3707 | netdev_err(dev, format: "PKG error %d requesting file: %s\n" , |
3708 | rc, filename); |
3709 | return rc; |
3710 | } |
3711 | |
3712 | rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type, extack); |
3713 | |
3714 | release_firmware(fw); |
3715 | |
3716 | return rc; |
3717 | } |
3718 | |
3719 | static int bnxt_flash_device(struct net_device *dev, |
3720 | struct ethtool_flash *flash) |
3721 | { |
3722 | if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) { |
3723 | netdev_err(dev, format: "flashdev not supported from a virtual function\n" ); |
3724 | return -EINVAL; |
3725 | } |
3726 | |
3727 | if (flash->region == ETHTOOL_FLASH_ALL_REGIONS || |
3728 | flash->region > 0xffff) |
3729 | return bnxt_flash_package_from_file(dev, filename: flash->data, |
3730 | install_type: flash->region, NULL); |
3731 | |
3732 | return bnxt_flash_firmware_from_file(dev, dir_type: flash->region, filename: flash->data); |
3733 | } |
3734 | |
3735 | static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length) |
3736 | { |
3737 | struct hwrm_nvm_get_dir_info_output *output; |
3738 | struct hwrm_nvm_get_dir_info_input *req; |
3739 | struct bnxt *bp = netdev_priv(dev); |
3740 | int rc; |
3741 | |
3742 | rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO); |
3743 | if (rc) |
3744 | return rc; |
3745 | |
3746 | output = hwrm_req_hold(bp, req); |
3747 | rc = hwrm_req_send(bp, req); |
3748 | if (!rc) { |
3749 | *entries = le32_to_cpu(output->entries); |
3750 | *length = le32_to_cpu(output->entry_length); |
3751 | } |
3752 | hwrm_req_drop(bp, req); |
3753 | return rc; |
3754 | } |
3755 | |
3756 | static int bnxt_get_eeprom_len(struct net_device *dev) |
3757 | { |
3758 | struct bnxt *bp = netdev_priv(dev); |
3759 | |
3760 | if (BNXT_VF(bp)) |
3761 | return 0; |
3762 | |
3763 | /* The -1 return value allows the entire 32-bit range of offsets to be |
3764 | * passed via the ethtool command-line utility. |
3765 | */ |
3766 | return -1; |
3767 | } |
3768 | |
3769 | static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data) |
3770 | { |
3771 | struct bnxt *bp = netdev_priv(dev); |
3772 | int rc; |
3773 | u32 dir_entries; |
3774 | u32 entry_length; |
3775 | u8 *buf; |
3776 | size_t buflen; |
3777 | dma_addr_t dma_handle; |
3778 | struct hwrm_nvm_get_dir_entries_input *req; |
3779 | |
3780 | rc = nvm_get_dir_info(dev, entries: &dir_entries, length: &entry_length); |
3781 | if (rc != 0) |
3782 | return rc; |
3783 | |
3784 | if (!dir_entries || !entry_length) |
3785 | return -EIO; |
3786 | |
3787 | /* Insert 2 bytes of directory info (count and size of entries) */ |
3788 | if (len < 2) |
3789 | return -EINVAL; |
3790 | |
3791 | *data++ = dir_entries; |
3792 | *data++ = entry_length; |
3793 | len -= 2; |
3794 | memset(data, 0xff, len); |
3795 | |
3796 | rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES); |
3797 | if (rc) |
3798 | return rc; |
3799 | |
3800 | buflen = mul_u32_u32(a: dir_entries, b: entry_length); |
3801 | buf = hwrm_req_dma_slice(bp, req, size: buflen, dma: &dma_handle); |
3802 | if (!buf) { |
3803 | hwrm_req_drop(bp, req); |
3804 | return -ENOMEM; |
3805 | } |
3806 | req->host_dest_addr = cpu_to_le64(dma_handle); |
3807 | |
3808 | hwrm_req_hold(bp, req); /* hold the slice */ |
3809 | rc = hwrm_req_send(bp, req); |
3810 | if (rc == 0) |
3811 | memcpy(data, buf, len > buflen ? buflen : len); |
3812 | hwrm_req_drop(bp, req); |
3813 | return rc; |
3814 | } |
3815 | |
3816 | int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset, |
3817 | u32 length, u8 *data) |
3818 | { |
3819 | struct bnxt *bp = netdev_priv(dev); |
3820 | int rc; |
3821 | u8 *buf; |
3822 | dma_addr_t dma_handle; |
3823 | struct hwrm_nvm_read_input *req; |
3824 | |
3825 | if (!length) |
3826 | return -EINVAL; |
3827 | |
3828 | rc = hwrm_req_init(bp, req, HWRM_NVM_READ); |
3829 | if (rc) |
3830 | return rc; |
3831 | |
3832 | buf = hwrm_req_dma_slice(bp, req, size: length, dma: &dma_handle); |
3833 | if (!buf) { |
3834 | hwrm_req_drop(bp, req); |
3835 | return -ENOMEM; |
3836 | } |
3837 | |
3838 | req->host_dest_addr = cpu_to_le64(dma_handle); |
3839 | req->dir_idx = cpu_to_le16(index); |
3840 | req->offset = cpu_to_le32(offset); |
3841 | req->len = cpu_to_le32(length); |
3842 | |
3843 | hwrm_req_hold(bp, req); /* hold the slice */ |
3844 | rc = hwrm_req_send(bp, req); |
3845 | if (rc == 0) |
3846 | memcpy(data, buf, length); |
3847 | hwrm_req_drop(bp, req); |
3848 | return rc; |
3849 | } |
3850 | |
3851 | int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, |
3852 | u16 ext, u16 *index, u32 *item_length, |
3853 | u32 *data_length) |
3854 | { |
3855 | struct hwrm_nvm_find_dir_entry_output *output; |
3856 | struct hwrm_nvm_find_dir_entry_input *req; |
3857 | struct bnxt *bp = netdev_priv(dev); |
3858 | int rc; |
3859 | |
3860 | rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY); |
3861 | if (rc) |
3862 | return rc; |
3863 | |
3864 | req->enables = 0; |
3865 | req->dir_idx = 0; |
3866 | req->dir_type = cpu_to_le16(type); |
3867 | req->dir_ordinal = cpu_to_le16(ordinal); |
3868 | req->dir_ext = cpu_to_le16(ext); |
3869 | req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ; |
3870 | output = hwrm_req_hold(bp, req); |
3871 | rc = hwrm_req_send_silent(bp, req); |
3872 | if (rc == 0) { |
3873 | if (index) |
3874 | *index = le16_to_cpu(output->dir_idx); |
3875 | if (item_length) |
3876 | *item_length = le32_to_cpu(output->dir_item_length); |
3877 | if (data_length) |
3878 | *data_length = le32_to_cpu(output->dir_data_length); |
3879 | } |
3880 | hwrm_req_drop(bp, req); |
3881 | return rc; |
3882 | } |
3883 | |
3884 | static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen) |
3885 | { |
3886 | char *retval = NULL; |
3887 | char *p; |
3888 | char *value; |
3889 | int field = 0; |
3890 | |
3891 | if (datalen < 1) |
3892 | return NULL; |
3893 | /* null-terminate the log data (removing last '\n'): */ |
3894 | data[datalen - 1] = 0; |
3895 | for (p = data; *p != 0; p++) { |
3896 | field = 0; |
3897 | retval = NULL; |
3898 | while (*p != 0 && *p != '\n') { |
3899 | value = p; |
3900 | while (*p != 0 && *p != '\t' && *p != '\n') |
3901 | p++; |
3902 | if (field == desired_field) |
3903 | retval = value; |
3904 | if (*p != '\t') |
3905 | break; |
3906 | *p = 0; |
3907 | field++; |
3908 | p++; |
3909 | } |
3910 | if (*p == 0) |
3911 | break; |
3912 | *p = 0; |
3913 | } |
3914 | return retval; |
3915 | } |
3916 | |
3917 | int bnxt_get_pkginfo(struct net_device *dev, char *ver, int size) |
3918 | { |
3919 | struct bnxt *bp = netdev_priv(dev); |
3920 | u16 index = 0; |
3921 | char *pkgver; |
3922 | u32 pkglen; |
3923 | u8 *pkgbuf; |
3924 | int rc; |
3925 | |
3926 | rc = bnxt_find_nvram_item(dev, type: BNX_DIR_TYPE_PKG_LOG, |
3927 | BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, |
3928 | index: &index, NULL, data_length: &pkglen); |
3929 | if (rc) |
3930 | return rc; |
3931 | |
3932 | pkgbuf = kzalloc(size: pkglen, GFP_KERNEL); |
3933 | if (!pkgbuf) { |
3934 | dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n" , |
3935 | pkglen); |
3936 | return -ENOMEM; |
3937 | } |
3938 | |
3939 | rc = bnxt_get_nvram_item(dev, index, offset: 0, length: pkglen, data: pkgbuf); |
3940 | if (rc) |
3941 | goto err; |
3942 | |
3943 | pkgver = bnxt_parse_pkglog(desired_field: BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, data: pkgbuf, |
3944 | datalen: pkglen); |
3945 | if (pkgver && *pkgver != 0 && isdigit(c: *pkgver)) |
3946 | strscpy(ver, pkgver, size); |
3947 | else |
3948 | rc = -ENOENT; |
3949 | |
3950 | err: |
3951 | kfree(objp: pkgbuf); |
3952 | |
3953 | return rc; |
3954 | } |
3955 | |
3956 | static void bnxt_get_pkgver(struct net_device *dev) |
3957 | { |
3958 | struct bnxt *bp = netdev_priv(dev); |
3959 | char buf[FW_VER_STR_LEN]; |
3960 | int len; |
3961 | |
3962 | if (!bnxt_get_pkginfo(dev, ver: buf, size: sizeof(buf))) { |
3963 | len = strlen(bp->fw_ver_str); |
3964 | snprintf(buf: bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, |
3965 | fmt: "/pkg %s" , buf); |
3966 | } |
3967 | } |
3968 | |
3969 | static int bnxt_get_eeprom(struct net_device *dev, |
3970 | struct ethtool_eeprom *eeprom, |
3971 | u8 *data) |
3972 | { |
3973 | u32 index; |
3974 | u32 offset; |
3975 | |
3976 | if (eeprom->offset == 0) /* special offset value to get directory */ |
3977 | return bnxt_get_nvram_directory(dev, len: eeprom->len, data); |
3978 | |
3979 | index = eeprom->offset >> 24; |
3980 | offset = eeprom->offset & 0xffffff; |
3981 | |
3982 | if (index == 0) { |
3983 | netdev_err(dev, format: "unsupported index value: %d\n" , index); |
3984 | return -EINVAL; |
3985 | } |
3986 | |
3987 | return bnxt_get_nvram_item(dev, index: index - 1, offset, length: eeprom->len, data); |
3988 | } |
3989 | |
3990 | static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index) |
3991 | { |
3992 | struct hwrm_nvm_erase_dir_entry_input *req; |
3993 | struct bnxt *bp = netdev_priv(dev); |
3994 | int rc; |
3995 | |
3996 | rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY); |
3997 | if (rc) |
3998 | return rc; |
3999 | |
4000 | req->dir_idx = cpu_to_le16(index); |
4001 | return hwrm_req_send(bp, req); |
4002 | } |
4003 | |
4004 | static int bnxt_set_eeprom(struct net_device *dev, |
4005 | struct ethtool_eeprom *eeprom, |
4006 | u8 *data) |
4007 | { |
4008 | struct bnxt *bp = netdev_priv(dev); |
4009 | u8 index, dir_op; |
4010 | u16 type, ext, ordinal, attr; |
4011 | |
4012 | if (!BNXT_PF(bp)) { |
4013 | netdev_err(dev, format: "NVM write not supported from a virtual function\n" ); |
4014 | return -EINVAL; |
4015 | } |
4016 | |
4017 | type = eeprom->magic >> 16; |
4018 | |
4019 | if (type == 0xffff) { /* special value for directory operations */ |
4020 | index = eeprom->magic & 0xff; |
4021 | dir_op = eeprom->magic >> 8; |
4022 | if (index == 0) |
4023 | return -EINVAL; |
4024 | switch (dir_op) { |
4025 | case 0x0e: /* erase */ |
4026 | if (eeprom->offset != ~eeprom->magic) |
4027 | return -EINVAL; |
4028 | return bnxt_erase_nvram_directory(dev, index: index - 1); |
4029 | default: |
4030 | return -EINVAL; |
4031 | } |
4032 | } |
4033 | |
4034 | /* Create or re-write an NVM item: */ |
4035 | if (bnxt_dir_type_is_executable(dir_type: type)) |
4036 | return -EOPNOTSUPP; |
4037 | ext = eeprom->magic & 0xffff; |
4038 | ordinal = eeprom->offset >> 16; |
4039 | attr = eeprom->offset & 0xffff; |
4040 | |
4041 | return bnxt_flash_nvram(dev, dir_type: type, dir_ordinal: ordinal, dir_ext: ext, dir_attr: attr, dir_item_len: 0, data, |
4042 | data_len: eeprom->len); |
4043 | } |
4044 | |
4045 | static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) |
4046 | { |
4047 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); |
4048 | __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); |
4049 | struct bnxt *bp = netdev_priv(dev); |
4050 | struct ethtool_keee *eee = &bp->eee; |
4051 | struct bnxt_link_info *link_info = &bp->link_info; |
4052 | int rc = 0; |
4053 | |
4054 | if (!BNXT_PHY_CFG_ABLE(bp)) |
4055 | return -EOPNOTSUPP; |
4056 | |
4057 | if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) |
4058 | return -EOPNOTSUPP; |
4059 | |
4060 | mutex_lock(&bp->link_lock); |
4061 | _bnxt_fw_to_linkmode(mode: advertising, fw_speeds: link_info->advertising); |
4062 | if (!edata->eee_enabled) |
4063 | goto eee_ok; |
4064 | |
4065 | if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { |
4066 | netdev_warn(dev, format: "EEE requires autoneg\n" ); |
4067 | rc = -EINVAL; |
4068 | goto eee_exit; |
4069 | } |
4070 | if (edata->tx_lpi_enabled) { |
4071 | if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || |
4072 | edata->tx_lpi_timer < bp->lpi_tmr_lo)) { |
4073 | netdev_warn(dev, format: "Valid LPI timer range is %d and %d microsecs\n" , |
4074 | bp->lpi_tmr_lo, bp->lpi_tmr_hi); |
4075 | rc = -EINVAL; |
4076 | goto eee_exit; |
4077 | } else if (!bp->lpi_tmr_hi) { |
4078 | edata->tx_lpi_timer = eee->tx_lpi_timer; |
4079 | } |
4080 | } |
4081 | if (linkmode_empty(src: edata->advertised)) { |
4082 | linkmode_and(dst: edata->advertised, a: advertising, b: eee->supported); |
4083 | } else if (linkmode_andnot(dst: tmp, src1: edata->advertised, src2: advertising)) { |
4084 | netdev_warn(dev, format: "EEE advertised must be a subset of autoneg advertised speeds\n" ); |
4085 | rc = -EINVAL; |
4086 | goto eee_exit; |
4087 | } |
4088 | |
4089 | linkmode_copy(dst: eee->advertised, src: edata->advertised); |
4090 | eee->tx_lpi_enabled = edata->tx_lpi_enabled; |
4091 | eee->tx_lpi_timer = edata->tx_lpi_timer; |
4092 | eee_ok: |
4093 | eee->eee_enabled = edata->eee_enabled; |
4094 | |
4095 | if (netif_running(dev)) |
4096 | rc = bnxt_hwrm_set_link_setting(bp, false, true); |
4097 | |
4098 | eee_exit: |
4099 | mutex_unlock(lock: &bp->link_lock); |
4100 | return rc; |
4101 | } |
4102 | |
4103 | static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) |
4104 | { |
4105 | struct bnxt *bp = netdev_priv(dev); |
4106 | |
4107 | if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) |
4108 | return -EOPNOTSUPP; |
4109 | |
4110 | *edata = bp->eee; |
4111 | if (!bp->eee.eee_enabled) { |
4112 | /* Preserve tx_lpi_timer so that the last value will be used |
4113 | * by default when it is re-enabled. |
4114 | */ |
4115 | linkmode_zero(dst: edata->advertised); |
4116 | edata->tx_lpi_enabled = 0; |
4117 | } |
4118 | |
4119 | if (!bp->eee.eee_active) |
4120 | linkmode_zero(dst: edata->lp_advertised); |
4121 | |
4122 | return 0; |
4123 | } |
4124 | |
4125 | static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, |
4126 | u16 page_number, u8 bank, |
4127 | u16 start_addr, u16 data_length, |
4128 | u8 *buf) |
4129 | { |
4130 | struct hwrm_port_phy_i2c_read_output *output; |
4131 | struct hwrm_port_phy_i2c_read_input *req; |
4132 | int rc, byte_offset = 0; |
4133 | |
4134 | rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ); |
4135 | if (rc) |
4136 | return rc; |
4137 | |
4138 | output = hwrm_req_hold(bp, req); |
4139 | req->i2c_slave_addr = i2c_addr; |
4140 | req->page_number = cpu_to_le16(page_number); |
4141 | req->port_id = cpu_to_le16(bp->pf.port_id); |
4142 | do { |
4143 | u16 xfer_size; |
4144 | |
4145 | xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); |
4146 | data_length -= xfer_size; |
4147 | req->page_offset = cpu_to_le16(start_addr + byte_offset); |
4148 | req->data_length = xfer_size; |
4149 | req->enables = |
4150 | cpu_to_le32((start_addr + byte_offset ? |
4151 | PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : |
4152 | 0) | |
4153 | (bank ? |
4154 | PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : |
4155 | 0)); |
4156 | rc = hwrm_req_send(bp, req); |
4157 | if (!rc) |
4158 | memcpy(buf + byte_offset, output->data, xfer_size); |
4159 | byte_offset += xfer_size; |
4160 | } while (!rc && data_length > 0); |
4161 | hwrm_req_drop(bp, req); |
4162 | |
4163 | return rc; |
4164 | } |
4165 | |
4166 | static int bnxt_get_module_info(struct net_device *dev, |
4167 | struct ethtool_modinfo *modinfo) |
4168 | { |
4169 | u8 data[SFF_DIAG_SUPPORT_OFFSET + 1]; |
4170 | struct bnxt *bp = netdev_priv(dev); |
4171 | int rc; |
4172 | |
4173 | /* No point in going further if phy status indicates |
4174 | * module is not inserted or if it is powered down or |
4175 | * if it is of type 10GBase-T |
4176 | */ |
4177 | if (bp->link_info.module_status > |
4178 | PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) |
4179 | return -EOPNOTSUPP; |
4180 | |
4181 | /* This feature is not supported in older firmware versions */ |
4182 | if (bp->hwrm_spec_code < 0x10202) |
4183 | return -EOPNOTSUPP; |
4184 | |
4185 | rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, page_number: 0, bank: 0, start_addr: 0, |
4186 | SFF_DIAG_SUPPORT_OFFSET + 1, |
4187 | buf: data); |
4188 | if (!rc) { |
4189 | u8 module_id = data[0]; |
4190 | u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET]; |
4191 | |
4192 | switch (module_id) { |
4193 | case SFF_MODULE_ID_SFP: |
4194 | modinfo->type = ETH_MODULE_SFF_8472; |
4195 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; |
4196 | if (!diag_supported) |
4197 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; |
4198 | break; |
4199 | case SFF_MODULE_ID_QSFP: |
4200 | case SFF_MODULE_ID_QSFP_PLUS: |
4201 | modinfo->type = ETH_MODULE_SFF_8436; |
4202 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; |
4203 | break; |
4204 | case SFF_MODULE_ID_QSFP28: |
4205 | modinfo->type = ETH_MODULE_SFF_8636; |
4206 | modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; |
4207 | break; |
4208 | default: |
4209 | rc = -EOPNOTSUPP; |
4210 | break; |
4211 | } |
4212 | } |
4213 | return rc; |
4214 | } |
4215 | |
4216 | static int bnxt_get_module_eeprom(struct net_device *dev, |
4217 | struct ethtool_eeprom *eeprom, |
4218 | u8 *data) |
4219 | { |
4220 | struct bnxt *bp = netdev_priv(dev); |
4221 | u16 start = eeprom->offset, length = eeprom->len; |
4222 | int rc = 0; |
4223 | |
4224 | memset(data, 0, eeprom->len); |
4225 | |
4226 | /* Read A0 portion of the EEPROM */ |
4227 | if (start < ETH_MODULE_SFF_8436_LEN) { |
4228 | if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) |
4229 | length = ETH_MODULE_SFF_8436_LEN - start; |
4230 | rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, page_number: 0, bank: 0, |
4231 | start_addr: start, data_length: length, buf: data); |
4232 | if (rc) |
4233 | return rc; |
4234 | start += length; |
4235 | data += length; |
4236 | length = eeprom->len - length; |
4237 | } |
4238 | |
4239 | /* Read A2 portion of the EEPROM */ |
4240 | if (length) { |
4241 | start -= ETH_MODULE_SFF_8436_LEN; |
4242 | rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, page_number: 0, bank: 0, |
4243 | start_addr: start, data_length: length, buf: data); |
4244 | } |
4245 | return rc; |
4246 | } |
4247 | |
4248 | static int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack) |
4249 | { |
4250 | if (bp->link_info.module_status <= |
4251 | PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) |
4252 | return 0; |
4253 | |
4254 | switch (bp->link_info.module_status) { |
4255 | case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: |
4256 | NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down" ); |
4257 | break; |
4258 | case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: |
4259 | NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted" ); |
4260 | break; |
4261 | case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: |
4262 | NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault" ); |
4263 | break; |
4264 | default: |
4265 | NL_SET_ERR_MSG_MOD(extack, "Unknown error" ); |
4266 | break; |
4267 | } |
4268 | return -EINVAL; |
4269 | } |
4270 | |
4271 | static int bnxt_get_module_eeprom_by_page(struct net_device *dev, |
4272 | const struct ethtool_module_eeprom *page_data, |
4273 | struct netlink_ext_ack *extack) |
4274 | { |
4275 | struct bnxt *bp = netdev_priv(dev); |
4276 | int rc; |
4277 | |
4278 | rc = bnxt_get_module_status(bp, extack); |
4279 | if (rc) |
4280 | return rc; |
4281 | |
4282 | if (bp->hwrm_spec_code < 0x10202) { |
4283 | NL_SET_ERR_MSG_MOD(extack, "Firmware version too old" ); |
4284 | return -EINVAL; |
4285 | } |
4286 | |
4287 | if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { |
4288 | NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection" ); |
4289 | return -EINVAL; |
4290 | } |
4291 | |
4292 | rc = bnxt_read_sfp_module_eeprom_info(bp, i2c_addr: page_data->i2c_address << 1, |
4293 | page_number: page_data->page, bank: page_data->bank, |
4294 | start_addr: page_data->offset, |
4295 | data_length: page_data->length, |
4296 | buf: page_data->data); |
4297 | if (rc) { |
4298 | NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed" ); |
4299 | return rc; |
4300 | } |
4301 | return page_data->length; |
4302 | } |
4303 | |
4304 | static int bnxt_nway_reset(struct net_device *dev) |
4305 | { |
4306 | int rc = 0; |
4307 | |
4308 | struct bnxt *bp = netdev_priv(dev); |
4309 | struct bnxt_link_info *link_info = &bp->link_info; |
4310 | |
4311 | if (!BNXT_PHY_CFG_ABLE(bp)) |
4312 | return -EOPNOTSUPP; |
4313 | |
4314 | if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) |
4315 | return -EINVAL; |
4316 | |
4317 | if (netif_running(dev)) |
4318 | rc = bnxt_hwrm_set_link_setting(bp, true, false); |
4319 | |
4320 | return rc; |
4321 | } |
4322 | |
4323 | static int bnxt_set_phys_id(struct net_device *dev, |
4324 | enum ethtool_phys_id_state state) |
4325 | { |
4326 | struct hwrm_port_led_cfg_input *req; |
4327 | struct bnxt *bp = netdev_priv(dev); |
4328 | struct bnxt_pf_info *pf = &bp->pf; |
4329 | struct bnxt_led_cfg *led_cfg; |
4330 | u8 led_state; |
4331 | __le16 duration; |
4332 | int rc, i; |
4333 | |
4334 | if (!bp->num_leds || BNXT_VF(bp)) |
4335 | return -EOPNOTSUPP; |
4336 | |
4337 | if (state == ETHTOOL_ID_ACTIVE) { |
4338 | led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT; |
4339 | duration = cpu_to_le16(500); |
4340 | } else if (state == ETHTOOL_ID_INACTIVE) { |
4341 | led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT; |
4342 | duration = cpu_to_le16(0); |
4343 | } else { |
4344 | return -EINVAL; |
4345 | } |
4346 | rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG); |
4347 | if (rc) |
4348 | return rc; |
4349 | |
4350 | req->port_id = cpu_to_le16(pf->port_id); |
4351 | req->num_leds = bp->num_leds; |
4352 | led_cfg = (struct bnxt_led_cfg *)&req->led0_id; |
4353 | for (i = 0; i < bp->num_leds; i++, led_cfg++) { |
4354 | req->enables |= BNXT_LED_DFLT_ENABLES(i); |
4355 | led_cfg->led_id = bp->leds[i].led_id; |
4356 | led_cfg->led_state = led_state; |
4357 | led_cfg->led_blink_on = duration; |
4358 | led_cfg->led_blink_off = duration; |
4359 | led_cfg->led_group_id = bp->leds[i].led_group_id; |
4360 | } |
4361 | return hwrm_req_send(bp, req); |
4362 | } |
4363 | |
4364 | static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) |
4365 | { |
4366 | struct hwrm_selftest_irq_input *req; |
4367 | int rc; |
4368 | |
4369 | rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ); |
4370 | if (rc) |
4371 | return rc; |
4372 | |
4373 | req->cmpl_ring = cpu_to_le16(cmpl_ring); |
4374 | return hwrm_req_send(bp, req); |
4375 | } |
4376 | |
4377 | static int bnxt_test_irq(struct bnxt *bp) |
4378 | { |
4379 | int i; |
4380 | |
4381 | for (i = 0; i < bp->cp_nr_rings; i++) { |
4382 | u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; |
4383 | int rc; |
4384 | |
4385 | rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); |
4386 | if (rc) |
4387 | return rc; |
4388 | } |
4389 | return 0; |
4390 | } |
4391 | |
4392 | static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) |
4393 | { |
4394 | struct hwrm_port_mac_cfg_input *req; |
4395 | int rc; |
4396 | |
4397 | rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); |
4398 | if (rc) |
4399 | return rc; |
4400 | |
4401 | req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); |
4402 | if (enable) |
4403 | req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; |
4404 | else |
4405 | req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; |
4406 | return hwrm_req_send(bp, req); |
4407 | } |
4408 | |
4409 | static int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds) |
4410 | { |
4411 | struct hwrm_port_phy_qcaps_output *resp; |
4412 | struct hwrm_port_phy_qcaps_input *req; |
4413 | int rc; |
4414 | |
4415 | rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS); |
4416 | if (rc) |
4417 | return rc; |
4418 | |
4419 | resp = hwrm_req_hold(bp, req); |
4420 | rc = hwrm_req_send(bp, req); |
4421 | if (!rc) |
4422 | *force_speeds = le16_to_cpu(resp->supported_speeds_force_mode); |
4423 | |
4424 | hwrm_req_drop(bp, req); |
4425 | return rc; |
4426 | } |
4427 | |
4428 | static int bnxt_disable_an_for_lpbk(struct bnxt *bp, |
4429 | struct hwrm_port_phy_cfg_input *req) |
4430 | { |
4431 | struct bnxt_link_info *link_info = &bp->link_info; |
4432 | u16 fw_advertising; |
4433 | u16 fw_speed; |
4434 | int rc; |
4435 | |
4436 | if (!link_info->autoneg || |
4437 | (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK)) |
4438 | return 0; |
4439 | |
4440 | rc = bnxt_query_force_speeds(bp, force_speeds: &fw_advertising); |
4441 | if (rc) |
4442 | return rc; |
4443 | |
4444 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; |
4445 | if (BNXT_LINK_IS_UP(bp)) |
4446 | fw_speed = bp->link_info.link_speed; |
4447 | else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) |
4448 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; |
4449 | else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) |
4450 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; |
4451 | else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) |
4452 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; |
4453 | else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) |
4454 | fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; |
4455 | |
4456 | req->force_link_speed = cpu_to_le16(fw_speed); |
4457 | req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | |
4458 | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); |
4459 | rc = hwrm_req_send(bp, req); |
4460 | req->flags = 0; |
4461 | req->force_link_speed = cpu_to_le16(0); |
4462 | return rc; |
4463 | } |
4464 | |
4465 | static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext) |
4466 | { |
4467 | struct hwrm_port_phy_cfg_input *req; |
4468 | int rc; |
4469 | |
4470 | rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG); |
4471 | if (rc) |
4472 | return rc; |
4473 | |
4474 | /* prevent bnxt_disable_an_for_lpbk() from consuming the request */ |
4475 | hwrm_req_hold(bp, req); |
4476 | |
4477 | if (enable) { |
4478 | bnxt_disable_an_for_lpbk(bp, req); |
4479 | if (ext) |
4480 | req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL; |
4481 | else |
4482 | req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; |
4483 | } else { |
4484 | req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; |
4485 | } |
4486 | req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); |
4487 | rc = hwrm_req_send(bp, req); |
4488 | hwrm_req_drop(bp, req); |
4489 | return rc; |
4490 | } |
4491 | |
4492 | static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, |
4493 | u32 raw_cons, int pkt_size) |
4494 | { |
4495 | struct bnxt_napi *bnapi = cpr->bnapi; |
4496 | struct bnxt_rx_ring_info *rxr; |
4497 | struct bnxt_sw_rx_bd *rx_buf; |
4498 | struct rx_cmp *rxcmp; |
4499 | u16 cp_cons, cons; |
4500 | u8 *data; |
4501 | u32 len; |
4502 | int i; |
4503 | |
4504 | rxr = bnapi->rx_ring; |
4505 | cp_cons = RING_CMP(raw_cons); |
4506 | rxcmp = (struct rx_cmp *) |
4507 | &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; |
4508 | cons = rxcmp->rx_cmp_opaque; |
4509 | rx_buf = &rxr->rx_buf_ring[cons]; |
4510 | data = rx_buf->data_ptr; |
4511 | len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; |
4512 | if (len != pkt_size) |
4513 | return -EIO; |
4514 | i = ETH_ALEN; |
4515 | if (!ether_addr_equal(addr1: data + i, addr2: bnapi->bp->dev->dev_addr)) |
4516 | return -EIO; |
4517 | i += ETH_ALEN; |
4518 | for ( ; i < pkt_size; i++) { |
4519 | if (data[i] != (u8)(i & 0xff)) |
4520 | return -EIO; |
4521 | } |
4522 | return 0; |
4523 | } |
4524 | |
4525 | static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, |
4526 | int pkt_size) |
4527 | { |
4528 | struct tx_cmp *txcmp; |
4529 | int rc = -EIO; |
4530 | u32 raw_cons; |
4531 | u32 cons; |
4532 | int i; |
4533 | |
4534 | raw_cons = cpr->cp_raw_cons; |
4535 | for (i = 0; i < 200; i++) { |
4536 | cons = RING_CMP(raw_cons); |
4537 | txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; |
4538 | |
4539 | if (!TX_CMP_VALID(txcmp, raw_cons)) { |
4540 | udelay(5); |
4541 | continue; |
4542 | } |
4543 | |
4544 | /* The valid test of the entry must be done first before |
4545 | * reading any further. |
4546 | */ |
4547 | dma_rmb(); |
4548 | if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP || |
4549 | TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_V3_CMP) { |
4550 | rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size); |
4551 | raw_cons = NEXT_RAW_CMP(raw_cons); |
4552 | raw_cons = NEXT_RAW_CMP(raw_cons); |
4553 | break; |
4554 | } |
4555 | raw_cons = NEXT_RAW_CMP(raw_cons); |
4556 | } |
4557 | cpr->cp_raw_cons = raw_cons; |
4558 | return rc; |
4559 | } |
4560 | |
4561 | static int bnxt_run_loopback(struct bnxt *bp) |
4562 | { |
4563 | struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; |
4564 | struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; |
4565 | struct bnxt_cp_ring_info *cpr; |
4566 | int pkt_size, i = 0; |
4567 | struct sk_buff *skb; |
4568 | dma_addr_t map; |
4569 | u8 *data; |
4570 | int rc; |
4571 | |
4572 | cpr = &rxr->bnapi->cp_ring; |
4573 | if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) |
4574 | cpr = rxr->rx_cpr; |
4575 | pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); |
4576 | skb = netdev_alloc_skb(dev: bp->dev, length: pkt_size); |
4577 | if (!skb) |
4578 | return -ENOMEM; |
4579 | data = skb_put(skb, len: pkt_size); |
4580 | ether_addr_copy(dst: &data[i], src: bp->dev->dev_addr); |
4581 | i += ETH_ALEN; |
4582 | ether_addr_copy(dst: &data[i], src: bp->dev->dev_addr); |
4583 | i += ETH_ALEN; |
4584 | for ( ; i < pkt_size; i++) |
4585 | data[i] = (u8)(i & 0xff); |
4586 | |
4587 | map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, |
4588 | DMA_TO_DEVICE); |
4589 | if (dma_mapping_error(dev: &bp->pdev->dev, dma_addr: map)) { |
4590 | dev_kfree_skb(skb); |
4591 | return -EIO; |
4592 | } |
4593 | bnxt_xmit_bd(bp, txr, mapping: map, len: pkt_size, NULL); |
4594 | |
4595 | /* Sync BD data before updating doorbell */ |
4596 | wmb(); |
4597 | |
4598 | bnxt_db_write(bp, db: &txr->tx_db, idx: txr->tx_prod); |
4599 | rc = bnxt_poll_loopback(bp, cpr, pkt_size); |
4600 | |
4601 | dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE); |
4602 | dev_kfree_skb(skb); |
4603 | return rc; |
4604 | } |
4605 | |
4606 | static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) |
4607 | { |
4608 | struct hwrm_selftest_exec_output *resp; |
4609 | struct hwrm_selftest_exec_input *req; |
4610 | int rc; |
4611 | |
4612 | rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC); |
4613 | if (rc) |
4614 | return rc; |
4615 | |
4616 | hwrm_req_timeout(bp, req, timeout: bp->test_info->timeout); |
4617 | req->flags = test_mask; |
4618 | |
4619 | resp = hwrm_req_hold(bp, req); |
4620 | rc = hwrm_req_send(bp, req); |
4621 | *test_results = resp->test_success; |
4622 | hwrm_req_drop(bp, req); |
4623 | return rc; |
4624 | } |
4625 | |
4626 | #define BNXT_DRV_TESTS 4 |
4627 | #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) |
4628 | #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) |
4629 | #define BNXT_EXTLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) |
4630 | #define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 3) |
4631 | |
4632 | static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, |
4633 | u64 *buf) |
4634 | { |
4635 | struct bnxt *bp = netdev_priv(dev); |
4636 | bool do_ext_lpbk = false; |
4637 | bool offline = false; |
4638 | u8 test_results = 0; |
4639 | u8 test_mask = 0; |
4640 | int rc = 0, i; |
4641 | |
4642 | if (!bp->num_tests || !BNXT_PF(bp)) |
4643 | return; |
4644 | memset(buf, 0, sizeof(u64) * bp->num_tests); |
4645 | if (!netif_running(dev)) { |
4646 | etest->flags |= ETH_TEST_FL_FAILED; |
4647 | return; |
4648 | } |
4649 | |
4650 | if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) && |
4651 | (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK)) |
4652 | do_ext_lpbk = true; |
4653 | |
4654 | if (etest->flags & ETH_TEST_FL_OFFLINE) { |
4655 | if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) { |
4656 | etest->flags |= ETH_TEST_FL_FAILED; |
4657 | netdev_warn(dev, format: "Offline tests cannot be run with active VFs or on shared PF\n" ); |
4658 | return; |
4659 | } |
4660 | offline = true; |
4661 | } |
4662 | |
4663 | for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { |
4664 | u8 bit_val = 1 << i; |
4665 | |
4666 | if (!(bp->test_info->offline_mask & bit_val)) |
4667 | test_mask |= bit_val; |
4668 | else if (offline) |
4669 | test_mask |= bit_val; |
4670 | } |
4671 | if (!offline) { |
4672 | bnxt_run_fw_tests(bp, test_mask, test_results: &test_results); |
4673 | } else { |
4674 | bnxt_ulp_stop(bp); |
4675 | bnxt_close_nic(bp, true, false); |
4676 | bnxt_run_fw_tests(bp, test_mask, test_results: &test_results); |
4677 | |
4678 | buf[BNXT_MACLPBK_TEST_IDX] = 1; |
4679 | bnxt_hwrm_mac_loopback(bp, enable: true); |
4680 | msleep(msecs: 250); |
4681 | rc = bnxt_half_open_nic(bp); |
4682 | if (rc) { |
4683 | bnxt_hwrm_mac_loopback(bp, enable: false); |
4684 | etest->flags |= ETH_TEST_FL_FAILED; |
4685 | bnxt_ulp_start(bp, err: rc); |
4686 | return; |
4687 | } |
4688 | if (bnxt_run_loopback(bp)) |
4689 | etest->flags |= ETH_TEST_FL_FAILED; |
4690 | else |
4691 | buf[BNXT_MACLPBK_TEST_IDX] = 0; |
4692 | |
4693 | bnxt_hwrm_mac_loopback(bp, enable: false); |
4694 | bnxt_hwrm_phy_loopback(bp, enable: true, ext: false); |
4695 | msleep(msecs: 1000); |
4696 | if (bnxt_run_loopback(bp)) { |
4697 | buf[BNXT_PHYLPBK_TEST_IDX] = 1; |
4698 | etest->flags |= ETH_TEST_FL_FAILED; |
4699 | } |
4700 | if (do_ext_lpbk) { |
4701 | etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; |
4702 | bnxt_hwrm_phy_loopback(bp, enable: true, ext: true); |
4703 | msleep(msecs: 1000); |
4704 | if (bnxt_run_loopback(bp)) { |
4705 | buf[BNXT_EXTLPBK_TEST_IDX] = 1; |
4706 | etest->flags |= ETH_TEST_FL_FAILED; |
4707 | } |
4708 | } |
4709 | bnxt_hwrm_phy_loopback(bp, enable: false, ext: false); |
4710 | bnxt_half_close_nic(bp); |
4711 | rc = bnxt_open_nic(bp, true, true); |
4712 | bnxt_ulp_start(bp, err: rc); |
4713 | } |
4714 | if (rc || bnxt_test_irq(bp)) { |
4715 | buf[BNXT_IRQ_TEST_IDX] = 1; |
4716 | etest->flags |= ETH_TEST_FL_FAILED; |
4717 | } |
4718 | for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { |
4719 | u8 bit_val = 1 << i; |
4720 | |
4721 | if ((test_mask & bit_val) && !(test_results & bit_val)) { |
4722 | buf[i] = 1; |
4723 | etest->flags |= ETH_TEST_FL_FAILED; |
4724 | } |
4725 | } |
4726 | } |
4727 | |
4728 | static int bnxt_reset(struct net_device *dev, u32 *flags) |
4729 | { |
4730 | struct bnxt *bp = netdev_priv(dev); |
4731 | bool reload = false; |
4732 | u32 req = *flags; |
4733 | |
4734 | if (!req) |
4735 | return -EINVAL; |
4736 | |
4737 | if (!BNXT_PF(bp)) { |
4738 | netdev_err(dev, format: "Reset is not supported from a VF\n" ); |
4739 | return -EOPNOTSUPP; |
4740 | } |
4741 | |
4742 | if (pci_vfs_assigned(dev: bp->pdev) && |
4743 | !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { |
4744 | netdev_err(dev, |
4745 | format: "Reset not allowed when VFs are assigned to VMs\n" ); |
4746 | return -EBUSY; |
4747 | } |
4748 | |
4749 | if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) { |
4750 | /* This feature is not supported in older firmware versions */ |
4751 | if (bp->hwrm_spec_code >= 0x10803) { |
4752 | if (!bnxt_firmware_reset_chip(dev)) { |
4753 | netdev_info(dev, format: "Firmware reset request successful.\n" ); |
4754 | if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) |
4755 | reload = true; |
4756 | *flags &= ~BNXT_FW_RESET_CHIP; |
4757 | } |
4758 | } else if (req == BNXT_FW_RESET_CHIP) { |
4759 | return -EOPNOTSUPP; /* only request, fail hard */ |
4760 | } |
4761 | } |
4762 | |
4763 | if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) { |
4764 | /* This feature is not supported in older firmware versions */ |
4765 | if (bp->hwrm_spec_code >= 0x10803) { |
4766 | if (!bnxt_firmware_reset_ap(dev)) { |
4767 | netdev_info(dev, format: "Reset application processor successful.\n" ); |
4768 | reload = true; |
4769 | *flags &= ~BNXT_FW_RESET_AP; |
4770 | } |
4771 | } else if (req == BNXT_FW_RESET_AP) { |
4772 | return -EOPNOTSUPP; /* only request, fail hard */ |
4773 | } |
4774 | } |
4775 | |
4776 | if (reload) |
4777 | netdev_info(dev, format: "Reload driver to complete reset\n" ); |
4778 | |
4779 | return 0; |
4780 | } |
4781 | |
4782 | static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) |
4783 | { |
4784 | struct bnxt *bp = netdev_priv(dev); |
4785 | |
4786 | if (dump->flag > BNXT_DUMP_CRASH) { |
4787 | netdev_info(dev, format: "Supports only Live(0) and Crash(1) dumps.\n" ); |
4788 | return -EINVAL; |
4789 | } |
4790 | |
4791 | if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { |
4792 | netdev_info(dev, format: "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n" ); |
4793 | return -EOPNOTSUPP; |
4794 | } |
4795 | |
4796 | bp->dump_flag = dump->flag; |
4797 | return 0; |
4798 | } |
4799 | |
4800 | static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) |
4801 | { |
4802 | struct bnxt *bp = netdev_priv(dev); |
4803 | |
4804 | if (bp->hwrm_spec_code < 0x10801) |
4805 | return -EOPNOTSUPP; |
4806 | |
4807 | dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 | |
4808 | bp->ver_resp.hwrm_fw_min_8b << 16 | |
4809 | bp->ver_resp.hwrm_fw_bld_8b << 8 | |
4810 | bp->ver_resp.hwrm_fw_rsvd_8b; |
4811 | |
4812 | dump->flag = bp->dump_flag; |
4813 | dump->len = bnxt_get_coredump_length(bp, dump_type: bp->dump_flag); |
4814 | return 0; |
4815 | } |
4816 | |
4817 | static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, |
4818 | void *buf) |
4819 | { |
4820 | struct bnxt *bp = netdev_priv(dev); |
4821 | |
4822 | if (bp->hwrm_spec_code < 0x10801) |
4823 | return -EOPNOTSUPP; |
4824 | |
4825 | memset(buf, 0, dump->len); |
4826 | |
4827 | dump->flag = bp->dump_flag; |
4828 | return bnxt_get_coredump(bp, dump_type: dump->flag, buf, dump_len: &dump->len); |
4829 | } |
4830 | |
4831 | static int bnxt_get_ts_info(struct net_device *dev, |
4832 | struct ethtool_ts_info *info) |
4833 | { |
4834 | struct bnxt *bp = netdev_priv(dev); |
4835 | struct bnxt_ptp_cfg *ptp; |
4836 | |
4837 | ptp = bp->ptp_cfg; |
4838 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
4839 | SOF_TIMESTAMPING_RX_SOFTWARE | |
4840 | SOF_TIMESTAMPING_SOFTWARE; |
4841 | |
4842 | info->phc_index = -1; |
4843 | if (!ptp) |
4844 | return 0; |
4845 | |
4846 | info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | |
4847 | SOF_TIMESTAMPING_RX_HARDWARE | |
4848 | SOF_TIMESTAMPING_RAW_HARDWARE; |
4849 | if (ptp->ptp_clock) |
4850 | info->phc_index = ptp_clock_index(ptp: ptp->ptp_clock); |
4851 | |
4852 | info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); |
4853 | |
4854 | info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | |
4855 | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | |
4856 | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); |
4857 | |
4858 | if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) |
4859 | info->rx_filters |= (1 << HWTSTAMP_FILTER_ALL); |
4860 | return 0; |
4861 | } |
4862 | |
4863 | void bnxt_ethtool_init(struct bnxt *bp) |
4864 | { |
4865 | struct hwrm_selftest_qlist_output *resp; |
4866 | struct hwrm_selftest_qlist_input *req; |
4867 | struct bnxt_test_info *test_info; |
4868 | struct net_device *dev = bp->dev; |
4869 | int i, rc; |
4870 | |
4871 | if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER)) |
4872 | bnxt_get_pkgver(dev); |
4873 | |
4874 | bp->num_tests = 0; |
4875 | if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp)) |
4876 | return; |
4877 | |
4878 | test_info = bp->test_info; |
4879 | if (!test_info) { |
4880 | test_info = kzalloc(size: sizeof(*bp->test_info), GFP_KERNEL); |
4881 | if (!test_info) |
4882 | return; |
4883 | bp->test_info = test_info; |
4884 | } |
4885 | |
4886 | if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST)) |
4887 | return; |
4888 | |
4889 | resp = hwrm_req_hold(bp, req); |
4890 | rc = hwrm_req_send_silent(bp, req); |
4891 | if (rc) |
4892 | goto ethtool_init_exit; |
4893 | |
4894 | bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; |
4895 | if (bp->num_tests > BNXT_MAX_TEST) |
4896 | bp->num_tests = BNXT_MAX_TEST; |
4897 | |
4898 | test_info->offline_mask = resp->offline_tests; |
4899 | test_info->timeout = le16_to_cpu(resp->test_timeout); |
4900 | if (!test_info->timeout) |
4901 | test_info->timeout = HWRM_CMD_TIMEOUT; |
4902 | for (i = 0; i < bp->num_tests; i++) { |
4903 | char *str = test_info->string[i]; |
4904 | char *fw_str = resp->test_name[i]; |
4905 | |
4906 | if (i == BNXT_MACLPBK_TEST_IDX) { |
4907 | strcpy(p: str, q: "Mac loopback test (offline)" ); |
4908 | } else if (i == BNXT_PHYLPBK_TEST_IDX) { |
4909 | strcpy(p: str, q: "Phy loopback test (offline)" ); |
4910 | } else if (i == BNXT_EXTLPBK_TEST_IDX) { |
4911 | strcpy(p: str, q: "Ext loopback test (offline)" ); |
4912 | } else if (i == BNXT_IRQ_TEST_IDX) { |
4913 | strcpy(p: str, q: "Interrupt_test (offline)" ); |
4914 | } else { |
4915 | snprintf(buf: str, ETH_GSTRING_LEN, fmt: "%s test (%s)" , |
4916 | fw_str, test_info->offline_mask & (1 << i) ? |
4917 | "offline" : "online" ); |
4918 | } |
4919 | } |
4920 | |
4921 | ethtool_init_exit: |
4922 | hwrm_req_drop(bp, req); |
4923 | } |
4924 | |
4925 | static void bnxt_get_eth_phy_stats(struct net_device *dev, |
4926 | struct ethtool_eth_phy_stats *phy_stats) |
4927 | { |
4928 | struct bnxt *bp = netdev_priv(dev); |
4929 | u64 *rx; |
4930 | |
4931 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) |
4932 | return; |
4933 | |
4934 | rx = bp->rx_port_stats_ext.sw_stats; |
4935 | phy_stats->SymbolErrorDuringCarrier = |
4936 | *(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err)); |
4937 | } |
4938 | |
4939 | static void bnxt_get_eth_mac_stats(struct net_device *dev, |
4940 | struct ethtool_eth_mac_stats *mac_stats) |
4941 | { |
4942 | struct bnxt *bp = netdev_priv(dev); |
4943 | u64 *rx, *tx; |
4944 | |
4945 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) |
4946 | return; |
4947 | |
4948 | rx = bp->port_stats.sw_stats; |
4949 | tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; |
4950 | |
4951 | mac_stats->FramesReceivedOK = |
4952 | BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames); |
4953 | mac_stats->FramesTransmittedOK = |
4954 | BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames); |
4955 | mac_stats->FrameCheckSequenceErrors = |
4956 | BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames); |
4957 | mac_stats->AlignmentErrors = |
4958 | BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames); |
4959 | mac_stats->OutOfRangeLengthField = |
4960 | BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames); |
4961 | } |
4962 | |
4963 | static void bnxt_get_eth_ctrl_stats(struct net_device *dev, |
4964 | struct ethtool_eth_ctrl_stats *ctrl_stats) |
4965 | { |
4966 | struct bnxt *bp = netdev_priv(dev); |
4967 | u64 *rx; |
4968 | |
4969 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) |
4970 | return; |
4971 | |
4972 | rx = bp->port_stats.sw_stats; |
4973 | ctrl_stats->MACControlFramesReceived = |
4974 | BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames); |
4975 | } |
4976 | |
4977 | static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = { |
4978 | { 0, 64 }, |
4979 | { 65, 127 }, |
4980 | { 128, 255 }, |
4981 | { 256, 511 }, |
4982 | { 512, 1023 }, |
4983 | { 1024, 1518 }, |
4984 | { 1519, 2047 }, |
4985 | { 2048, 4095 }, |
4986 | { 4096, 9216 }, |
4987 | { 9217, 16383 }, |
4988 | {} |
4989 | }; |
4990 | |
4991 | static void bnxt_get_rmon_stats(struct net_device *dev, |
4992 | struct ethtool_rmon_stats *rmon_stats, |
4993 | const struct ethtool_rmon_hist_range **ranges) |
4994 | { |
4995 | struct bnxt *bp = netdev_priv(dev); |
4996 | u64 *rx, *tx; |
4997 | |
4998 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS)) |
4999 | return; |
5000 | |
5001 | rx = bp->port_stats.sw_stats; |
5002 | tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8; |
5003 | |
5004 | rmon_stats->jabbers = |
5005 | BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames); |
5006 | rmon_stats->oversize_pkts = |
5007 | BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames); |
5008 | rmon_stats->undersize_pkts = |
5009 | BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames); |
5010 | |
5011 | rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames); |
5012 | rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames); |
5013 | rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames); |
5014 | rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames); |
5015 | rmon_stats->hist[4] = |
5016 | BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames); |
5017 | rmon_stats->hist[5] = |
5018 | BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames); |
5019 | rmon_stats->hist[6] = |
5020 | BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames); |
5021 | rmon_stats->hist[7] = |
5022 | BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames); |
5023 | rmon_stats->hist[8] = |
5024 | BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames); |
5025 | rmon_stats->hist[9] = |
5026 | BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames); |
5027 | |
5028 | rmon_stats->hist_tx[0] = |
5029 | BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames); |
5030 | rmon_stats->hist_tx[1] = |
5031 | BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames); |
5032 | rmon_stats->hist_tx[2] = |
5033 | BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames); |
5034 | rmon_stats->hist_tx[3] = |
5035 | BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames); |
5036 | rmon_stats->hist_tx[4] = |
5037 | BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames); |
5038 | rmon_stats->hist_tx[5] = |
5039 | BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames); |
5040 | rmon_stats->hist_tx[6] = |
5041 | BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames); |
5042 | rmon_stats->hist_tx[7] = |
5043 | BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames); |
5044 | rmon_stats->hist_tx[8] = |
5045 | BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames); |
5046 | rmon_stats->hist_tx[9] = |
5047 | BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames); |
5048 | |
5049 | *ranges = bnxt_rmon_ranges; |
5050 | } |
5051 | |
5052 | static void bnxt_get_link_ext_stats(struct net_device *dev, |
5053 | struct ethtool_link_ext_stats *stats) |
5054 | { |
5055 | struct bnxt *bp = netdev_priv(dev); |
5056 | u64 *rx; |
5057 | |
5058 | if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT)) |
5059 | return; |
5060 | |
5061 | rx = bp->rx_port_stats_ext.sw_stats; |
5062 | stats->link_down_events = |
5063 | *(rx + BNXT_RX_STATS_EXT_OFFSET(link_down_events)); |
5064 | } |
5065 | |
5066 | void bnxt_ethtool_free(struct bnxt *bp) |
5067 | { |
5068 | kfree(objp: bp->test_info); |
5069 | bp->test_info = NULL; |
5070 | } |
5071 | |
5072 | const struct ethtool_ops bnxt_ethtool_ops = { |
5073 | .cap_link_lanes_supported = 1, |
5074 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
5075 | ETHTOOL_COALESCE_MAX_FRAMES | |
5076 | ETHTOOL_COALESCE_USECS_IRQ | |
5077 | ETHTOOL_COALESCE_MAX_FRAMES_IRQ | |
5078 | ETHTOOL_COALESCE_STATS_BLOCK_USECS | |
5079 | ETHTOOL_COALESCE_USE_ADAPTIVE_RX | |
5080 | ETHTOOL_COALESCE_USE_CQE, |
5081 | .get_link_ksettings = bnxt_get_link_ksettings, |
5082 | .set_link_ksettings = bnxt_set_link_ksettings, |
5083 | .get_fec_stats = bnxt_get_fec_stats, |
5084 | .get_fecparam = bnxt_get_fecparam, |
5085 | .set_fecparam = bnxt_set_fecparam, |
5086 | .get_pause_stats = bnxt_get_pause_stats, |
5087 | .get_pauseparam = bnxt_get_pauseparam, |
5088 | .set_pauseparam = bnxt_set_pauseparam, |
5089 | .get_drvinfo = bnxt_get_drvinfo, |
5090 | .get_regs_len = bnxt_get_regs_len, |
5091 | .get_regs = bnxt_get_regs, |
5092 | .get_wol = bnxt_get_wol, |
5093 | .set_wol = bnxt_set_wol, |
5094 | .get_coalesce = bnxt_get_coalesce, |
5095 | .set_coalesce = bnxt_set_coalesce, |
5096 | .get_msglevel = bnxt_get_msglevel, |
5097 | .set_msglevel = bnxt_set_msglevel, |
5098 | .get_sset_count = bnxt_get_sset_count, |
5099 | .get_strings = bnxt_get_strings, |
5100 | .get_ethtool_stats = bnxt_get_ethtool_stats, |
5101 | .set_ringparam = bnxt_set_ringparam, |
5102 | .get_ringparam = bnxt_get_ringparam, |
5103 | .get_channels = bnxt_get_channels, |
5104 | .set_channels = bnxt_set_channels, |
5105 | .get_rxnfc = bnxt_get_rxnfc, |
5106 | .set_rxnfc = bnxt_set_rxnfc, |
5107 | .get_rxfh_indir_size = bnxt_get_rxfh_indir_size, |
5108 | .get_rxfh_key_size = bnxt_get_rxfh_key_size, |
5109 | .get_rxfh = bnxt_get_rxfh, |
5110 | .set_rxfh = bnxt_set_rxfh, |
5111 | .flash_device = bnxt_flash_device, |
5112 | .get_eeprom_len = bnxt_get_eeprom_len, |
5113 | .get_eeprom = bnxt_get_eeprom, |
5114 | .set_eeprom = bnxt_set_eeprom, |
5115 | .get_link = bnxt_get_link, |
5116 | .get_link_ext_stats = bnxt_get_link_ext_stats, |
5117 | .get_eee = bnxt_get_eee, |
5118 | .set_eee = bnxt_set_eee, |
5119 | .get_module_info = bnxt_get_module_info, |
5120 | .get_module_eeprom = bnxt_get_module_eeprom, |
5121 | .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, |
5122 | .nway_reset = bnxt_nway_reset, |
5123 | .set_phys_id = bnxt_set_phys_id, |
5124 | .self_test = bnxt_self_test, |
5125 | .get_ts_info = bnxt_get_ts_info, |
5126 | .reset = bnxt_reset, |
5127 | .set_dump = bnxt_set_dump, |
5128 | .get_dump_flag = bnxt_get_dump_flag, |
5129 | .get_dump_data = bnxt_get_dump_data, |
5130 | .get_eth_phy_stats = bnxt_get_eth_phy_stats, |
5131 | .get_eth_mac_stats = bnxt_get_eth_mac_stats, |
5132 | .get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats, |
5133 | .get_rmon_stats = bnxt_get_rmon_stats, |
5134 | }; |
5135 | |