1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2016-2019 Solarflare Communications Inc.
6 * This software was jointly developed between OKTET Labs (under contract
7 * for Solarflare) and Solarflare Communications, Inc.
10 #include <rte_bitmap.h>
15 #include "sfc_debug.h"
17 #include "sfc_kvargs.h"
19 /** Default MAC statistics update period is 1 second */
20 #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF MS_PER_S
22 /** The number of microseconds to sleep on attempt to get statistics update */
23 #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US 10
25 /** The number of attempts to await arrival of freshly generated statistics */
26 #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS 50
29 * Update MAC statistics in the buffer.
32 * @param force_upload Flag to upload MAC stats in any case
36 * @retval EAGAIN Try again
37 * @retval ENOMEM Memory allocation failure
40 sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
42 struct sfc_port *port = &sa->port;
43 efsys_mem_t *esmp = &port->mac_stats_dma_mem;
44 uint32_t *genp = NULL;
46 unsigned int nb_attempts = 0;
49 SFC_ASSERT(sfc_adapter_is_locked(sa));
51 if (sa->state != SFC_ETHDEV_STARTED)
55 * If periodic statistics DMA'ing is off or if not supported,
56 * make a manual request and keep an eye on timer if need be
58 if (!port->mac_stats_periodic_dma_supported ||
59 (port->mac_stats_update_period_ms == 0) || force_upload) {
60 if (port->mac_stats_update_period_ms != 0) {
61 uint64_t timestamp = sfc_get_system_msecs();
64 port->mac_stats_last_request_timestamp) <
65 port->mac_stats_update_period_ms)
68 port->mac_stats_last_request_timestamp = timestamp;
71 rc = efx_mac_stats_upload(sa->nic, esmp);
75 genp = &port->mac_stats_update_generation;
81 rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
83 rc = efx_mac_stats_update(sa->nic, esmp,
84 port->mac_stats_buf, genp);
88 } while ((genp != NULL) && (*genp == gen_old) &&
89 (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
95 sfc_port_reset_sw_stats(struct sfc_adapter *sa)
97 struct sfc_port *port = &sa->port;
100 * Reset diff stats explicitly since check which does not allow
101 * the statistics to grow backward could deny it.
107 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
111 SFC_ASSERT(sfc_adapter_is_locked(sa));
113 rc = efx_mac_stats_clear(sa->nic);
115 sfc_port_reset_sw_stats(sa);
121 sfc_port_init_dev_link(struct sfc_adapter *sa)
123 struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
125 efx_link_mode_t link_mode;
126 struct rte_eth_link current_link;
128 rc = efx_port_poll(sa->nic, &link_mode);
132 sfc_port_link_mode_to_info(link_mode, ¤t_link);
134 EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
135 rte_atomic64_set((rte_atomic64_t *)dev_link,
136 *(uint64_t *)¤t_link);
141 #if EFSYS_OPT_LOOPBACK
143 static efx_link_mode_t
144 sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
146 if (phy_caps & (1u << EFX_PHY_CAP_100000FDX))
147 return EFX_LINK_100000FDX;
148 if (phy_caps & (1u << EFX_PHY_CAP_50000FDX))
149 return EFX_LINK_50000FDX;
150 if (phy_caps & (1u << EFX_PHY_CAP_40000FDX))
151 return EFX_LINK_40000FDX;
152 if (phy_caps & (1u << EFX_PHY_CAP_25000FDX))
153 return EFX_LINK_25000FDX;
154 if (phy_caps & (1u << EFX_PHY_CAP_10000FDX))
155 return EFX_LINK_10000FDX;
156 if (phy_caps & (1u << EFX_PHY_CAP_1000FDX))
157 return EFX_LINK_1000FDX;
158 return EFX_LINK_UNKNOWN;
164 sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
166 unsigned int mac_stats_nb_supported = 0;
167 struct sfc_port *port = &sa->port;
168 unsigned int stat_idx;
170 efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
171 sizeof(port->mac_stats_mask));
173 for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
174 if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
177 port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
178 mac_stats_nb_supported++;
181 port->mac_stats_nb_supported = mac_stats_nb_supported;
185 sfc_port_start(struct sfc_adapter *sa)
187 struct sfc_port *port = &sa->port;
189 uint32_t phy_adv_cap;
190 const uint32_t phy_pause_caps =
191 ((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
193 sfc_log_init(sa, "entry");
195 sfc_log_init(sa, "init filters");
196 rc = efx_filter_init(sa->nic);
198 goto fail_filter_init;
200 sfc_log_init(sa, "init port");
201 rc = efx_port_init(sa->nic);
205 #if EFSYS_OPT_LOOPBACK
206 if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) {
207 efx_link_mode_t link_mode;
210 sfc_port_phy_caps_to_max_link_speed(port->phy_adv_cap);
211 sfc_log_init(sa, "set loopback link_mode=%u type=%u", link_mode,
212 sa->eth_dev->data->dev_conf.lpbk_mode);
213 rc = efx_port_loopback_set(sa->nic, link_mode,
214 sa->eth_dev->data->dev_conf.lpbk_mode);
216 goto fail_loopback_set;
220 sfc_log_init(sa, "set flow control to %#x autoneg=%u",
221 port->flow_ctrl, port->flow_ctrl_autoneg);
222 rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl,
223 port->flow_ctrl_autoneg);
225 goto fail_mac_fcntl_set;
227 /* Preserve pause capabilities set by above efx_mac_fcntl_set() */
228 efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_CURRENT, &phy_adv_cap);
229 SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0);
230 phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps);
233 * No controls for FEC yet. Use default FEC mode.
234 * I.e. advertise everything supported (*_FEC=1), but do not request
235 * anything explicitly (*_FEC_REQUESTED=0).
237 phy_adv_cap |= port->phy_adv_cap_mask &
238 (1u << EFX_PHY_CAP_BASER_FEC |
239 1u << EFX_PHY_CAP_RS_FEC |
240 1u << EFX_PHY_CAP_25G_BASER_FEC);
242 sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap);
243 rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap);
245 goto fail_phy_adv_cap_set;
247 sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
248 rc = efx_mac_pdu_set(sa->nic, port->pdu);
250 goto fail_mac_pdu_set;
252 if (!sfc_sa2shared(sa)->isolated) {
253 struct rte_ether_addr *addr = &port->default_mac_addr;
255 sfc_log_init(sa, "set MAC address");
256 rc = efx_mac_addr_set(sa->nic, addr->addr_bytes);
258 goto fail_mac_addr_set;
260 sfc_log_init(sa, "set MAC filters");
261 port->promisc = (sa->eth_dev->data->promiscuous != 0) ?
263 port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
265 rc = sfc_set_rx_mode_unchecked(sa);
267 goto fail_mac_filter_set;
269 sfc_log_init(sa, "set multicast address list");
270 rc = efx_mac_multicast_list_set(sa->nic, port->mcast_addrs,
271 port->nb_mcast_addrs);
273 goto fail_mcast_address_list_set;
276 if (port->mac_stats_reset_pending) {
277 rc = sfc_port_reset_mac_stats(sa);
279 sfc_err(sa, "statistics reset failed (requested "
280 "before the port was started)");
282 port->mac_stats_reset_pending = B_FALSE;
285 sfc_port_fill_mac_stats_info(sa);
287 port->mac_stats_update_generation = 0;
289 if (port->mac_stats_update_period_ms != 0) {
291 * Update MAC stats using periodic DMA;
292 * any positive update interval different from
293 * 1000 ms can be set only on SFN8xxx provided
294 * that FW version is 6.2.1.1033 or higher
296 sfc_log_init(sa, "request MAC stats DMA'ing");
297 rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
298 port->mac_stats_update_period_ms,
301 port->mac_stats_periodic_dma_supported = B_TRUE;
302 } else if (rc == EOPNOTSUPP) {
303 port->mac_stats_periodic_dma_supported = B_FALSE;
304 port->mac_stats_last_request_timestamp = 0;
306 goto fail_mac_stats_periodic;
310 if ((port->mac_stats_update_period_ms != 0) &&
311 port->mac_stats_periodic_dma_supported) {
313 * Request an explicit MAC stats upload immediately to
314 * preclude bogus figures readback if the user decides
315 * to read stats before periodic DMA is really started
317 rc = efx_mac_stats_upload(sa->nic, &port->mac_stats_dma_mem);
319 goto fail_mac_stats_upload;
322 sfc_log_init(sa, "disable MAC drain");
323 rc = efx_mac_drain(sa->nic, B_FALSE);
327 /* Synchronize link status knowledge */
328 rc = sfc_port_init_dev_link(sa);
330 goto fail_port_init_dev_link;
332 sfc_log_init(sa, "done");
335 fail_port_init_dev_link:
336 (void)efx_mac_drain(sa->nic, B_TRUE);
339 fail_mac_stats_upload:
340 (void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
343 fail_mac_stats_periodic:
344 fail_mcast_address_list_set:
348 fail_phy_adv_cap_set:
350 #if EFSYS_OPT_LOOPBACK
353 efx_port_fini(sa->nic);
356 efx_filter_fini(sa->nic);
359 sfc_log_init(sa, "failed %d", rc);
364 sfc_port_stop(struct sfc_adapter *sa)
366 sfc_log_init(sa, "entry");
368 efx_mac_drain(sa->nic, B_TRUE);
370 (void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
373 sfc_port_update_mac_stats(sa, B_TRUE);
375 efx_port_fini(sa->nic);
376 efx_filter_fini(sa->nic);
378 sfc_log_init(sa, "done");
382 sfc_port_configure(struct sfc_adapter *sa)
384 const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
385 struct sfc_port *port = &sa->port;
387 sfc_log_init(sa, "entry");
389 port->pdu = EFX_MAC_PDU(dev_data->mtu);
395 sfc_port_close(struct sfc_adapter *sa)
397 sfc_log_init(sa, "entry");
401 sfc_port_attach(struct sfc_adapter *sa)
403 struct sfc_port *port = &sa->port;
404 const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
405 const struct rte_ether_addr *from;
407 size_t mac_stats_size;
408 long kvarg_stats_update_period_ms;
411 sfc_log_init(sa, "entry");
413 efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask);
415 /* Enable flow control by default */
416 port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
417 port->flow_ctrl_autoneg = B_TRUE;
419 RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from));
420 from = (const struct rte_ether_addr *)(encp->enc_mac_addr);
421 rte_ether_addr_copy(from, &port->default_mac_addr);
423 port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
424 port->nb_mcast_addrs = 0;
425 port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
426 port->max_mcast_addrs,
429 if (port->mcast_addrs == NULL) {
431 goto fail_mcast_addr_list_buf_alloc;
435 port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
438 if (port->mac_stats_buf == NULL)
439 goto fail_mac_stats_buf_alloc;
441 mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats;
442 mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE);
443 rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_NIC_DMA_ADDR_MAC_STATS_BUF,
445 sa->socket_id, &port->mac_stats_dma_mem);
447 goto fail_mac_stats_dma_alloc;
449 port->mac_stats_reset_pending = B_FALSE;
451 kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
453 rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
454 sfc_kvarg_long_handler,
455 &kvarg_stats_update_period_ms);
457 ((kvarg_stats_update_period_ms < 0) ||
458 (kvarg_stats_update_period_ms > UINT16_MAX))) {
459 sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
460 "was set (%ld);", kvarg_stats_update_period_ms);
461 sfc_err(sa, "it must not be less than 0 "
462 "or greater than %" PRIu16, UINT16_MAX);
464 goto fail_kvarg_stats_update_period_ms;
465 } else if (rc != 0) {
466 goto fail_kvarg_stats_update_period_ms;
469 port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
471 sfc_log_init(sa, "done");
474 fail_kvarg_stats_update_period_ms:
475 sfc_dma_free(sa, &port->mac_stats_dma_mem);
477 fail_mac_stats_dma_alloc:
478 rte_free(port->mac_stats_buf);
480 fail_mac_stats_buf_alloc:
481 rte_free(port->mcast_addrs);
483 fail_mcast_addr_list_buf_alloc:
484 sfc_log_init(sa, "failed %d", rc);
489 sfc_port_detach(struct sfc_adapter *sa)
491 struct sfc_port *port = &sa->port;
493 sfc_log_init(sa, "entry");
495 sfc_dma_free(sa, &port->mac_stats_dma_mem);
496 rte_free(port->mac_stats_buf);
498 rte_free(port->mcast_addrs);
500 sfc_log_init(sa, "done");
504 sfc_get_requested_all_ucast(struct sfc_port *port)
506 return port->promisc;
510 sfc_get_requested_all_mcast(struct sfc_port *port)
512 return port->promisc || port->allmulti;
516 sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
518 struct sfc_port *port = &sa->port;
519 boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
520 boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
523 rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
524 requested_all_mcast, B_TRUE);
532 sfc_set_rx_mode(struct sfc_adapter *sa)
534 struct sfc_port *port = &sa->port;
535 boolean_t old_all_ucast;
536 boolean_t old_all_mcast;
537 boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
538 boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
539 boolean_t actual_all_ucast;
540 boolean_t actual_all_mcast;
543 efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
546 rc = sfc_set_rx_mode_unchecked(sa);
550 efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
553 if (actual_all_ucast != requested_all_ucast ||
554 actual_all_mcast != requested_all_mcast) {
556 * MAC filter set succeeded but not all requested modes
557 * were applied. The rollback is necessary to bring back the
558 * consistent old state.
560 (void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
561 old_all_mcast, B_TRUE);
570 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
571 struct rte_eth_link *link_info)
573 SFC_ASSERT(link_mode < EFX_LINK_NMODES);
575 memset(link_info, 0, sizeof(*link_info));
576 if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
577 link_info->link_status = RTE_ETH_LINK_DOWN;
579 link_info->link_status = RTE_ETH_LINK_UP;
583 link_info->link_speed = RTE_ETH_SPEED_NUM_10M;
584 link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
587 link_info->link_speed = RTE_ETH_SPEED_NUM_10M;
588 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
590 case EFX_LINK_100HDX:
591 link_info->link_speed = RTE_ETH_SPEED_NUM_100M;
592 link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
594 case EFX_LINK_100FDX:
595 link_info->link_speed = RTE_ETH_SPEED_NUM_100M;
596 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
598 case EFX_LINK_1000HDX:
599 link_info->link_speed = RTE_ETH_SPEED_NUM_1G;
600 link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
602 case EFX_LINK_1000FDX:
603 link_info->link_speed = RTE_ETH_SPEED_NUM_1G;
604 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
606 case EFX_LINK_10000FDX:
607 link_info->link_speed = RTE_ETH_SPEED_NUM_10G;
608 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
610 case EFX_LINK_25000FDX:
611 link_info->link_speed = RTE_ETH_SPEED_NUM_25G;
612 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
614 case EFX_LINK_40000FDX:
615 link_info->link_speed = RTE_ETH_SPEED_NUM_40G;
616 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
618 case EFX_LINK_50000FDX:
619 link_info->link_speed = RTE_ETH_SPEED_NUM_50G;
620 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
622 case EFX_LINK_100000FDX:
623 link_info->link_speed = RTE_ETH_SPEED_NUM_100G;
624 link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
629 case EFX_LINK_UNKNOWN:
631 link_info->link_speed = RTE_ETH_SPEED_NUM_NONE;
632 link_info->link_duplex = 0;
636 link_info->link_autoneg = RTE_ETH_LINK_AUTONEG;
640 sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
641 unsigned int xstats_count, unsigned int *nb_written)
643 struct sfc_port *port = &sa->port;
649 sfc_adapter_lock(sa);
651 ret = sfc_port_update_mac_stats(sa, B_FALSE);
658 mac_stats = port->mac_stats_buf;
660 for (i = 0; i < EFX_MAC_NSTATS; ++i) {
661 if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
662 if (nstats < (int)xstats_count) {
663 xstats[nstats].id = nstats;
664 xstats[nstats].value = mac_stats[i];
673 sfc_adapter_unlock(sa);
679 sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
680 uint64_t *values, unsigned int n)
682 struct sfc_port *port = &sa->port;
688 sfc_adapter_lock(sa);
690 rc = sfc_port_update_mac_stats(sa, B_FALSE);
697 mac_stats = port->mac_stats_buf;
699 SFC_ASSERT(port->mac_stats_nb_supported <=
700 RTE_DIM(port->mac_stats_by_id));
702 for (i = 0; i < n; i++) {
703 if (ids[i] < port->mac_stats_nb_supported)
704 values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
710 sfc_adapter_unlock(sa);