1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Marvell RVU Ethernet driver |
3 | * |
4 | * Copyright (C) 2020 Marvell. |
5 | * |
6 | */ |
7 | |
8 | #include <linux/pci.h> |
9 | #include <linux/ethtool.h> |
10 | #include <linux/stddef.h> |
11 | #include <linux/etherdevice.h> |
12 | #include <linux/log2.h> |
13 | #include <linux/net_tstamp.h> |
14 | #include <linux/linkmode.h> |
15 | |
16 | #include "otx2_common.h" |
17 | #include "otx2_ptp.h" |
18 | |
19 | #define DRV_NAME "rvu-nicpf" |
20 | #define DRV_VF_NAME "rvu-nicvf" |
21 | |
22 | struct otx2_stat { |
23 | char name[ETH_GSTRING_LEN]; |
24 | unsigned int index; |
25 | }; |
26 | |
27 | /* HW device stats */ |
28 | #define OTX2_DEV_STAT(stat) { \ |
29 | .name = #stat, \ |
30 | .index = offsetof(struct otx2_dev_stats, stat) / sizeof(u64), \ |
31 | } |
32 | |
33 | enum link_mode { |
34 | OTX2_MODE_SUPPORTED, |
35 | OTX2_MODE_ADVERTISED |
36 | }; |
37 | |
38 | static const struct otx2_stat otx2_dev_stats[] = { |
39 | OTX2_DEV_STAT(rx_ucast_frames), |
40 | OTX2_DEV_STAT(rx_bcast_frames), |
41 | OTX2_DEV_STAT(rx_mcast_frames), |
42 | |
43 | OTX2_DEV_STAT(tx_ucast_frames), |
44 | OTX2_DEV_STAT(tx_bcast_frames), |
45 | OTX2_DEV_STAT(tx_mcast_frames), |
46 | }; |
47 | |
48 | /* Driver level stats */ |
49 | #define OTX2_DRV_STAT(stat) { \ |
50 | .name = #stat, \ |
51 | .index = offsetof(struct otx2_drv_stats, stat) / sizeof(atomic_t), \ |
52 | } |
53 | |
54 | static const struct otx2_stat otx2_drv_stats[] = { |
55 | OTX2_DRV_STAT(rx_fcs_errs), |
56 | OTX2_DRV_STAT(rx_oversize_errs), |
57 | OTX2_DRV_STAT(rx_undersize_errs), |
58 | OTX2_DRV_STAT(rx_csum_errs), |
59 | OTX2_DRV_STAT(rx_len_errs), |
60 | OTX2_DRV_STAT(rx_other_errs), |
61 | }; |
62 | |
63 | static const struct otx2_stat otx2_queue_stats[] = { |
64 | { "bytes" , 0 }, |
65 | { "frames" , 1 }, |
66 | }; |
67 | |
68 | static const unsigned int otx2_n_dev_stats = ARRAY_SIZE(otx2_dev_stats); |
69 | static const unsigned int otx2_n_drv_stats = ARRAY_SIZE(otx2_drv_stats); |
70 | static const unsigned int otx2_n_queue_stats = ARRAY_SIZE(otx2_queue_stats); |
71 | |
72 | static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf); |
73 | |
74 | static void otx2_get_drvinfo(struct net_device *netdev, |
75 | struct ethtool_drvinfo *info) |
76 | { |
77 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
78 | |
79 | strscpy(info->driver, DRV_NAME, sizeof(info->driver)); |
80 | strscpy(info->bus_info, pci_name(pfvf->pdev), sizeof(info->bus_info)); |
81 | } |
82 | |
83 | static void otx2_get_qset_strings(struct otx2_nic *pfvf, u8 **data, int qset) |
84 | { |
85 | int start_qidx = qset * pfvf->hw.rx_queues; |
86 | int qidx, stats; |
87 | |
88 | for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) { |
89 | for (stats = 0; stats < otx2_n_queue_stats; stats++) { |
90 | sprintf(buf: *data, fmt: "rxq%d: %s" , qidx + start_qidx, |
91 | otx2_queue_stats[stats].name); |
92 | *data += ETH_GSTRING_LEN; |
93 | } |
94 | } |
95 | |
96 | for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { |
97 | for (stats = 0; stats < otx2_n_queue_stats; stats++) { |
98 | if (qidx >= pfvf->hw.non_qos_queues) |
99 | sprintf(buf: *data, fmt: "txq_qos%d: %s" , |
100 | qidx + start_qidx - pfvf->hw.non_qos_queues, |
101 | otx2_queue_stats[stats].name); |
102 | else |
103 | sprintf(buf: *data, fmt: "txq%d: %s" , qidx + start_qidx, |
104 | otx2_queue_stats[stats].name); |
105 | *data += ETH_GSTRING_LEN; |
106 | } |
107 | } |
108 | } |
109 | |
110 | static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data) |
111 | { |
112 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
113 | int stats; |
114 | |
115 | if (sset != ETH_SS_STATS) |
116 | return; |
117 | |
118 | for (stats = 0; stats < otx2_n_dev_stats; stats++) { |
119 | memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN); |
120 | data += ETH_GSTRING_LEN; |
121 | } |
122 | |
123 | for (stats = 0; stats < otx2_n_drv_stats; stats++) { |
124 | memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN); |
125 | data += ETH_GSTRING_LEN; |
126 | } |
127 | |
128 | otx2_get_qset_strings(pfvf, data: &data, qset: 0); |
129 | |
130 | if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) { |
131 | for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) { |
132 | sprintf(buf: data, fmt: "cgx_rxstat%d: " , stats); |
133 | data += ETH_GSTRING_LEN; |
134 | } |
135 | |
136 | for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) { |
137 | sprintf(buf: data, fmt: "cgx_txstat%d: " , stats); |
138 | data += ETH_GSTRING_LEN; |
139 | } |
140 | } |
141 | |
142 | strcpy(p: data, q: "reset_count" ); |
143 | data += ETH_GSTRING_LEN; |
144 | sprintf(buf: data, fmt: "Fec Corrected Errors: " ); |
145 | data += ETH_GSTRING_LEN; |
146 | sprintf(buf: data, fmt: "Fec Uncorrected Errors: " ); |
147 | data += ETH_GSTRING_LEN; |
148 | } |
149 | |
150 | static void otx2_get_qset_stats(struct otx2_nic *pfvf, |
151 | struct ethtool_stats *stats, u64 **data) |
152 | { |
153 | int stat, qidx; |
154 | |
155 | if (!pfvf) |
156 | return; |
157 | for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) { |
158 | if (!otx2_update_rq_stats(pfvf, qidx)) { |
159 | for (stat = 0; stat < otx2_n_queue_stats; stat++) |
160 | *((*data)++) = 0; |
161 | continue; |
162 | } |
163 | for (stat = 0; stat < otx2_n_queue_stats; stat++) |
164 | *((*data)++) = ((u64 *)&pfvf->qset.rq[qidx].stats) |
165 | [otx2_queue_stats[stat].index]; |
166 | } |
167 | |
168 | for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { |
169 | if (!otx2_update_sq_stats(pfvf, qidx)) { |
170 | for (stat = 0; stat < otx2_n_queue_stats; stat++) |
171 | *((*data)++) = 0; |
172 | continue; |
173 | } |
174 | for (stat = 0; stat < otx2_n_queue_stats; stat++) |
175 | *((*data)++) = ((u64 *)&pfvf->qset.sq[qidx].stats) |
176 | [otx2_queue_stats[stat].index]; |
177 | } |
178 | } |
179 | |
180 | static int otx2_get_phy_fec_stats(struct otx2_nic *pfvf) |
181 | { |
182 | struct msg_req *req; |
183 | int rc = -ENOMEM; |
184 | |
185 | mutex_lock(&pfvf->mbox.lock); |
186 | req = otx2_mbox_alloc_msg_cgx_get_phy_fec_stats(mbox: &pfvf->mbox); |
187 | if (!req) |
188 | goto end; |
189 | |
190 | if (!otx2_sync_mbox_msg(mbox: &pfvf->mbox)) |
191 | rc = 0; |
192 | end: |
193 | mutex_unlock(lock: &pfvf->mbox.lock); |
194 | return rc; |
195 | } |
196 | |
197 | /* Get device and per queue statistics */ |
198 | static void otx2_get_ethtool_stats(struct net_device *netdev, |
199 | struct ethtool_stats *stats, u64 *data) |
200 | { |
201 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
202 | u64 fec_corr_blks, fec_uncorr_blks; |
203 | struct cgx_fw_data *rsp; |
204 | int stat; |
205 | |
206 | otx2_get_dev_stats(pfvf); |
207 | for (stat = 0; stat < otx2_n_dev_stats; stat++) |
208 | *(data++) = ((u64 *)&pfvf->hw.dev_stats) |
209 | [otx2_dev_stats[stat].index]; |
210 | |
211 | for (stat = 0; stat < otx2_n_drv_stats; stat++) |
212 | *(data++) = atomic_read(v: &((atomic_t *)&pfvf->hw.drv_stats) |
213 | [otx2_drv_stats[stat].index]); |
214 | |
215 | otx2_get_qset_stats(pfvf, stats, data: &data); |
216 | |
217 | if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) { |
218 | otx2_update_lmac_stats(pfvf); |
219 | for (stat = 0; stat < CGX_RX_STATS_COUNT; stat++) |
220 | *(data++) = pfvf->hw.cgx_rx_stats[stat]; |
221 | for (stat = 0; stat < CGX_TX_STATS_COUNT; stat++) |
222 | *(data++) = pfvf->hw.cgx_tx_stats[stat]; |
223 | } |
224 | |
225 | *(data++) = pfvf->reset_count; |
226 | |
227 | fec_corr_blks = pfvf->hw.cgx_fec_corr_blks; |
228 | fec_uncorr_blks = pfvf->hw.cgx_fec_uncorr_blks; |
229 | |
230 | rsp = otx2_get_fwdata(pfvf); |
231 | if (!IS_ERR(ptr: rsp) && rsp->fwdata.phy.misc.has_fec_stats && |
232 | !otx2_get_phy_fec_stats(pfvf)) { |
233 | /* Fetch fwdata again because it's been recently populated with |
234 | * latest PHY FEC stats. |
235 | */ |
236 | rsp = otx2_get_fwdata(pfvf); |
237 | if (!IS_ERR(ptr: rsp)) { |
238 | struct fec_stats_s *p = &rsp->fwdata.phy.fec_stats; |
239 | |
240 | if (pfvf->linfo.fec == OTX2_FEC_BASER) { |
241 | fec_corr_blks = p->brfec_corr_blks; |
242 | fec_uncorr_blks = p->brfec_uncorr_blks; |
243 | } else { |
244 | fec_corr_blks = p->rsfec_corr_cws; |
245 | fec_uncorr_blks = p->rsfec_uncorr_cws; |
246 | } |
247 | } |
248 | } |
249 | |
250 | *(data++) = fec_corr_blks; |
251 | *(data++) = fec_uncorr_blks; |
252 | } |
253 | |
254 | static int otx2_get_sset_count(struct net_device *netdev, int sset) |
255 | { |
256 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
257 | int qstats_count, mac_stats = 0; |
258 | |
259 | if (sset != ETH_SS_STATS) |
260 | return -EINVAL; |
261 | |
262 | qstats_count = otx2_n_queue_stats * |
263 | (pfvf->hw.rx_queues + otx2_get_total_tx_queues(pfvf)); |
264 | if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) |
265 | mac_stats = CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT; |
266 | otx2_update_lmac_fec_stats(pfvf); |
267 | |
268 | return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count + |
269 | mac_stats + OTX2_FEC_STATS_CNT + 1; |
270 | } |
271 | |
272 | /* Get no of queues device supports and current queue count */ |
273 | static void otx2_get_channels(struct net_device *dev, |
274 | struct ethtool_channels *channel) |
275 | { |
276 | struct otx2_nic *pfvf = netdev_priv(dev); |
277 | |
278 | channel->max_rx = pfvf->hw.max_queues; |
279 | channel->max_tx = pfvf->hw.max_queues; |
280 | |
281 | channel->rx_count = pfvf->hw.rx_queues; |
282 | channel->tx_count = pfvf->hw.tx_queues; |
283 | } |
284 | |
285 | /* Set no of Tx, Rx queues to be used */ |
286 | static int otx2_set_channels(struct net_device *dev, |
287 | struct ethtool_channels *channel) |
288 | { |
289 | struct otx2_nic *pfvf = netdev_priv(dev); |
290 | bool if_up = netif_running(dev); |
291 | int err, qos_txqs; |
292 | |
293 | if (!channel->rx_count || !channel->tx_count) |
294 | return -EINVAL; |
295 | |
296 | if (bitmap_weight(src: &pfvf->rq_bmap, nbits: pfvf->hw.rx_queues) > 1) { |
297 | netdev_err(dev, |
298 | format: "Receive queues are in use by TC police action\n" ); |
299 | return -EINVAL; |
300 | } |
301 | |
302 | if (if_up) |
303 | dev->netdev_ops->ndo_stop(dev); |
304 | |
305 | qos_txqs = bitmap_weight(src: pfvf->qos.qos_sq_bmap, |
306 | OTX2_QOS_MAX_LEAF_NODES); |
307 | |
308 | err = otx2_set_real_num_queues(netdev: dev, tx_queues: channel->tx_count + qos_txqs, |
309 | rx_queues: channel->rx_count); |
310 | if (err) |
311 | return err; |
312 | |
313 | pfvf->hw.rx_queues = channel->rx_count; |
314 | pfvf->hw.tx_queues = channel->tx_count; |
315 | if (pfvf->xdp_prog) |
316 | pfvf->hw.xdp_queues = channel->rx_count; |
317 | |
318 | if (if_up) |
319 | err = dev->netdev_ops->ndo_open(dev); |
320 | |
321 | netdev_info(dev, format: "Setting num Tx rings to %d, Rx rings to %d success\n" , |
322 | pfvf->hw.tx_queues, pfvf->hw.rx_queues); |
323 | |
324 | return err; |
325 | } |
326 | |
327 | static void otx2_get_pauseparam(struct net_device *netdev, |
328 | struct ethtool_pauseparam *pause) |
329 | { |
330 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
331 | struct cgx_pause_frm_cfg *req, *rsp; |
332 | |
333 | if (is_otx2_lbkvf(pdev: pfvf->pdev)) |
334 | return; |
335 | |
336 | mutex_lock(&pfvf->mbox.lock); |
337 | req = otx2_mbox_alloc_msg_cgx_cfg_pause_frm(mbox: &pfvf->mbox); |
338 | if (!req) { |
339 | mutex_unlock(lock: &pfvf->mbox.lock); |
340 | return; |
341 | } |
342 | |
343 | if (!otx2_sync_mbox_msg(mbox: &pfvf->mbox)) { |
344 | rsp = (struct cgx_pause_frm_cfg *) |
345 | otx2_mbox_get_rsp(mbox: &pfvf->mbox.mbox, devid: 0, msg: &req->hdr); |
346 | pause->rx_pause = rsp->rx_pause; |
347 | pause->tx_pause = rsp->tx_pause; |
348 | } |
349 | mutex_unlock(lock: &pfvf->mbox.lock); |
350 | } |
351 | |
352 | static int otx2_set_pauseparam(struct net_device *netdev, |
353 | struct ethtool_pauseparam *pause) |
354 | { |
355 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
356 | |
357 | if (pause->autoneg) |
358 | return -EOPNOTSUPP; |
359 | |
360 | if (is_otx2_lbkvf(pdev: pfvf->pdev)) |
361 | return -EOPNOTSUPP; |
362 | |
363 | if (pause->rx_pause) |
364 | pfvf->flags |= OTX2_FLAG_RX_PAUSE_ENABLED; |
365 | else |
366 | pfvf->flags &= ~OTX2_FLAG_RX_PAUSE_ENABLED; |
367 | |
368 | if (pause->tx_pause) |
369 | pfvf->flags |= OTX2_FLAG_TX_PAUSE_ENABLED; |
370 | else |
371 | pfvf->flags &= ~OTX2_FLAG_TX_PAUSE_ENABLED; |
372 | |
373 | return otx2_config_pause_frm(pfvf); |
374 | } |
375 | |
376 | static void otx2_get_ringparam(struct net_device *netdev, |
377 | struct ethtool_ringparam *ring, |
378 | struct kernel_ethtool_ringparam *kernel_ring, |
379 | struct netlink_ext_ack *extack) |
380 | { |
381 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
382 | struct otx2_qset *qs = &pfvf->qset; |
383 | |
384 | ring->rx_max_pending = Q_COUNT(Q_SIZE_MAX); |
385 | ring->rx_pending = qs->rqe_cnt ? qs->rqe_cnt : Q_COUNT(Q_SIZE_256); |
386 | ring->tx_max_pending = Q_COUNT(Q_SIZE_MAX); |
387 | ring->tx_pending = qs->sqe_cnt ? qs->sqe_cnt : Q_COUNT(Q_SIZE_4K); |
388 | kernel_ring->rx_buf_len = pfvf->hw.rbuf_len; |
389 | kernel_ring->cqe_size = pfvf->hw.xqe_size; |
390 | } |
391 | |
392 | static int otx2_set_ringparam(struct net_device *netdev, |
393 | struct ethtool_ringparam *ring, |
394 | struct kernel_ethtool_ringparam *kernel_ring, |
395 | struct netlink_ext_ack *extack) |
396 | { |
397 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
398 | u32 rx_buf_len = kernel_ring->rx_buf_len; |
399 | u32 old_rx_buf_len = pfvf->hw.rbuf_len; |
400 | u32 xqe_size = kernel_ring->cqe_size; |
401 | bool if_up = netif_running(dev: netdev); |
402 | struct otx2_qset *qs = &pfvf->qset; |
403 | u32 rx_count, tx_count; |
404 | |
405 | if (ring->rx_mini_pending || ring->rx_jumbo_pending) |
406 | return -EINVAL; |
407 | |
408 | /* Hardware supports max size of 32k for a receive buffer |
409 | * and 1536 is typical ethernet frame size. |
410 | */ |
411 | if (rx_buf_len && (rx_buf_len < 1536 || rx_buf_len > 32768)) { |
412 | netdev_err(dev: netdev, |
413 | format: "Receive buffer range is 1536 - 32768" ); |
414 | return -EINVAL; |
415 | } |
416 | |
417 | if (xqe_size != 128 && xqe_size != 512) { |
418 | netdev_err(dev: netdev, |
419 | format: "Completion event size must be 128 or 512" ); |
420 | return -EINVAL; |
421 | } |
422 | |
423 | /* Permitted lengths are 16 64 256 1K 4K 16K 64K 256K 1M */ |
424 | rx_count = ring->rx_pending; |
425 | /* On some silicon variants a skid or reserved CQEs are |
426 | * needed to avoid CQ overflow. |
427 | */ |
428 | if (rx_count < pfvf->hw.rq_skid) |
429 | rx_count = pfvf->hw.rq_skid; |
430 | rx_count = Q_COUNT(Q_SIZE(rx_count, 3)); |
431 | |
432 | /* Due pipelining impact minimum 2000 unused SQ CQE's |
433 | * need to be maintained to avoid CQ overflow, hence the |
434 | * minimum 4K size. |
435 | */ |
436 | tx_count = clamp_t(u32, ring->tx_pending, |
437 | Q_COUNT(Q_SIZE_4K), Q_COUNT(Q_SIZE_MAX)); |
438 | tx_count = Q_COUNT(Q_SIZE(tx_count, 3)); |
439 | |
440 | if (tx_count == qs->sqe_cnt && rx_count == qs->rqe_cnt && |
441 | rx_buf_len == old_rx_buf_len && xqe_size == pfvf->hw.xqe_size) |
442 | return 0; |
443 | |
444 | if (if_up) |
445 | netdev->netdev_ops->ndo_stop(netdev); |
446 | |
447 | /* Assigned to the nearest possible exponent. */ |
448 | qs->sqe_cnt = tx_count; |
449 | qs->rqe_cnt = rx_count; |
450 | |
451 | pfvf->hw.rbuf_len = rx_buf_len; |
452 | pfvf->hw.xqe_size = xqe_size; |
453 | |
454 | if (if_up) |
455 | return netdev->netdev_ops->ndo_open(netdev); |
456 | |
457 | return 0; |
458 | } |
459 | |
460 | static int otx2_get_coalesce(struct net_device *netdev, |
461 | struct ethtool_coalesce *cmd, |
462 | struct kernel_ethtool_coalesce *kernel_coal, |
463 | struct netlink_ext_ack *extack) |
464 | { |
465 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
466 | struct otx2_hw *hw = &pfvf->hw; |
467 | |
468 | cmd->rx_coalesce_usecs = hw->cq_time_wait; |
469 | cmd->rx_max_coalesced_frames = hw->cq_ecount_wait; |
470 | cmd->tx_coalesce_usecs = hw->cq_time_wait; |
471 | cmd->tx_max_coalesced_frames = hw->cq_ecount_wait; |
472 | if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) == |
473 | OTX2_FLAG_ADPTV_INT_COAL_ENABLED) { |
474 | cmd->use_adaptive_rx_coalesce = 1; |
475 | cmd->use_adaptive_tx_coalesce = 1; |
476 | } else { |
477 | cmd->use_adaptive_rx_coalesce = 0; |
478 | cmd->use_adaptive_tx_coalesce = 0; |
479 | } |
480 | |
481 | return 0; |
482 | } |
483 | |
484 | static int otx2_set_coalesce(struct net_device *netdev, |
485 | struct ethtool_coalesce *ec, |
486 | struct kernel_ethtool_coalesce *kernel_coal, |
487 | struct netlink_ext_ack *extack) |
488 | { |
489 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
490 | struct otx2_hw *hw = &pfvf->hw; |
491 | u8 priv_coalesce_status; |
492 | int qidx; |
493 | |
494 | if (!ec->rx_max_coalesced_frames || !ec->tx_max_coalesced_frames) |
495 | return 0; |
496 | |
497 | if (ec->use_adaptive_rx_coalesce != ec->use_adaptive_tx_coalesce) { |
498 | netdev_err(dev: netdev, |
499 | format: "adaptive-rx should be same as adaptive-tx" ); |
500 | return -EINVAL; |
501 | } |
502 | |
503 | /* Check and update coalesce status */ |
504 | if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) == |
505 | OTX2_FLAG_ADPTV_INT_COAL_ENABLED) { |
506 | priv_coalesce_status = 1; |
507 | if (!ec->use_adaptive_rx_coalesce) |
508 | pfvf->flags &= ~OTX2_FLAG_ADPTV_INT_COAL_ENABLED; |
509 | } else { |
510 | priv_coalesce_status = 0; |
511 | if (ec->use_adaptive_rx_coalesce) |
512 | pfvf->flags |= OTX2_FLAG_ADPTV_INT_COAL_ENABLED; |
513 | } |
514 | |
515 | /* 'cq_time_wait' is 8bit and is in multiple of 100ns, |
516 | * so clamp the user given value to the range of 1 to 25usec. |
517 | */ |
518 | ec->rx_coalesce_usecs = clamp_t(u32, ec->rx_coalesce_usecs, |
519 | 1, CQ_TIMER_THRESH_MAX); |
520 | ec->tx_coalesce_usecs = clamp_t(u32, ec->tx_coalesce_usecs, |
521 | 1, CQ_TIMER_THRESH_MAX); |
522 | |
523 | /* Rx and Tx are mapped to same CQ, check which one |
524 | * is changed, if both then choose the min. |
525 | */ |
526 | if (hw->cq_time_wait == ec->rx_coalesce_usecs) |
527 | hw->cq_time_wait = ec->tx_coalesce_usecs; |
528 | else if (hw->cq_time_wait == ec->tx_coalesce_usecs) |
529 | hw->cq_time_wait = ec->rx_coalesce_usecs; |
530 | else |
531 | hw->cq_time_wait = min_t(u8, ec->rx_coalesce_usecs, |
532 | ec->tx_coalesce_usecs); |
533 | |
534 | /* Max ecount_wait supported is 16bit, |
535 | * so clamp the user given value to the range of 1 to 64k. |
536 | */ |
537 | ec->rx_max_coalesced_frames = clamp_t(u32, ec->rx_max_coalesced_frames, |
538 | 1, NAPI_POLL_WEIGHT); |
539 | ec->tx_max_coalesced_frames = clamp_t(u32, ec->tx_max_coalesced_frames, |
540 | 1, NAPI_POLL_WEIGHT); |
541 | |
542 | /* Rx and Tx are mapped to same CQ, check which one |
543 | * is changed, if both then choose the min. |
544 | */ |
545 | if (hw->cq_ecount_wait == ec->rx_max_coalesced_frames) |
546 | hw->cq_ecount_wait = ec->tx_max_coalesced_frames; |
547 | else if (hw->cq_ecount_wait == ec->tx_max_coalesced_frames) |
548 | hw->cq_ecount_wait = ec->rx_max_coalesced_frames; |
549 | else |
550 | hw->cq_ecount_wait = min_t(u16, ec->rx_max_coalesced_frames, |
551 | ec->tx_max_coalesced_frames); |
552 | |
553 | /* Reset 'cq_time_wait' and 'cq_ecount_wait' to |
554 | * default values if coalesce status changed from |
555 | * 'on' to 'off'. |
556 | */ |
557 | if (priv_coalesce_status && |
558 | ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) != |
559 | OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) { |
560 | hw->cq_time_wait = CQ_TIMER_THRESH_DEFAULT; |
561 | hw->cq_ecount_wait = CQ_CQE_THRESH_DEFAULT; |
562 | } |
563 | |
564 | if (netif_running(dev: netdev)) { |
565 | for (qidx = 0; qidx < pfvf->hw.cint_cnt; qidx++) |
566 | otx2_config_irq_coalescing(pfvf, qidx); |
567 | } |
568 | |
569 | return 0; |
570 | } |
571 | |
572 | static int (struct otx2_nic *pfvf, |
573 | struct ethtool_rxnfc *nfc) |
574 | { |
575 | struct otx2_rss_info * = &pfvf->hw.rss_info; |
576 | |
577 | if (!(rss->flowkey_cfg & |
578 | (NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6))) |
579 | return 0; |
580 | |
581 | /* Mimimum is IPv4 and IPv6, SIP/DIP */ |
582 | nfc->data = RXH_IP_SRC | RXH_IP_DST; |
583 | if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_VLAN) |
584 | nfc->data |= RXH_VLAN; |
585 | |
586 | switch (nfc->flow_type) { |
587 | case TCP_V4_FLOW: |
588 | case TCP_V6_FLOW: |
589 | if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_TCP) |
590 | nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
591 | break; |
592 | case UDP_V4_FLOW: |
593 | case UDP_V6_FLOW: |
594 | if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_UDP) |
595 | nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
596 | break; |
597 | case SCTP_V4_FLOW: |
598 | case SCTP_V6_FLOW: |
599 | if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_SCTP) |
600 | nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
601 | break; |
602 | case AH_ESP_V4_FLOW: |
603 | case AH_ESP_V6_FLOW: |
604 | if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_ESP) |
605 | nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
606 | break; |
607 | case AH_V4_FLOW: |
608 | case ESP_V4_FLOW: |
609 | case IPV4_FLOW: |
610 | break; |
611 | case AH_V6_FLOW: |
612 | case ESP_V6_FLOW: |
613 | case IPV6_FLOW: |
614 | break; |
615 | default: |
616 | return -EINVAL; |
617 | } |
618 | |
619 | return 0; |
620 | } |
621 | |
622 | static int (struct otx2_nic *pfvf, |
623 | struct ethtool_rxnfc *nfc) |
624 | { |
625 | struct otx2_rss_info * = &pfvf->hw.rss_info; |
626 | u32 rxh_l4 = RXH_L4_B_0_1 | RXH_L4_B_2_3; |
627 | u32 = rss->flowkey_cfg; |
628 | |
629 | if (!rss->enable) { |
630 | netdev_err(dev: pfvf->netdev, |
631 | format: "RSS is disabled, cannot change settings\n" ); |
632 | return -EIO; |
633 | } |
634 | |
635 | /* Mimimum is IPv4 and IPv6, SIP/DIP */ |
636 | if (!(nfc->data & RXH_IP_SRC) || !(nfc->data & RXH_IP_DST)) |
637 | return -EINVAL; |
638 | |
639 | if (nfc->data & RXH_VLAN) |
640 | rss_cfg |= NIX_FLOW_KEY_TYPE_VLAN; |
641 | else |
642 | rss_cfg &= ~NIX_FLOW_KEY_TYPE_VLAN; |
643 | |
644 | switch (nfc->flow_type) { |
645 | case TCP_V4_FLOW: |
646 | case TCP_V6_FLOW: |
647 | /* Different config for v4 and v6 is not supported. |
648 | * Both of them have to be either 4-tuple or 2-tuple. |
649 | */ |
650 | switch (nfc->data & rxh_l4) { |
651 | case 0: |
652 | rss_cfg &= ~NIX_FLOW_KEY_TYPE_TCP; |
653 | break; |
654 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
655 | rss_cfg |= NIX_FLOW_KEY_TYPE_TCP; |
656 | break; |
657 | default: |
658 | return -EINVAL; |
659 | } |
660 | break; |
661 | case UDP_V4_FLOW: |
662 | case UDP_V6_FLOW: |
663 | switch (nfc->data & rxh_l4) { |
664 | case 0: |
665 | rss_cfg &= ~NIX_FLOW_KEY_TYPE_UDP; |
666 | break; |
667 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
668 | rss_cfg |= NIX_FLOW_KEY_TYPE_UDP; |
669 | break; |
670 | default: |
671 | return -EINVAL; |
672 | } |
673 | break; |
674 | case SCTP_V4_FLOW: |
675 | case SCTP_V6_FLOW: |
676 | switch (nfc->data & rxh_l4) { |
677 | case 0: |
678 | rss_cfg &= ~NIX_FLOW_KEY_TYPE_SCTP; |
679 | break; |
680 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
681 | rss_cfg |= NIX_FLOW_KEY_TYPE_SCTP; |
682 | break; |
683 | default: |
684 | return -EINVAL; |
685 | } |
686 | break; |
687 | case AH_ESP_V4_FLOW: |
688 | case AH_ESP_V6_FLOW: |
689 | switch (nfc->data & rxh_l4) { |
690 | case 0: |
691 | rss_cfg &= ~(NIX_FLOW_KEY_TYPE_ESP | |
692 | NIX_FLOW_KEY_TYPE_AH); |
693 | rss_cfg |= NIX_FLOW_KEY_TYPE_VLAN | |
694 | NIX_FLOW_KEY_TYPE_IPV4_PROTO; |
695 | break; |
696 | case (RXH_L4_B_0_1 | RXH_L4_B_2_3): |
697 | /* If VLAN hashing is also requested for ESP then do not |
698 | * allow because of hardware 40 bytes flow key limit. |
699 | */ |
700 | if (rss_cfg & NIX_FLOW_KEY_TYPE_VLAN) { |
701 | netdev_err(dev: pfvf->netdev, |
702 | format: "RSS hash of ESP or AH with VLAN is not supported\n" ); |
703 | return -EOPNOTSUPP; |
704 | } |
705 | |
706 | rss_cfg |= NIX_FLOW_KEY_TYPE_ESP | NIX_FLOW_KEY_TYPE_AH; |
707 | /* Disable IPv4 proto hashing since IPv6 SA+DA(32 bytes) |
708 | * and ESP SPI+sequence(8 bytes) uses hardware maximum |
709 | * limit of 40 byte flow key. |
710 | */ |
711 | rss_cfg &= ~NIX_FLOW_KEY_TYPE_IPV4_PROTO; |
712 | break; |
713 | default: |
714 | return -EINVAL; |
715 | } |
716 | break; |
717 | case IPV4_FLOW: |
718 | case IPV6_FLOW: |
719 | rss_cfg = NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6; |
720 | break; |
721 | default: |
722 | return -EINVAL; |
723 | } |
724 | |
725 | rss->flowkey_cfg = rss_cfg; |
726 | otx2_set_flowkey_cfg(pfvf); |
727 | return 0; |
728 | } |
729 | |
730 | static int otx2_get_rxnfc(struct net_device *dev, |
731 | struct ethtool_rxnfc *nfc, u32 *rules) |
732 | { |
733 | bool ntuple = !!(dev->features & NETIF_F_NTUPLE); |
734 | struct otx2_nic *pfvf = netdev_priv(dev); |
735 | int ret = -EOPNOTSUPP; |
736 | |
737 | switch (nfc->cmd) { |
738 | case ETHTOOL_GRXRINGS: |
739 | nfc->data = pfvf->hw.rx_queues; |
740 | ret = 0; |
741 | break; |
742 | case ETHTOOL_GRXCLSRLCNT: |
743 | if (netif_running(dev) && ntuple) { |
744 | nfc->rule_cnt = pfvf->flow_cfg->nr_flows; |
745 | ret = 0; |
746 | } |
747 | break; |
748 | case ETHTOOL_GRXCLSRULE: |
749 | if (netif_running(dev) && ntuple) |
750 | ret = otx2_get_flow(pfvf, nfc, location: nfc->fs.location); |
751 | break; |
752 | case ETHTOOL_GRXCLSRLALL: |
753 | if (netif_running(dev) && ntuple) |
754 | ret = otx2_get_all_flows(pfvf, nfc, rule_locs: rules); |
755 | break; |
756 | case ETHTOOL_GRXFH: |
757 | return otx2_get_rss_hash_opts(pfvf, nfc); |
758 | default: |
759 | break; |
760 | } |
761 | return ret; |
762 | } |
763 | |
764 | static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc) |
765 | { |
766 | bool ntuple = !!(dev->features & NETIF_F_NTUPLE); |
767 | struct otx2_nic *pfvf = netdev_priv(dev); |
768 | int ret = -EOPNOTSUPP; |
769 | |
770 | pfvf->flow_cfg->ntuple = ntuple; |
771 | switch (nfc->cmd) { |
772 | case ETHTOOL_SRXFH: |
773 | ret = otx2_set_rss_hash_opts(pfvf, nfc); |
774 | break; |
775 | case ETHTOOL_SRXCLSRLINS: |
776 | if (netif_running(dev) && ntuple) |
777 | ret = otx2_add_flow(pfvf, nfc); |
778 | break; |
779 | case ETHTOOL_SRXCLSRLDEL: |
780 | if (netif_running(dev) && ntuple) |
781 | ret = otx2_remove_flow(pfvf, location: nfc->fs.location); |
782 | break; |
783 | default: |
784 | break; |
785 | } |
786 | |
787 | return ret; |
788 | } |
789 | |
790 | static u32 otx2_get_rxfh_key_size(struct net_device *netdev) |
791 | { |
792 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
793 | struct otx2_rss_info *; |
794 | |
795 | rss = &pfvf->hw.rss_info; |
796 | |
797 | return sizeof(rss->key); |
798 | } |
799 | |
800 | static u32 otx2_get_rxfh_indir_size(struct net_device *dev) |
801 | { |
802 | return MAX_RSS_INDIR_TBL_SIZE; |
803 | } |
804 | |
805 | static int (struct otx2_nic *pfvf, int ctx_id) |
806 | { |
807 | struct otx2_rss_info * = &pfvf->hw.rss_info; |
808 | |
809 | otx2_rss_ctx_flow_del(pfvf, ctx_id); |
810 | kfree(objp: rss->rss_ctx[ctx_id]); |
811 | rss->rss_ctx[ctx_id] = NULL; |
812 | |
813 | return 0; |
814 | } |
815 | |
816 | static int (struct otx2_nic *pfvf, |
817 | u32 *) |
818 | { |
819 | struct otx2_rss_info * = &pfvf->hw.rss_info; |
820 | u8 ctx; |
821 | |
822 | for (ctx = 0; ctx < MAX_RSS_GROUPS; ctx++) { |
823 | if (!rss->rss_ctx[ctx]) |
824 | break; |
825 | } |
826 | if (ctx == MAX_RSS_GROUPS) |
827 | return -EINVAL; |
828 | |
829 | rss->rss_ctx[ctx] = kzalloc(size: sizeof(*rss->rss_ctx[ctx]), GFP_KERNEL); |
830 | if (!rss->rss_ctx[ctx]) |
831 | return -ENOMEM; |
832 | *rss_context = ctx; |
833 | |
834 | return 0; |
835 | } |
836 | |
837 | /* Configure RSS table and hash key */ |
838 | static int otx2_set_rxfh(struct net_device *dev, |
839 | struct ethtool_rxfh_param *rxfh, |
840 | struct netlink_ext_ack *extack) |
841 | { |
842 | u32 = DEFAULT_RSS_CONTEXT_GROUP; |
843 | struct otx2_nic *pfvf = netdev_priv(dev); |
844 | struct otx2_rss_ctx *; |
845 | struct otx2_rss_info *; |
846 | int ret, idx; |
847 | |
848 | if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && |
849 | rxfh->hfunc != ETH_RSS_HASH_TOP) |
850 | return -EOPNOTSUPP; |
851 | |
852 | if (rxfh->rss_context) |
853 | rss_context = rxfh->rss_context; |
854 | |
855 | if (rss_context != ETH_RXFH_CONTEXT_ALLOC && |
856 | rss_context >= MAX_RSS_GROUPS) |
857 | return -EINVAL; |
858 | |
859 | rss = &pfvf->hw.rss_info; |
860 | |
861 | if (!rss->enable) { |
862 | netdev_err(dev, format: "RSS is disabled, cannot change settings\n" ); |
863 | return -EIO; |
864 | } |
865 | |
866 | if (rxfh->key) { |
867 | memcpy(rss->key, rxfh->key, sizeof(rss->key)); |
868 | otx2_set_rss_key(pfvf); |
869 | } |
870 | if (rxfh->rss_delete) |
871 | return otx2_rss_ctx_delete(pfvf, ctx_id: rss_context); |
872 | |
873 | if (rss_context == ETH_RXFH_CONTEXT_ALLOC) { |
874 | ret = otx2_rss_ctx_create(pfvf, rss_context: &rss_context); |
875 | rxfh->rss_context = rss_context; |
876 | if (ret) |
877 | return ret; |
878 | } |
879 | if (rxfh->indir) { |
880 | rss_ctx = rss->rss_ctx[rss_context]; |
881 | for (idx = 0; idx < rss->rss_size; idx++) |
882 | rss_ctx->ind_tbl[idx] = rxfh->indir[idx]; |
883 | } |
884 | otx2_set_rss_table(pfvf, ctx_id: rss_context); |
885 | |
886 | return 0; |
887 | } |
888 | |
889 | /* Get RSS configuration */ |
890 | static int otx2_get_rxfh(struct net_device *dev, |
891 | struct ethtool_rxfh_param *rxfh) |
892 | { |
893 | u32 = DEFAULT_RSS_CONTEXT_GROUP; |
894 | struct otx2_nic *pfvf = netdev_priv(dev); |
895 | struct otx2_rss_ctx *; |
896 | struct otx2_rss_info *; |
897 | u32 *indir = rxfh->indir; |
898 | int idx, rx_queues; |
899 | |
900 | rss = &pfvf->hw.rss_info; |
901 | |
902 | rxfh->hfunc = ETH_RSS_HASH_TOP; |
903 | if (rxfh->rss_context) |
904 | rss_context = rxfh->rss_context; |
905 | |
906 | if (!indir) |
907 | return 0; |
908 | |
909 | if (!rss->enable && rss_context == DEFAULT_RSS_CONTEXT_GROUP) { |
910 | rx_queues = pfvf->hw.rx_queues; |
911 | for (idx = 0; idx < MAX_RSS_INDIR_TBL_SIZE; idx++) |
912 | indir[idx] = ethtool_rxfh_indir_default(index: idx, n_rx_rings: rx_queues); |
913 | return 0; |
914 | } |
915 | if (rss_context >= MAX_RSS_GROUPS) |
916 | return -ENOENT; |
917 | |
918 | rss_ctx = rss->rss_ctx[rss_context]; |
919 | if (!rss_ctx) |
920 | return -ENOENT; |
921 | |
922 | if (indir) { |
923 | for (idx = 0; idx < rss->rss_size; idx++) |
924 | indir[idx] = rss_ctx->ind_tbl[idx]; |
925 | } |
926 | if (rxfh->key) |
927 | memcpy(rxfh->key, rss->key, sizeof(rss->key)); |
928 | |
929 | return 0; |
930 | } |
931 | |
932 | static u32 otx2_get_msglevel(struct net_device *netdev) |
933 | { |
934 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
935 | |
936 | return pfvf->msg_enable; |
937 | } |
938 | |
939 | static void otx2_set_msglevel(struct net_device *netdev, u32 val) |
940 | { |
941 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
942 | |
943 | pfvf->msg_enable = val; |
944 | } |
945 | |
946 | static u32 otx2_get_link(struct net_device *netdev) |
947 | { |
948 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
949 | |
950 | /* LBK link is internal and always UP */ |
951 | if (is_otx2_lbkvf(pdev: pfvf->pdev)) |
952 | return 1; |
953 | return pfvf->linfo.link_up; |
954 | } |
955 | |
956 | static int otx2_get_ts_info(struct net_device *netdev, |
957 | struct ethtool_ts_info *info) |
958 | { |
959 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
960 | |
961 | if (!pfvf->ptp) |
962 | return ethtool_op_get_ts_info(dev: netdev, eti: info); |
963 | |
964 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | |
965 | SOF_TIMESTAMPING_RX_SOFTWARE | |
966 | SOF_TIMESTAMPING_SOFTWARE | |
967 | SOF_TIMESTAMPING_TX_HARDWARE | |
968 | SOF_TIMESTAMPING_RX_HARDWARE | |
969 | SOF_TIMESTAMPING_RAW_HARDWARE; |
970 | |
971 | info->phc_index = otx2_ptp_clock_index(pfvf); |
972 | |
973 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); |
974 | if (test_bit(CN10K_PTP_ONESTEP, &pfvf->hw.cap_flag)) |
975 | info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_SYNC); |
976 | |
977 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | |
978 | BIT(HWTSTAMP_FILTER_ALL); |
979 | |
980 | return 0; |
981 | } |
982 | |
983 | static struct cgx_fw_data *otx2_get_fwdata(struct otx2_nic *pfvf) |
984 | { |
985 | struct cgx_fw_data *rsp = NULL; |
986 | struct msg_req *req; |
987 | int err = 0; |
988 | |
989 | mutex_lock(&pfvf->mbox.lock); |
990 | req = otx2_mbox_alloc_msg_cgx_get_aux_link_info(mbox: &pfvf->mbox); |
991 | if (!req) { |
992 | mutex_unlock(lock: &pfvf->mbox.lock); |
993 | return ERR_PTR(error: -ENOMEM); |
994 | } |
995 | |
996 | err = otx2_sync_mbox_msg(mbox: &pfvf->mbox); |
997 | if (!err) { |
998 | rsp = (struct cgx_fw_data *) |
999 | otx2_mbox_get_rsp(mbox: &pfvf->mbox.mbox, devid: 0, msg: &req->hdr); |
1000 | } else { |
1001 | rsp = ERR_PTR(error: err); |
1002 | } |
1003 | |
1004 | mutex_unlock(lock: &pfvf->mbox.lock); |
1005 | return rsp; |
1006 | } |
1007 | |
1008 | static int otx2_get_fecparam(struct net_device *netdev, |
1009 | struct ethtool_fecparam *fecparam) |
1010 | { |
1011 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
1012 | struct cgx_fw_data *rsp; |
1013 | const int fec[] = { |
1014 | ETHTOOL_FEC_OFF, |
1015 | ETHTOOL_FEC_BASER, |
1016 | ETHTOOL_FEC_RS, |
1017 | ETHTOOL_FEC_BASER | ETHTOOL_FEC_RS}; |
1018 | #define FEC_MAX_INDEX 4 |
1019 | if (pfvf->linfo.fec < FEC_MAX_INDEX) |
1020 | fecparam->active_fec = fec[pfvf->linfo.fec]; |
1021 | |
1022 | rsp = otx2_get_fwdata(pfvf); |
1023 | if (IS_ERR(ptr: rsp)) |
1024 | return PTR_ERR(ptr: rsp); |
1025 | |
1026 | if (rsp->fwdata.supported_fec < FEC_MAX_INDEX) { |
1027 | if (!rsp->fwdata.supported_fec) |
1028 | fecparam->fec = ETHTOOL_FEC_NONE; |
1029 | else |
1030 | fecparam->fec = fec[rsp->fwdata.supported_fec]; |
1031 | } |
1032 | return 0; |
1033 | } |
1034 | |
1035 | static int otx2_set_fecparam(struct net_device *netdev, |
1036 | struct ethtool_fecparam *fecparam) |
1037 | { |
1038 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
1039 | struct mbox *mbox = &pfvf->mbox; |
1040 | struct fec_mode *req, *rsp; |
1041 | int err = 0, fec = 0; |
1042 | |
1043 | switch (fecparam->fec) { |
1044 | /* Firmware does not support AUTO mode consider it as FEC_OFF */ |
1045 | case ETHTOOL_FEC_OFF: |
1046 | case ETHTOOL_FEC_AUTO: |
1047 | fec = OTX2_FEC_OFF; |
1048 | break; |
1049 | case ETHTOOL_FEC_RS: |
1050 | fec = OTX2_FEC_RS; |
1051 | break; |
1052 | case ETHTOOL_FEC_BASER: |
1053 | fec = OTX2_FEC_BASER; |
1054 | break; |
1055 | default: |
1056 | netdev_warn(dev: pfvf->netdev, format: "Unsupported FEC mode: %d" , |
1057 | fecparam->fec); |
1058 | return -EINVAL; |
1059 | } |
1060 | |
1061 | if (fec == pfvf->linfo.fec) |
1062 | return 0; |
1063 | |
1064 | mutex_lock(&mbox->lock); |
1065 | req = otx2_mbox_alloc_msg_cgx_set_fec_param(mbox: &pfvf->mbox); |
1066 | if (!req) { |
1067 | err = -ENOMEM; |
1068 | goto end; |
1069 | } |
1070 | req->fec = fec; |
1071 | err = otx2_sync_mbox_msg(mbox: &pfvf->mbox); |
1072 | if (err) |
1073 | goto end; |
1074 | |
1075 | rsp = (struct fec_mode *)otx2_mbox_get_rsp(mbox: &pfvf->mbox.mbox, |
1076 | devid: 0, msg: &req->hdr); |
1077 | if (rsp->fec >= 0) |
1078 | pfvf->linfo.fec = rsp->fec; |
1079 | else |
1080 | err = rsp->fec; |
1081 | end: |
1082 | mutex_unlock(lock: &mbox->lock); |
1083 | return err; |
1084 | } |
1085 | |
1086 | static void otx2_get_fec_info(u64 index, int req_mode, |
1087 | struct ethtool_link_ksettings *link_ksettings) |
1088 | { |
1089 | __ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_fec_modes) = { 0, }; |
1090 | |
1091 | switch (index) { |
1092 | case OTX2_FEC_NONE: |
1093 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_NONE_BIT, |
1094 | addr: otx2_fec_modes); |
1095 | break; |
1096 | case OTX2_FEC_BASER: |
1097 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_BASER_BIT, |
1098 | addr: otx2_fec_modes); |
1099 | break; |
1100 | case OTX2_FEC_RS: |
1101 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_RS_BIT, |
1102 | addr: otx2_fec_modes); |
1103 | break; |
1104 | case OTX2_FEC_BASER | OTX2_FEC_RS: |
1105 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_BASER_BIT, |
1106 | addr: otx2_fec_modes); |
1107 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FEC_RS_BIT, |
1108 | addr: otx2_fec_modes); |
1109 | break; |
1110 | } |
1111 | |
1112 | /* Add fec modes to existing modes */ |
1113 | if (req_mode == OTX2_MODE_ADVERTISED) |
1114 | linkmode_or(dst: link_ksettings->link_modes.advertising, |
1115 | a: link_ksettings->link_modes.advertising, |
1116 | b: otx2_fec_modes); |
1117 | else |
1118 | linkmode_or(dst: link_ksettings->link_modes.supported, |
1119 | a: link_ksettings->link_modes.supported, |
1120 | b: otx2_fec_modes); |
1121 | } |
1122 | |
1123 | static void otx2_get_link_mode_info(u64 link_mode_bmap, |
1124 | bool req_mode, |
1125 | struct ethtool_link_ksettings |
1126 | *link_ksettings) |
1127 | { |
1128 | __ETHTOOL_DECLARE_LINK_MODE_MASK(otx2_link_modes) = { 0, }; |
1129 | const int otx2_sgmii_features[6] = { |
1130 | ETHTOOL_LINK_MODE_10baseT_Half_BIT, |
1131 | ETHTOOL_LINK_MODE_10baseT_Full_BIT, |
1132 | ETHTOOL_LINK_MODE_100baseT_Half_BIT, |
1133 | ETHTOOL_LINK_MODE_100baseT_Full_BIT, |
1134 | ETHTOOL_LINK_MODE_1000baseT_Half_BIT, |
1135 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
1136 | }; |
1137 | /* CGX link modes to Ethtool link mode mapping */ |
1138 | const int cgx_link_mode[27] = { |
1139 | 0, /* SGMII Mode */ |
1140 | ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
1141 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
1142 | ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, |
1143 | ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, |
1144 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, |
1145 | 0, |
1146 | ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, |
1147 | 0, |
1148 | 0, |
1149 | ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, |
1150 | ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, |
1151 | ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, |
1152 | ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, |
1153 | ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, |
1154 | ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, |
1155 | 0, |
1156 | ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, |
1157 | 0, |
1158 | ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, |
1159 | ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, |
1160 | ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, |
1161 | 0, |
1162 | ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, |
1163 | ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, |
1164 | ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, |
1165 | ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT |
1166 | }; |
1167 | u8 bit; |
1168 | |
1169 | for_each_set_bit(bit, (unsigned long *)&link_mode_bmap, 27) { |
1170 | /* SGMII mode is set */ |
1171 | if (bit == 0) |
1172 | linkmode_set_bit_array(array: otx2_sgmii_features, |
1173 | ARRAY_SIZE(otx2_sgmii_features), |
1174 | addr: otx2_link_modes); |
1175 | else |
1176 | linkmode_set_bit(nr: cgx_link_mode[bit], addr: otx2_link_modes); |
1177 | } |
1178 | |
1179 | if (req_mode == OTX2_MODE_ADVERTISED) |
1180 | linkmode_copy(dst: link_ksettings->link_modes.advertising, |
1181 | src: otx2_link_modes); |
1182 | else |
1183 | linkmode_copy(dst: link_ksettings->link_modes.supported, |
1184 | src: otx2_link_modes); |
1185 | } |
1186 | |
1187 | static int otx2_get_link_ksettings(struct net_device *netdev, |
1188 | struct ethtool_link_ksettings *cmd) |
1189 | { |
1190 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
1191 | struct cgx_fw_data *rsp = NULL; |
1192 | |
1193 | cmd->base.duplex = pfvf->linfo.full_duplex; |
1194 | cmd->base.speed = pfvf->linfo.speed; |
1195 | cmd->base.autoneg = pfvf->linfo.an; |
1196 | |
1197 | rsp = otx2_get_fwdata(pfvf); |
1198 | if (IS_ERR(ptr: rsp)) |
1199 | return PTR_ERR(ptr: rsp); |
1200 | |
1201 | if (rsp->fwdata.supported_an) |
1202 | ethtool_link_ksettings_add_link_mode(cmd, |
1203 | supported, |
1204 | Autoneg); |
1205 | |
1206 | otx2_get_link_mode_info(link_mode_bmap: rsp->fwdata.advertised_link_modes, |
1207 | req_mode: OTX2_MODE_ADVERTISED, link_ksettings: cmd); |
1208 | otx2_get_fec_info(index: rsp->fwdata.advertised_fec, |
1209 | req_mode: OTX2_MODE_ADVERTISED, link_ksettings: cmd); |
1210 | otx2_get_link_mode_info(link_mode_bmap: rsp->fwdata.supported_link_modes, |
1211 | req_mode: OTX2_MODE_SUPPORTED, link_ksettings: cmd); |
1212 | otx2_get_fec_info(index: rsp->fwdata.supported_fec, |
1213 | req_mode: OTX2_MODE_SUPPORTED, link_ksettings: cmd); |
1214 | return 0; |
1215 | } |
1216 | |
1217 | static void otx2_get_advertised_mode(const struct ethtool_link_ksettings *cmd, |
1218 | u64 *mode) |
1219 | { |
1220 | u32 bit_pos; |
1221 | |
1222 | /* Firmware does not support requesting multiple advertised modes |
1223 | * return first set bit |
1224 | */ |
1225 | bit_pos = find_first_bit(addr: cmd->link_modes.advertising, |
1226 | size: __ETHTOOL_LINK_MODE_MASK_NBITS); |
1227 | if (bit_pos != __ETHTOOL_LINK_MODE_MASK_NBITS) |
1228 | *mode = bit_pos; |
1229 | } |
1230 | |
1231 | static int otx2_set_link_ksettings(struct net_device *netdev, |
1232 | const struct ethtool_link_ksettings *cmd) |
1233 | { |
1234 | struct otx2_nic *pf = netdev_priv(dev: netdev); |
1235 | struct ethtool_link_ksettings cur_ks; |
1236 | struct cgx_set_link_mode_req *req; |
1237 | struct mbox *mbox = &pf->mbox; |
1238 | int err = 0; |
1239 | |
1240 | memset(&cur_ks, 0, sizeof(struct ethtool_link_ksettings)); |
1241 | |
1242 | if (!ethtool_validate_speed(speed: cmd->base.speed) || |
1243 | !ethtool_validate_duplex(duplex: cmd->base.duplex)) |
1244 | return -EINVAL; |
1245 | |
1246 | if (cmd->base.autoneg != AUTONEG_ENABLE && |
1247 | cmd->base.autoneg != AUTONEG_DISABLE) |
1248 | return -EINVAL; |
1249 | |
1250 | otx2_get_link_ksettings(netdev, cmd: &cur_ks); |
1251 | |
1252 | /* Check requested modes against supported modes by hardware */ |
1253 | if (!linkmode_subset(src1: cmd->link_modes.advertising, |
1254 | src2: cur_ks.link_modes.supported)) |
1255 | return -EINVAL; |
1256 | |
1257 | mutex_lock(&mbox->lock); |
1258 | req = otx2_mbox_alloc_msg_cgx_set_link_mode(mbox: &pf->mbox); |
1259 | if (!req) { |
1260 | err = -ENOMEM; |
1261 | goto end; |
1262 | } |
1263 | |
1264 | req->args.speed = cmd->base.speed; |
1265 | /* firmware expects 1 for half duplex and 0 for full duplex |
1266 | * hence inverting |
1267 | */ |
1268 | req->args.duplex = cmd->base.duplex ^ 0x1; |
1269 | req->args.an = cmd->base.autoneg; |
1270 | otx2_get_advertised_mode(cmd, mode: &req->args.mode); |
1271 | |
1272 | err = otx2_sync_mbox_msg(mbox: &pf->mbox); |
1273 | end: |
1274 | mutex_unlock(lock: &mbox->lock); |
1275 | return err; |
1276 | } |
1277 | |
1278 | static void otx2_get_fec_stats(struct net_device *netdev, |
1279 | struct ethtool_fec_stats *fec_stats) |
1280 | { |
1281 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
1282 | struct cgx_fw_data *rsp; |
1283 | |
1284 | otx2_update_lmac_fec_stats(pfvf); |
1285 | |
1286 | /* Report MAC FEC stats */ |
1287 | fec_stats->corrected_blocks.total = pfvf->hw.cgx_fec_corr_blks; |
1288 | fec_stats->uncorrectable_blocks.total = pfvf->hw.cgx_fec_uncorr_blks; |
1289 | |
1290 | rsp = otx2_get_fwdata(pfvf); |
1291 | if (!IS_ERR(ptr: rsp) && rsp->fwdata.phy.misc.has_fec_stats && |
1292 | !otx2_get_phy_fec_stats(pfvf)) { |
1293 | /* Fetch fwdata again because it's been recently populated with |
1294 | * latest PHY FEC stats. |
1295 | */ |
1296 | rsp = otx2_get_fwdata(pfvf); |
1297 | if (!IS_ERR(ptr: rsp)) { |
1298 | struct fec_stats_s *p = &rsp->fwdata.phy.fec_stats; |
1299 | |
1300 | if (pfvf->linfo.fec == OTX2_FEC_BASER) { |
1301 | fec_stats->corrected_blocks.total = p->brfec_corr_blks; |
1302 | fec_stats->uncorrectable_blocks.total = p->brfec_uncorr_blks; |
1303 | } else { |
1304 | fec_stats->corrected_blocks.total = p->rsfec_corr_cws; |
1305 | fec_stats->uncorrectable_blocks.total = p->rsfec_uncorr_cws; |
1306 | } |
1307 | } |
1308 | } |
1309 | } |
1310 | |
1311 | static const struct ethtool_ops otx2_ethtool_ops = { |
1312 | .cap_rss_ctx_supported = true, |
1313 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
1314 | ETHTOOL_COALESCE_MAX_FRAMES | |
1315 | ETHTOOL_COALESCE_USE_ADAPTIVE, |
1316 | .supported_ring_params = ETHTOOL_RING_USE_RX_BUF_LEN | |
1317 | ETHTOOL_RING_USE_CQE_SIZE, |
1318 | .get_link = otx2_get_link, |
1319 | .get_drvinfo = otx2_get_drvinfo, |
1320 | .get_strings = otx2_get_strings, |
1321 | .get_ethtool_stats = otx2_get_ethtool_stats, |
1322 | .get_sset_count = otx2_get_sset_count, |
1323 | .set_channels = otx2_set_channels, |
1324 | .get_channels = otx2_get_channels, |
1325 | .get_ringparam = otx2_get_ringparam, |
1326 | .set_ringparam = otx2_set_ringparam, |
1327 | .get_coalesce = otx2_get_coalesce, |
1328 | .set_coalesce = otx2_set_coalesce, |
1329 | .get_rxnfc = otx2_get_rxnfc, |
1330 | .set_rxnfc = otx2_set_rxnfc, |
1331 | .get_rxfh_key_size = otx2_get_rxfh_key_size, |
1332 | .get_rxfh_indir_size = otx2_get_rxfh_indir_size, |
1333 | .get_rxfh = otx2_get_rxfh, |
1334 | .set_rxfh = otx2_set_rxfh, |
1335 | .get_msglevel = otx2_get_msglevel, |
1336 | .set_msglevel = otx2_set_msglevel, |
1337 | .get_pauseparam = otx2_get_pauseparam, |
1338 | .set_pauseparam = otx2_set_pauseparam, |
1339 | .get_ts_info = otx2_get_ts_info, |
1340 | .get_fec_stats = otx2_get_fec_stats, |
1341 | .get_fecparam = otx2_get_fecparam, |
1342 | .set_fecparam = otx2_set_fecparam, |
1343 | .get_link_ksettings = otx2_get_link_ksettings, |
1344 | .set_link_ksettings = otx2_set_link_ksettings, |
1345 | }; |
1346 | |
1347 | void otx2_set_ethtool_ops(struct net_device *netdev) |
1348 | { |
1349 | netdev->ethtool_ops = &otx2_ethtool_ops; |
1350 | } |
1351 | |
1352 | /* VF's ethtool APIs */ |
1353 | static void otx2vf_get_drvinfo(struct net_device *netdev, |
1354 | struct ethtool_drvinfo *info) |
1355 | { |
1356 | struct otx2_nic *vf = netdev_priv(dev: netdev); |
1357 | |
1358 | strscpy(info->driver, DRV_VF_NAME, sizeof(info->driver)); |
1359 | strscpy(info->bus_info, pci_name(vf->pdev), sizeof(info->bus_info)); |
1360 | } |
1361 | |
1362 | static void otx2vf_get_strings(struct net_device *netdev, u32 sset, u8 *data) |
1363 | { |
1364 | struct otx2_nic *vf = netdev_priv(dev: netdev); |
1365 | int stats; |
1366 | |
1367 | if (sset != ETH_SS_STATS) |
1368 | return; |
1369 | |
1370 | for (stats = 0; stats < otx2_n_dev_stats; stats++) { |
1371 | memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN); |
1372 | data += ETH_GSTRING_LEN; |
1373 | } |
1374 | |
1375 | for (stats = 0; stats < otx2_n_drv_stats; stats++) { |
1376 | memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN); |
1377 | data += ETH_GSTRING_LEN; |
1378 | } |
1379 | |
1380 | otx2_get_qset_strings(pfvf: vf, data: &data, qset: 0); |
1381 | |
1382 | strcpy(p: data, q: "reset_count" ); |
1383 | data += ETH_GSTRING_LEN; |
1384 | } |
1385 | |
1386 | static void otx2vf_get_ethtool_stats(struct net_device *netdev, |
1387 | struct ethtool_stats *stats, u64 *data) |
1388 | { |
1389 | struct otx2_nic *vf = netdev_priv(dev: netdev); |
1390 | int stat; |
1391 | |
1392 | otx2_get_dev_stats(pfvf: vf); |
1393 | for (stat = 0; stat < otx2_n_dev_stats; stat++) |
1394 | *(data++) = ((u64 *)&vf->hw.dev_stats) |
1395 | [otx2_dev_stats[stat].index]; |
1396 | |
1397 | for (stat = 0; stat < otx2_n_drv_stats; stat++) |
1398 | *(data++) = atomic_read(v: &((atomic_t *)&vf->hw.drv_stats) |
1399 | [otx2_drv_stats[stat].index]); |
1400 | |
1401 | otx2_get_qset_stats(pfvf: vf, stats, data: &data); |
1402 | *(data++) = vf->reset_count; |
1403 | } |
1404 | |
1405 | static int otx2vf_get_sset_count(struct net_device *netdev, int sset) |
1406 | { |
1407 | struct otx2_nic *vf = netdev_priv(dev: netdev); |
1408 | int qstats_count; |
1409 | |
1410 | if (sset != ETH_SS_STATS) |
1411 | return -EINVAL; |
1412 | |
1413 | qstats_count = otx2_n_queue_stats * |
1414 | (vf->hw.rx_queues + otx2_get_total_tx_queues(pfvf: vf)); |
1415 | |
1416 | return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count + 1; |
1417 | } |
1418 | |
1419 | static int otx2vf_get_link_ksettings(struct net_device *netdev, |
1420 | struct ethtool_link_ksettings *cmd) |
1421 | { |
1422 | struct otx2_nic *pfvf = netdev_priv(dev: netdev); |
1423 | |
1424 | if (is_otx2_lbkvf(pdev: pfvf->pdev)) { |
1425 | cmd->base.duplex = DUPLEX_FULL; |
1426 | cmd->base.speed = SPEED_100000; |
1427 | } else { |
1428 | return otx2_get_link_ksettings(netdev, cmd); |
1429 | } |
1430 | return 0; |
1431 | } |
1432 | |
1433 | static const struct ethtool_ops otx2vf_ethtool_ops = { |
1434 | .cap_rss_ctx_supported = true, |
1435 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
1436 | ETHTOOL_COALESCE_MAX_FRAMES | |
1437 | ETHTOOL_COALESCE_USE_ADAPTIVE, |
1438 | .supported_ring_params = ETHTOOL_RING_USE_RX_BUF_LEN | |
1439 | ETHTOOL_RING_USE_CQE_SIZE, |
1440 | .get_link = otx2_get_link, |
1441 | .get_drvinfo = otx2vf_get_drvinfo, |
1442 | .get_strings = otx2vf_get_strings, |
1443 | .get_ethtool_stats = otx2vf_get_ethtool_stats, |
1444 | .get_sset_count = otx2vf_get_sset_count, |
1445 | .set_channels = otx2_set_channels, |
1446 | .get_channels = otx2_get_channels, |
1447 | .get_rxnfc = otx2_get_rxnfc, |
1448 | .set_rxnfc = otx2_set_rxnfc, |
1449 | .get_rxfh_key_size = otx2_get_rxfh_key_size, |
1450 | .get_rxfh_indir_size = otx2_get_rxfh_indir_size, |
1451 | .get_rxfh = otx2_get_rxfh, |
1452 | .set_rxfh = otx2_set_rxfh, |
1453 | .get_ringparam = otx2_get_ringparam, |
1454 | .set_ringparam = otx2_set_ringparam, |
1455 | .get_coalesce = otx2_get_coalesce, |
1456 | .set_coalesce = otx2_set_coalesce, |
1457 | .get_msglevel = otx2_get_msglevel, |
1458 | .set_msglevel = otx2_set_msglevel, |
1459 | .get_pauseparam = otx2_get_pauseparam, |
1460 | .set_pauseparam = otx2_set_pauseparam, |
1461 | .get_link_ksettings = otx2vf_get_link_ksettings, |
1462 | .get_ts_info = otx2_get_ts_info, |
1463 | }; |
1464 | |
1465 | void otx2vf_set_ethtool_ops(struct net_device *netdev) |
1466 | { |
1467 | netdev->ethtool_ops = &otx2vf_ethtool_ops; |
1468 | } |
1469 | EXPORT_SYMBOL(otx2vf_set_ethtool_ops); |
1470 | |