xref: /dpdk/drivers/net/sfc/sfc_port.c (revision 081e42dab11d1add2d038fdf2bd4c86b20043d08)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  * Copyright(c) 2016-2019 Solarflare Communications Inc.
5  *
6  * This software was jointly developed between OKTET Labs (under contract
7  * for Solarflare) and Solarflare Communications, Inc.
8  */
9 
10 #include <rte_bitmap.h>
11 
12 #include "efx.h"
13 
14 #include "sfc.h"
15 #include "sfc_debug.h"
16 #include "sfc_log.h"
17 #include "sfc_kvargs.h"
18 
19 /** Default MAC statistics update period is 1 second */
20 #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF	MS_PER_S
21 
22 /** The number of microseconds to sleep on attempt to get statistics update */
23 #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US	10
24 
25 /** The number of attempts to await arrival of freshly generated statistics */
26 #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS	50
27 
28 /**
29  * Update MAC statistics in the buffer.
30  *
31  * @param	sa		Adapter
32  * @param	force_upload	Flag to upload MAC stats in any case
33  *
34  * @return Status code
35  * @retval	0	Success
36  * @retval	EAGAIN	Try again
37  * @retval	ENOMEM	Memory allocation failure
38  */
39 int
40 sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
41 {
42 	struct sfc_port *port = &sa->port;
43 	efsys_mem_t *esmp = &port->mac_stats_dma_mem;
44 	uint32_t *genp = NULL;
45 	uint32_t gen_old;
46 	unsigned int nb_attempts = 0;
47 	int rc;
48 
49 	SFC_ASSERT(sfc_adapter_is_locked(sa));
50 
51 	if (sa->state != SFC_ETHDEV_STARTED)
52 		return 0;
53 
54 	/*
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
57 	 */
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();
62 
63 			if ((timestamp -
64 			     port->mac_stats_last_request_timestamp) <
65 			    port->mac_stats_update_period_ms)
66 				return 0;
67 
68 			port->mac_stats_last_request_timestamp = timestamp;
69 		}
70 
71 		rc = efx_mac_stats_upload(sa->nic, esmp);
72 		if (rc != 0)
73 			return rc;
74 
75 		genp = &port->mac_stats_update_generation;
76 		gen_old = *genp;
77 	}
78 
79 	do {
80 		if (nb_attempts > 0)
81 			rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
82 
83 		rc = efx_mac_stats_update(sa->nic, esmp,
84 					  port->mac_stats_buf, genp);
85 		if (rc != 0)
86 			return rc;
87 
88 	} while ((genp != NULL) && (*genp == gen_old) &&
89 		 (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
90 
91 	return 0;
92 }
93 
94 static void
95 sfc_port_reset_sw_stats(struct sfc_adapter *sa)
96 {
97 	struct sfc_port *port = &sa->port;
98 
99 	/*
100 	 * Reset diff stats explicitly since check which does not allow
101 	 * the statistics to grow backward could deny it.
102 	 */
103 	port->ipackets = 0;
104 }
105 
106 int
107 sfc_port_reset_mac_stats(struct sfc_adapter *sa)
108 {
109 	int rc;
110 
111 	SFC_ASSERT(sfc_adapter_is_locked(sa));
112 
113 	rc = efx_mac_stats_clear(sa->nic);
114 	if (rc == 0)
115 		sfc_port_reset_sw_stats(sa);
116 
117 	return rc;
118 }
119 
120 static int
121 sfc_port_init_dev_link(struct sfc_adapter *sa)
122 {
123 	struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
124 	int rc;
125 	efx_link_mode_t link_mode;
126 	struct rte_eth_link current_link;
127 
128 	rc = efx_port_poll(sa->nic, &link_mode);
129 	if (rc != 0)
130 		return rc;
131 
132 	sfc_port_link_mode_to_info(link_mode, &current_link);
133 
134 	EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
135 	rte_atomic64_set((rte_atomic64_t *)dev_link,
136 			 *(uint64_t *)&current_link);
137 
138 	return 0;
139 }
140 
141 #if EFSYS_OPT_LOOPBACK
142 
143 static efx_link_mode_t
144 sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
145 {
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;
159 }
160 
161 #endif
162 
163 static void
164 sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
165 {
166 	unsigned int mac_stats_nb_supported = 0;
167 	struct sfc_port *port = &sa->port;
168 	unsigned int stat_idx;
169 
170 	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
171 			       sizeof(port->mac_stats_mask));
172 
173 	for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
174 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
175 			continue;
176 
177 		port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
178 		mac_stats_nb_supported++;
179 	}
180 
181 	port->mac_stats_nb_supported = mac_stats_nb_supported;
182 }
183 
184 int
185 sfc_port_start(struct sfc_adapter *sa)
186 {
187 	struct sfc_port *port = &sa->port;
188 	int rc;
189 	uint32_t phy_adv_cap;
190 	const uint32_t phy_pause_caps =
191 		((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
192 
193 	sfc_log_init(sa, "entry");
194 
195 	sfc_log_init(sa, "init filters");
196 	rc = efx_filter_init(sa->nic);
197 	if (rc != 0)
198 		goto fail_filter_init;
199 
200 	sfc_log_init(sa, "init port");
201 	rc = efx_port_init(sa->nic);
202 	if (rc != 0)
203 		goto fail_port_init;
204 
205 #if EFSYS_OPT_LOOPBACK
206 	if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) {
207 		efx_link_mode_t link_mode;
208 
209 		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);
215 		if (rc != 0)
216 			goto fail_loopback_set;
217 	}
218 #endif
219 
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);
224 	if (rc != 0)
225 		goto fail_mac_fcntl_set;
226 
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);
231 
232 	/*
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).
236 	 */
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);
241 
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);
244 	if (rc != 0)
245 		goto fail_phy_adv_cap_set;
246 
247 	sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
248 	rc = efx_mac_pdu_set(sa->nic, port->pdu);
249 	if (rc != 0)
250 		goto fail_mac_pdu_set;
251 
252 	if (!sfc_sa2shared(sa)->isolated) {
253 		struct rte_ether_addr *addr = &port->default_mac_addr;
254 
255 		sfc_log_init(sa, "set MAC address");
256 		rc = efx_mac_addr_set(sa->nic, addr->addr_bytes);
257 		if (rc != 0)
258 			goto fail_mac_addr_set;
259 
260 		sfc_log_init(sa, "set MAC filters");
261 		port->promisc = (sa->eth_dev->data->promiscuous != 0) ?
262 				B_TRUE : B_FALSE;
263 		port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
264 				 B_TRUE : B_FALSE;
265 		rc = sfc_set_rx_mode_unchecked(sa);
266 		if (rc != 0)
267 			goto fail_mac_filter_set;
268 
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);
272 		if (rc != 0)
273 			goto fail_mcast_address_list_set;
274 	}
275 
276 	if (port->mac_stats_reset_pending) {
277 		rc = sfc_port_reset_mac_stats(sa);
278 		if (rc != 0)
279 			sfc_err(sa, "statistics reset failed (requested "
280 				    "before the port was started)");
281 
282 		port->mac_stats_reset_pending = B_FALSE;
283 	}
284 
285 	sfc_port_fill_mac_stats_info(sa);
286 
287 	port->mac_stats_update_generation = 0;
288 
289 	if (port->mac_stats_update_period_ms != 0) {
290 		/*
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
295 		 */
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,
299 					    B_FALSE);
300 		if (rc == 0) {
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;
305 		} else {
306 			goto fail_mac_stats_periodic;
307 		}
308 	}
309 
310 	if ((port->mac_stats_update_period_ms != 0) &&
311 	    port->mac_stats_periodic_dma_supported) {
312 		/*
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
316 		 */
317 		rc = efx_mac_stats_upload(sa->nic, &port->mac_stats_dma_mem);
318 		if (rc != 0)
319 			goto fail_mac_stats_upload;
320 	}
321 
322 	sfc_log_init(sa, "disable MAC drain");
323 	rc = efx_mac_drain(sa->nic, B_FALSE);
324 	if (rc != 0)
325 		goto fail_mac_drain;
326 
327 	/* Synchronize link status knowledge */
328 	rc = sfc_port_init_dev_link(sa);
329 	if (rc != 0)
330 		goto fail_port_init_dev_link;
331 
332 	sfc_log_init(sa, "done");
333 	return 0;
334 
335 fail_port_init_dev_link:
336 	(void)efx_mac_drain(sa->nic, B_TRUE);
337 
338 fail_mac_drain:
339 fail_mac_stats_upload:
340 	(void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
341 				     0, B_FALSE);
342 
343 fail_mac_stats_periodic:
344 fail_mcast_address_list_set:
345 fail_mac_filter_set:
346 fail_mac_addr_set:
347 fail_mac_pdu_set:
348 fail_phy_adv_cap_set:
349 fail_mac_fcntl_set:
350 #if EFSYS_OPT_LOOPBACK
351 fail_loopback_set:
352 #endif
353 	efx_port_fini(sa->nic);
354 
355 fail_port_init:
356 	efx_filter_fini(sa->nic);
357 
358 fail_filter_init:
359 	sfc_log_init(sa, "failed %d", rc);
360 	return rc;
361 }
362 
363 void
364 sfc_port_stop(struct sfc_adapter *sa)
365 {
366 	sfc_log_init(sa, "entry");
367 
368 	efx_mac_drain(sa->nic, B_TRUE);
369 
370 	(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
371 				     0, B_FALSE);
372 
373 	sfc_port_update_mac_stats(sa, B_TRUE);
374 
375 	efx_port_fini(sa->nic);
376 	efx_filter_fini(sa->nic);
377 
378 	sfc_log_init(sa, "done");
379 }
380 
381 int
382 sfc_port_configure(struct sfc_adapter *sa)
383 {
384 	const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
385 	struct sfc_port *port = &sa->port;
386 	const struct rte_eth_rxmode *rxmode = &dev_data->dev_conf.rxmode;
387 
388 	sfc_log_init(sa, "entry");
389 
390 	if (rxmode->offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
391 		port->pdu = rxmode->max_rx_pkt_len;
392 	else
393 		port->pdu = EFX_MAC_PDU(dev_data->mtu);
394 
395 	return 0;
396 }
397 
398 void
399 sfc_port_close(struct sfc_adapter *sa)
400 {
401 	sfc_log_init(sa, "entry");
402 }
403 
404 int
405 sfc_port_attach(struct sfc_adapter *sa)
406 {
407 	struct sfc_port *port = &sa->port;
408 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
409 	const struct rte_ether_addr *from;
410 	uint32_t mac_nstats;
411 	size_t mac_stats_size;
412 	long kvarg_stats_update_period_ms;
413 	int rc;
414 
415 	sfc_log_init(sa, "entry");
416 
417 	efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask);
418 
419 	/* Enable flow control by default */
420 	port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
421 	port->flow_ctrl_autoneg = B_TRUE;
422 
423 	RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from));
424 	from = (const struct rte_ether_addr *)(encp->enc_mac_addr);
425 	rte_ether_addr_copy(from, &port->default_mac_addr);
426 
427 	port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
428 	port->nb_mcast_addrs = 0;
429 	port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
430 					      port->max_mcast_addrs,
431 					      EFX_MAC_ADDR_LEN, 0,
432 					      sa->socket_id);
433 	if (port->mcast_addrs == NULL) {
434 		rc = ENOMEM;
435 		goto fail_mcast_addr_list_buf_alloc;
436 	}
437 
438 	rc = ENOMEM;
439 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
440 						sizeof(uint64_t), 0,
441 						sa->socket_id);
442 	if (port->mac_stats_buf == NULL)
443 		goto fail_mac_stats_buf_alloc;
444 
445 	mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats;
446 	mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE);
447 	rc = sfc_dma_alloc(sa, "mac_stats", 0, mac_stats_size,
448 			   sa->socket_id, &port->mac_stats_dma_mem);
449 	if (rc != 0)
450 		goto fail_mac_stats_dma_alloc;
451 
452 	port->mac_stats_reset_pending = B_FALSE;
453 
454 	kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
455 
456 	rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
457 				sfc_kvarg_long_handler,
458 				&kvarg_stats_update_period_ms);
459 	if ((rc == 0) &&
460 	    ((kvarg_stats_update_period_ms < 0) ||
461 	     (kvarg_stats_update_period_ms > UINT16_MAX))) {
462 		sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
463 			    "was set (%ld);", kvarg_stats_update_period_ms);
464 		sfc_err(sa, "it must not be less than 0 "
465 			    "or greater than %" PRIu16, UINT16_MAX);
466 		rc = EINVAL;
467 		goto fail_kvarg_stats_update_period_ms;
468 	} else if (rc != 0) {
469 		goto fail_kvarg_stats_update_period_ms;
470 	}
471 
472 	port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
473 
474 	sfc_log_init(sa, "done");
475 	return 0;
476 
477 fail_kvarg_stats_update_period_ms:
478 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
479 
480 fail_mac_stats_dma_alloc:
481 	rte_free(port->mac_stats_buf);
482 
483 fail_mac_stats_buf_alloc:
484 	rte_free(port->mcast_addrs);
485 
486 fail_mcast_addr_list_buf_alloc:
487 	sfc_log_init(sa, "failed %d", rc);
488 	return rc;
489 }
490 
491 void
492 sfc_port_detach(struct sfc_adapter *sa)
493 {
494 	struct sfc_port *port = &sa->port;
495 
496 	sfc_log_init(sa, "entry");
497 
498 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
499 	rte_free(port->mac_stats_buf);
500 
501 	rte_free(port->mcast_addrs);
502 
503 	sfc_log_init(sa, "done");
504 }
505 
506 static boolean_t
507 sfc_get_requested_all_ucast(struct sfc_port *port)
508 {
509 	return port->promisc;
510 }
511 
512 static boolean_t
513 sfc_get_requested_all_mcast(struct sfc_port *port)
514 {
515 	return port->promisc || port->allmulti;
516 }
517 
518 int
519 sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
520 {
521 	struct sfc_port *port = &sa->port;
522 	boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
523 	boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
524 	int rc;
525 
526 	rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
527 				requested_all_mcast, B_TRUE);
528 	if (rc != 0)
529 		return rc;
530 
531 	return 0;
532 }
533 
534 int
535 sfc_set_rx_mode(struct sfc_adapter *sa)
536 {
537 	struct sfc_port *port = &sa->port;
538 	boolean_t old_all_ucast;
539 	boolean_t old_all_mcast;
540 	boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
541 	boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
542 	boolean_t actual_all_ucast;
543 	boolean_t actual_all_mcast;
544 	int rc;
545 
546 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
547 					   &old_all_mcast);
548 
549 	rc = sfc_set_rx_mode_unchecked(sa);
550 	if (rc != 0)
551 		return rc;
552 
553 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
554 					   &actual_all_mcast);
555 
556 	if (actual_all_ucast != requested_all_ucast ||
557 	    actual_all_mcast != requested_all_mcast) {
558 		/*
559 		 * MAC filter set succeeded but not all requested modes
560 		 * were applied. The rollback is necessary to bring back the
561 		 * consistent old state.
562 		 */
563 		(void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
564 					 old_all_mcast, B_TRUE);
565 
566 		return EPERM;
567 	}
568 
569 	return 0;
570 }
571 
572 void
573 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
574 			   struct rte_eth_link *link_info)
575 {
576 	SFC_ASSERT(link_mode < EFX_LINK_NMODES);
577 
578 	memset(link_info, 0, sizeof(*link_info));
579 	if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
580 		link_info->link_status = ETH_LINK_DOWN;
581 	else
582 		link_info->link_status = ETH_LINK_UP;
583 
584 	switch (link_mode) {
585 	case EFX_LINK_10HDX:
586 		link_info->link_speed  = ETH_SPEED_NUM_10M;
587 		link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
588 		break;
589 	case EFX_LINK_10FDX:
590 		link_info->link_speed  = ETH_SPEED_NUM_10M;
591 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
592 		break;
593 	case EFX_LINK_100HDX:
594 		link_info->link_speed  = ETH_SPEED_NUM_100M;
595 		link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
596 		break;
597 	case EFX_LINK_100FDX:
598 		link_info->link_speed  = ETH_SPEED_NUM_100M;
599 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
600 		break;
601 	case EFX_LINK_1000HDX:
602 		link_info->link_speed  = ETH_SPEED_NUM_1G;
603 		link_info->link_duplex = ETH_LINK_HALF_DUPLEX;
604 		break;
605 	case EFX_LINK_1000FDX:
606 		link_info->link_speed  = ETH_SPEED_NUM_1G;
607 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
608 		break;
609 	case EFX_LINK_10000FDX:
610 		link_info->link_speed  = ETH_SPEED_NUM_10G;
611 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
612 		break;
613 	case EFX_LINK_25000FDX:
614 		link_info->link_speed  = ETH_SPEED_NUM_25G;
615 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
616 		break;
617 	case EFX_LINK_40000FDX:
618 		link_info->link_speed  = ETH_SPEED_NUM_40G;
619 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
620 		break;
621 	case EFX_LINK_50000FDX:
622 		link_info->link_speed  = ETH_SPEED_NUM_50G;
623 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
624 		break;
625 	case EFX_LINK_100000FDX:
626 		link_info->link_speed  = ETH_SPEED_NUM_100G;
627 		link_info->link_duplex = ETH_LINK_FULL_DUPLEX;
628 		break;
629 	default:
630 		SFC_ASSERT(B_FALSE);
631 		/* FALLTHROUGH */
632 	case EFX_LINK_UNKNOWN:
633 	case EFX_LINK_DOWN:
634 		link_info->link_speed  = ETH_SPEED_NUM_NONE;
635 		link_info->link_duplex = 0;
636 		break;
637 	}
638 
639 	link_info->link_autoneg = ETH_LINK_AUTONEG;
640 }
641 
642 int
643 sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
644 		       unsigned int xstats_count, unsigned int *nb_written)
645 {
646 	struct sfc_port *port = &sa->port;
647 	uint64_t *mac_stats;
648 	unsigned int i;
649 	int nstats = 0;
650 	int ret;
651 
652 	sfc_adapter_lock(sa);
653 
654 	ret = sfc_port_update_mac_stats(sa, B_FALSE);
655 	if (ret != 0) {
656 		SFC_ASSERT(ret > 0);
657 		ret = -ret;
658 		goto unlock;
659 	}
660 
661 	mac_stats = port->mac_stats_buf;
662 
663 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
664 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
665 			if (nstats < (int)xstats_count) {
666 				xstats[nstats].id = nstats;
667 				xstats[nstats].value = mac_stats[i];
668 				(*nb_written)++;
669 			}
670 			nstats++;
671 		}
672 	}
673 	ret = nstats;
674 
675 unlock:
676 	sfc_adapter_unlock(sa);
677 
678 	return ret;
679 }
680 
681 int
682 sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
683 			     uint64_t *values, unsigned int n)
684 {
685 	struct sfc_port *port = &sa->port;
686 	uint64_t *mac_stats;
687 	unsigned int i;
688 	int ret;
689 	int rc;
690 
691 	sfc_adapter_lock(sa);
692 
693 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
694 	if (rc != 0) {
695 		SFC_ASSERT(rc > 0);
696 		ret = -rc;
697 		goto unlock;
698 	}
699 
700 	mac_stats = port->mac_stats_buf;
701 
702 	SFC_ASSERT(port->mac_stats_nb_supported <=
703 		   RTE_DIM(port->mac_stats_by_id));
704 
705 	for (i = 0; i < n; i++) {
706 		if (ids[i] < port->mac_stats_nb_supported)
707 			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
708 	}
709 
710 	ret = 0;
711 
712 unlock:
713 	sfc_adapter_unlock(sa);
714 
715 	return ret;
716 }
717