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