xref: /dpdk/drivers/net/sfc/sfc_port.c (revision 3037e6cf)
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
sfc_port_update_mac_stats(struct sfc_adapter * sa,boolean_t force_upload)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
sfc_port_reset_sw_stats(struct sfc_adapter * sa)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
sfc_port_reset_mac_stats(struct sfc_adapter * sa)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
sfc_port_init_dev_link(struct sfc_adapter * sa)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
sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)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
sfc_port_fill_mac_stats_info(struct sfc_adapter * sa)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
sfc_port_start(struct sfc_adapter * sa)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
sfc_port_stop(struct sfc_adapter * sa)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
sfc_port_configure(struct sfc_adapter * sa)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 
387 	sfc_log_init(sa, "entry");
388 
389 	port->pdu = EFX_MAC_PDU(dev_data->mtu);
390 
391 	return 0;
392 }
393 
394 void
sfc_port_close(struct sfc_adapter * sa)395 sfc_port_close(struct sfc_adapter *sa)
396 {
397 	sfc_log_init(sa, "entry");
398 }
399 
400 int
sfc_port_attach(struct sfc_adapter * sa)401 sfc_port_attach(struct sfc_adapter *sa)
402 {
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;
406 	uint32_t mac_nstats;
407 	size_t mac_stats_size;
408 	long kvarg_stats_update_period_ms;
409 	int rc;
410 
411 	sfc_log_init(sa, "entry");
412 
413 	efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask);
414 
415 	/* Enable flow control by default */
416 	port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
417 	port->flow_ctrl_autoneg = B_TRUE;
418 
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);
422 
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,
427 					      EFX_MAC_ADDR_LEN, 0,
428 					      sa->socket_id);
429 	if (port->mcast_addrs == NULL) {
430 		rc = ENOMEM;
431 		goto fail_mcast_addr_list_buf_alloc;
432 	}
433 
434 	rc = ENOMEM;
435 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
436 						sizeof(uint64_t), 0,
437 						sa->socket_id);
438 	if (port->mac_stats_buf == NULL)
439 		goto fail_mac_stats_buf_alloc;
440 
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,
444 			   mac_stats_size,
445 			   sa->socket_id, &port->mac_stats_dma_mem);
446 	if (rc != 0)
447 		goto fail_mac_stats_dma_alloc;
448 
449 	port->mac_stats_reset_pending = B_FALSE;
450 
451 	kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
452 
453 	rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
454 				sfc_kvarg_long_handler,
455 				&kvarg_stats_update_period_ms);
456 	if ((rc == 0) &&
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);
463 		rc = EINVAL;
464 		goto fail_kvarg_stats_update_period_ms;
465 	} else if (rc != 0) {
466 		goto fail_kvarg_stats_update_period_ms;
467 	}
468 
469 	port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
470 
471 	sfc_log_init(sa, "done");
472 	return 0;
473 
474 fail_kvarg_stats_update_period_ms:
475 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
476 
477 fail_mac_stats_dma_alloc:
478 	rte_free(port->mac_stats_buf);
479 
480 fail_mac_stats_buf_alloc:
481 	rte_free(port->mcast_addrs);
482 
483 fail_mcast_addr_list_buf_alloc:
484 	sfc_log_init(sa, "failed %d", rc);
485 	return rc;
486 }
487 
488 void
sfc_port_detach(struct sfc_adapter * sa)489 sfc_port_detach(struct sfc_adapter *sa)
490 {
491 	struct sfc_port *port = &sa->port;
492 
493 	sfc_log_init(sa, "entry");
494 
495 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
496 	rte_free(port->mac_stats_buf);
497 
498 	rte_free(port->mcast_addrs);
499 
500 	sfc_log_init(sa, "done");
501 }
502 
503 static boolean_t
sfc_get_requested_all_ucast(struct sfc_port * port)504 sfc_get_requested_all_ucast(struct sfc_port *port)
505 {
506 	return port->promisc;
507 }
508 
509 static boolean_t
sfc_get_requested_all_mcast(struct sfc_port * port)510 sfc_get_requested_all_mcast(struct sfc_port *port)
511 {
512 	return port->promisc || port->allmulti;
513 }
514 
515 int
sfc_set_rx_mode_unchecked(struct sfc_adapter * sa)516 sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
517 {
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);
521 	int rc;
522 
523 	rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
524 				requested_all_mcast, B_TRUE);
525 	if (rc != 0)
526 		return rc;
527 
528 	return 0;
529 }
530 
531 int
sfc_set_rx_mode(struct sfc_adapter * sa)532 sfc_set_rx_mode(struct sfc_adapter *sa)
533 {
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;
541 	int rc;
542 
543 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
544 					   &old_all_mcast);
545 
546 	rc = sfc_set_rx_mode_unchecked(sa);
547 	if (rc != 0)
548 		return rc;
549 
550 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
551 					   &actual_all_mcast);
552 
553 	if (actual_all_ucast != requested_all_ucast ||
554 	    actual_all_mcast != requested_all_mcast) {
555 		/*
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.
559 		 */
560 		(void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
561 					 old_all_mcast, B_TRUE);
562 
563 		return EPERM;
564 	}
565 
566 	return 0;
567 }
568 
569 void
sfc_port_link_mode_to_info(efx_link_mode_t link_mode,struct rte_eth_link * link_info)570 sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
571 			   struct rte_eth_link *link_info)
572 {
573 	SFC_ASSERT(link_mode < EFX_LINK_NMODES);
574 
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;
578 	else
579 		link_info->link_status = RTE_ETH_LINK_UP;
580 
581 	switch (link_mode) {
582 	case EFX_LINK_10HDX:
583 		link_info->link_speed  = RTE_ETH_SPEED_NUM_10M;
584 		link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
585 		break;
586 	case EFX_LINK_10FDX:
587 		link_info->link_speed  = RTE_ETH_SPEED_NUM_10M;
588 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
589 		break;
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;
593 		break;
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;
597 		break;
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;
601 		break;
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;
605 		break;
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;
609 		break;
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;
613 		break;
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;
617 		break;
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;
621 		break;
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;
625 		break;
626 	default:
627 		SFC_ASSERT(B_FALSE);
628 		/* FALLTHROUGH */
629 	case EFX_LINK_UNKNOWN:
630 	case EFX_LINK_DOWN:
631 		link_info->link_speed  = RTE_ETH_SPEED_NUM_NONE;
632 		link_info->link_duplex = 0;
633 		break;
634 	}
635 
636 	link_info->link_autoneg = RTE_ETH_LINK_AUTONEG;
637 }
638 
639 int
sfc_port_get_mac_stats(struct sfc_adapter * sa,struct rte_eth_xstat * xstats,unsigned int xstats_count,unsigned int * nb_written)640 sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
641 		       unsigned int xstats_count, unsigned int *nb_written)
642 {
643 	struct sfc_port *port = &sa->port;
644 	uint64_t *mac_stats;
645 	unsigned int i;
646 	int nstats = 0;
647 	int ret;
648 
649 	sfc_adapter_lock(sa);
650 
651 	ret = sfc_port_update_mac_stats(sa, B_FALSE);
652 	if (ret != 0) {
653 		SFC_ASSERT(ret > 0);
654 		ret = -ret;
655 		goto unlock;
656 	}
657 
658 	mac_stats = port->mac_stats_buf;
659 
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];
665 				(*nb_written)++;
666 			}
667 			nstats++;
668 		}
669 	}
670 	ret = nstats;
671 
672 unlock:
673 	sfc_adapter_unlock(sa);
674 
675 	return ret;
676 }
677 
678 int
sfc_port_get_mac_stats_by_id(struct sfc_adapter * sa,const uint64_t * ids,uint64_t * values,unsigned int n)679 sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
680 			     uint64_t *values, unsigned int n)
681 {
682 	struct sfc_port *port = &sa->port;
683 	uint64_t *mac_stats;
684 	unsigned int i;
685 	int ret;
686 	int rc;
687 
688 	sfc_adapter_lock(sa);
689 
690 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
691 	if (rc != 0) {
692 		SFC_ASSERT(rc > 0);
693 		ret = -rc;
694 		goto unlock;
695 	}
696 
697 	mac_stats = port->mac_stats_buf;
698 
699 	SFC_ASSERT(port->mac_stats_nb_supported <=
700 		   RTE_DIM(port->mac_stats_by_id));
701 
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]]];
705 	}
706 
707 	ret = 0;
708 
709 unlock:
710 	sfc_adapter_unlock(sa);
711 
712 	return ret;
713 }
714