xref: /dpdk/drivers/net/sfc/sfc_port.c (revision 62082124a23e004a771167b191b2102ca9cb3350)
144c0947bSAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
2244cfa79SAndrew Rybchenko  *
398d26ef7SAndrew Rybchenko  * Copyright(c) 2019-2021 Xilinx, Inc.
4a0147be5SAndrew Rybchenko  * Copyright(c) 2016-2019 Solarflare Communications Inc.
503ed2119SAndrew Rybchenko  *
603ed2119SAndrew Rybchenko  * This software was jointly developed between OKTET Labs (under contract
703ed2119SAndrew Rybchenko  * for Solarflare) and Solarflare Communications, Inc.
803ed2119SAndrew Rybchenko  */
903ed2119SAndrew Rybchenko 
10fdd7719eSIvan Ilchenko #include <rte_bitmap.h>
11ae9aafe4SIvan Malov #include <rte_ether.h>
12fdd7719eSIvan Ilchenko 
1303ed2119SAndrew Rybchenko #include "efx.h"
1403ed2119SAndrew Rybchenko 
1503ed2119SAndrew Rybchenko #include "sfc.h"
161b0236e2SAndrew Rybchenko #include "sfc_debug.h"
1703ed2119SAndrew Rybchenko #include "sfc_log.h"
18e56fa9c2SIvan Malov #include "sfc_kvargs.h"
19e56fa9c2SIvan Malov 
20e56fa9c2SIvan Malov /** Default MAC statistics update period is 1 second */
21e56fa9c2SIvan Malov #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF	MS_PER_S
22e56fa9c2SIvan Malov 
23e56fa9c2SIvan Malov /** The number of microseconds to sleep on attempt to get statistics update */
24e56fa9c2SIvan Malov #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US	10
25e56fa9c2SIvan Malov 
26e56fa9c2SIvan Malov /** The number of attempts to await arrival of freshly generated statistics */
27e56fa9c2SIvan Malov #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS	50
2803ed2119SAndrew Rybchenko 
291caab2f1SAndrew Rybchenko /**
301caab2f1SAndrew Rybchenko  * Update MAC statistics in the buffer.
311caab2f1SAndrew Rybchenko  *
321caab2f1SAndrew Rybchenko  * @param	sa		Adapter
331827b073SIvan Ilchenko  * @param	force_upload	Flag to upload MAC stats in any case
341caab2f1SAndrew Rybchenko  *
351caab2f1SAndrew Rybchenko  * @return Status code
361caab2f1SAndrew Rybchenko  * @retval	0	Success
371caab2f1SAndrew Rybchenko  * @retval	EAGAIN	Try again
381caab2f1SAndrew Rybchenko  * @retval	ENOMEM	Memory allocation failure
391caab2f1SAndrew Rybchenko  */
401caab2f1SAndrew Rybchenko int
sfc_port_update_mac_stats(struct sfc_adapter * sa,boolean_t force_upload)411827b073SIvan Ilchenko sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload)
421caab2f1SAndrew Rybchenko {
431caab2f1SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
44e56fa9c2SIvan Malov 	efsys_mem_t *esmp = &port->mac_stats_dma_mem;
45e56fa9c2SIvan Malov 	uint32_t *genp = NULL;
46e56fa9c2SIvan Malov 	uint32_t gen_old;
47e56fa9c2SIvan Malov 	unsigned int nb_attempts = 0;
481caab2f1SAndrew Rybchenko 	int rc;
491caab2f1SAndrew Rybchenko 
5017b0d7b3SIvan Ilchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
511caab2f1SAndrew Rybchenko 
52ac478689SIgor Romanov 	if (sa->state != SFC_ETHDEV_STARTED)
531827b073SIvan Ilchenko 		return 0;
541caab2f1SAndrew Rybchenko 
55178fc0d3SIvan Malov 	/*
56178fc0d3SIvan Malov 	 * If periodic statistics DMA'ing is off or if not supported,
57178fc0d3SIvan Malov 	 * make a manual request and keep an eye on timer if need be
58178fc0d3SIvan Malov 	 */
59178fc0d3SIvan Malov 	if (!port->mac_stats_periodic_dma_supported ||
601827b073SIvan Ilchenko 	    (port->mac_stats_update_period_ms == 0) || force_upload) {
61178fc0d3SIvan Malov 		if (port->mac_stats_update_period_ms != 0) {
62178fc0d3SIvan Malov 			uint64_t timestamp = sfc_get_system_msecs();
63178fc0d3SIvan Malov 
64178fc0d3SIvan Malov 			if ((timestamp -
65178fc0d3SIvan Malov 			     port->mac_stats_last_request_timestamp) <
66178fc0d3SIvan Malov 			    port->mac_stats_update_period_ms)
67178fc0d3SIvan Malov 				return 0;
68178fc0d3SIvan Malov 
69178fc0d3SIvan Malov 			port->mac_stats_last_request_timestamp = timestamp;
70178fc0d3SIvan Malov 		}
71178fc0d3SIvan Malov 
72e56fa9c2SIvan Malov 		rc = efx_mac_stats_upload(sa->nic, esmp);
731caab2f1SAndrew Rybchenko 		if (rc != 0)
741caab2f1SAndrew Rybchenko 			return rc;
751caab2f1SAndrew Rybchenko 
76e56fa9c2SIvan Malov 		genp = &port->mac_stats_update_generation;
77e56fa9c2SIvan Malov 		gen_old = *genp;
78e56fa9c2SIvan Malov 	}
79e56fa9c2SIvan Malov 
80e56fa9c2SIvan Malov 	do {
81e56fa9c2SIvan Malov 		if (nb_attempts > 0)
82e56fa9c2SIvan Malov 			rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US);
83e56fa9c2SIvan Malov 
84e56fa9c2SIvan Malov 		rc = efx_mac_stats_update(sa->nic, esmp,
85e56fa9c2SIvan Malov 					  port->mac_stats_buf, genp);
86e56fa9c2SIvan Malov 		if (rc != 0)
87e56fa9c2SIvan Malov 			return rc;
88e56fa9c2SIvan Malov 
89e56fa9c2SIvan Malov 	} while ((genp != NULL) && (*genp == gen_old) &&
90e56fa9c2SIvan Malov 		 (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS));
91e56fa9c2SIvan Malov 
921caab2f1SAndrew Rybchenko 	return 0;
931caab2f1SAndrew Rybchenko }
9403ed2119SAndrew Rybchenko 
95ab77a001SAndrew Rybchenko static void
sfc_port_reset_sw_stats(struct sfc_adapter * sa)96ab77a001SAndrew Rybchenko sfc_port_reset_sw_stats(struct sfc_adapter *sa)
97ab77a001SAndrew Rybchenko {
98ab77a001SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
99ab77a001SAndrew Rybchenko 
100ab77a001SAndrew Rybchenko 	/*
101ab77a001SAndrew Rybchenko 	 * Reset diff stats explicitly since check which does not allow
102ab77a001SAndrew Rybchenko 	 * the statistics to grow backward could deny it.
103ab77a001SAndrew Rybchenko 	 */
104ab77a001SAndrew Rybchenko 	port->ipackets = 0;
105ab77a001SAndrew Rybchenko }
106ab77a001SAndrew Rybchenko 
107e8acb329SIvan Malov int
sfc_port_reset_mac_stats(struct sfc_adapter * sa)108e8acb329SIvan Malov sfc_port_reset_mac_stats(struct sfc_adapter *sa)
109e8acb329SIvan Malov {
110e8acb329SIvan Malov 	int rc;
111e8acb329SIvan Malov 
11217b0d7b3SIvan Ilchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
11317b0d7b3SIvan Ilchenko 
114e8acb329SIvan Malov 	rc = efx_mac_stats_clear(sa->nic);
115ab77a001SAndrew Rybchenko 	if (rc == 0)
116ab77a001SAndrew Rybchenko 		sfc_port_reset_sw_stats(sa);
117e8acb329SIvan Malov 
118e8acb329SIvan Malov 	return rc;
119e8acb329SIvan Malov }
120e8acb329SIvan Malov 
121f08a2377SAndrew Rybchenko static int
sfc_port_init_dev_link(struct sfc_adapter * sa)122f08a2377SAndrew Rybchenko sfc_port_init_dev_link(struct sfc_adapter *sa)
123f08a2377SAndrew Rybchenko {
124f08a2377SAndrew Rybchenko 	struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link;
125f08a2377SAndrew Rybchenko 	int rc;
126f08a2377SAndrew Rybchenko 	efx_link_mode_t link_mode;
127f08a2377SAndrew Rybchenko 	struct rte_eth_link current_link;
128f08a2377SAndrew Rybchenko 
129f08a2377SAndrew Rybchenko 	rc = efx_port_poll(sa->nic, &link_mode);
130f08a2377SAndrew Rybchenko 	if (rc != 0)
131f08a2377SAndrew Rybchenko 		return rc;
132f08a2377SAndrew Rybchenko 
133f08a2377SAndrew Rybchenko 	sfc_port_link_mode_to_info(link_mode, &current_link);
134f08a2377SAndrew Rybchenko 
135f08a2377SAndrew Rybchenko 	EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
136f08a2377SAndrew Rybchenko 	rte_atomic64_set((rte_atomic64_t *)dev_link,
137f08a2377SAndrew Rybchenko 			 *(uint64_t *)&current_link);
138f08a2377SAndrew Rybchenko 
139f08a2377SAndrew Rybchenko 	return 0;
140f08a2377SAndrew Rybchenko }
141f08a2377SAndrew Rybchenko 
142b16cf4b2SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
143b16cf4b2SAndrew Rybchenko 
144b16cf4b2SAndrew Rybchenko static efx_link_mode_t
sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)145b16cf4b2SAndrew Rybchenko sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps)
146b16cf4b2SAndrew Rybchenko {
147b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_100000FDX))
148b16cf4b2SAndrew Rybchenko 		return EFX_LINK_100000FDX;
149b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_50000FDX))
150b16cf4b2SAndrew Rybchenko 		return EFX_LINK_50000FDX;
151b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_40000FDX))
152b16cf4b2SAndrew Rybchenko 		return EFX_LINK_40000FDX;
153b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_25000FDX))
154b16cf4b2SAndrew Rybchenko 		return EFX_LINK_25000FDX;
155b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_10000FDX))
156b16cf4b2SAndrew Rybchenko 		return EFX_LINK_10000FDX;
157b16cf4b2SAndrew Rybchenko 	if (phy_caps & (1u << EFX_PHY_CAP_1000FDX))
158b16cf4b2SAndrew Rybchenko 		return EFX_LINK_1000FDX;
159b16cf4b2SAndrew Rybchenko 	return EFX_LINK_UNKNOWN;
160b16cf4b2SAndrew Rybchenko }
161b16cf4b2SAndrew Rybchenko 
162b16cf4b2SAndrew Rybchenko #endif
163b16cf4b2SAndrew Rybchenko 
1647d466e5fSIvan Ilchenko static void
sfc_port_fill_mac_stats_info(struct sfc_adapter * sa)1657d466e5fSIvan Ilchenko sfc_port_fill_mac_stats_info(struct sfc_adapter *sa)
1667d466e5fSIvan Ilchenko {
1677d466e5fSIvan Ilchenko 	unsigned int mac_stats_nb_supported = 0;
1687d466e5fSIvan Ilchenko 	struct sfc_port *port = &sa->port;
1697d466e5fSIvan Ilchenko 	unsigned int stat_idx;
1707d466e5fSIvan Ilchenko 
1717d466e5fSIvan Ilchenko 	efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask,
1727d466e5fSIvan Ilchenko 			       sizeof(port->mac_stats_mask));
1737d466e5fSIvan Ilchenko 
1747d466e5fSIvan Ilchenko 	for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) {
1757d466e5fSIvan Ilchenko 		if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx))
1767d466e5fSIvan Ilchenko 			continue;
1777d466e5fSIvan Ilchenko 
1787d466e5fSIvan Ilchenko 		port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx;
1797d466e5fSIvan Ilchenko 		mac_stats_nb_supported++;
1807d466e5fSIvan Ilchenko 	}
1817d466e5fSIvan Ilchenko 
1827d466e5fSIvan Ilchenko 	port->mac_stats_nb_supported = mac_stats_nb_supported;
1837d466e5fSIvan Ilchenko }
1847d466e5fSIvan Ilchenko 
18503ed2119SAndrew Rybchenko int
sfc_port_start(struct sfc_adapter * sa)18603ed2119SAndrew Rybchenko sfc_port_start(struct sfc_adapter *sa)
18703ed2119SAndrew Rybchenko {
18803ed2119SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
18903ed2119SAndrew Rybchenko 	int rc;
1900e7449caSAndrew Rybchenko 	uint32_t phy_adv_cap;
1910e7449caSAndrew Rybchenko 	const uint32_t phy_pause_caps =
1920e7449caSAndrew Rybchenko 		((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM));
19303ed2119SAndrew Rybchenko 
19403ed2119SAndrew Rybchenko 	sfc_log_init(sa, "entry");
19503ed2119SAndrew Rybchenko 
19603ed2119SAndrew Rybchenko 	sfc_log_init(sa, "init filters");
19703ed2119SAndrew Rybchenko 	rc = efx_filter_init(sa->nic);
19803ed2119SAndrew Rybchenko 	if (rc != 0)
19903ed2119SAndrew Rybchenko 		goto fail_filter_init;
20003ed2119SAndrew Rybchenko 
20103ed2119SAndrew Rybchenko 	sfc_log_init(sa, "init port");
20203ed2119SAndrew Rybchenko 	rc = efx_port_init(sa->nic);
20303ed2119SAndrew Rybchenko 	if (rc != 0)
20403ed2119SAndrew Rybchenko 		goto fail_port_init;
20503ed2119SAndrew Rybchenko 
206b16cf4b2SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
207b16cf4b2SAndrew Rybchenko 	if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) {
208b16cf4b2SAndrew Rybchenko 		efx_link_mode_t link_mode;
209b16cf4b2SAndrew Rybchenko 
210b16cf4b2SAndrew Rybchenko 		link_mode =
211b16cf4b2SAndrew Rybchenko 			sfc_port_phy_caps_to_max_link_speed(port->phy_adv_cap);
212b16cf4b2SAndrew Rybchenko 		sfc_log_init(sa, "set loopback link_mode=%u type=%u", link_mode,
213b16cf4b2SAndrew Rybchenko 			     sa->eth_dev->data->dev_conf.lpbk_mode);
214b16cf4b2SAndrew Rybchenko 		rc = efx_port_loopback_set(sa->nic, link_mode,
215b16cf4b2SAndrew Rybchenko 			sa->eth_dev->data->dev_conf.lpbk_mode);
216b16cf4b2SAndrew Rybchenko 		if (rc != 0)
217b16cf4b2SAndrew Rybchenko 			goto fail_loopback_set;
218b16cf4b2SAndrew Rybchenko 	}
219b16cf4b2SAndrew Rybchenko #endif
220b16cf4b2SAndrew Rybchenko 
221cdbb29cfSAndrew Rybchenko 	sfc_log_init(sa, "set flow control to %#x autoneg=%u",
222cdbb29cfSAndrew Rybchenko 		     port->flow_ctrl, port->flow_ctrl_autoneg);
223cdbb29cfSAndrew Rybchenko 	rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl,
224cdbb29cfSAndrew Rybchenko 			       port->flow_ctrl_autoneg);
225cdbb29cfSAndrew Rybchenko 	if (rc != 0)
226cdbb29cfSAndrew Rybchenko 		goto fail_mac_fcntl_set;
227cdbb29cfSAndrew Rybchenko 
228*62082124SArtemii Morozov 	sfc_log_init(sa, "set vlan strip to %u", port->vlan_strip);
229*62082124SArtemii Morozov 	rc = efx_port_vlan_strip_set(sa->nic, port->vlan_strip);
230*62082124SArtemii Morozov 	if (rc != 0)
231*62082124SArtemii Morozov 		goto fail_mac_vlan_strip_set;
232*62082124SArtemii Morozov 
2330e7449caSAndrew Rybchenko 	/* Preserve pause capabilities set by above efx_mac_fcntl_set()  */
2340e7449caSAndrew Rybchenko 	efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_CURRENT, &phy_adv_cap);
2350e7449caSAndrew Rybchenko 	SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0);
2365efa8fc1SDenis Pryazhennikov 	phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps) |
2375efa8fc1SDenis Pryazhennikov 			port->fec_cfg;
2380b19aec1SAndrew Rybchenko 
2390e7449caSAndrew Rybchenko 	sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap);
2400e7449caSAndrew Rybchenko 	rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap);
241d23f3a89SAndrew Rybchenko 	if (rc != 0)
242d23f3a89SAndrew Rybchenko 		goto fail_phy_adv_cap_set;
243d23f3a89SAndrew Rybchenko 
24403ed2119SAndrew Rybchenko 	sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu);
24503ed2119SAndrew Rybchenko 	rc = efx_mac_pdu_set(sa->nic, port->pdu);
24603ed2119SAndrew Rybchenko 	if (rc != 0)
24703ed2119SAndrew Rybchenko 		goto fail_mac_pdu_set;
24803ed2119SAndrew Rybchenko 
24904a04943SDenis Pryazhennikov 	sfc_log_init(sa, "set include FCS=%u", port->include_fcs);
25004a04943SDenis Pryazhennikov 	rc = efx_mac_include_fcs_set(sa->nic, port->include_fcs);
25104a04943SDenis Pryazhennikov 	if (rc != 0)
25204a04943SDenis Pryazhennikov 		goto fail_include_fcs_set;
25304a04943SDenis Pryazhennikov 
254e0d5ba7eSAndrew Rybchenko 	if (!sfc_sa2shared(sa)->isolated) {
2556d13ea8eSOlivier Matz 		struct rte_ether_addr *addr = &port->default_mac_addr;
25684a9b481SIvan Malov 
25703ed2119SAndrew Rybchenko 		sfc_log_init(sa, "set MAC address");
258642088ddSIvan Malov 		rc = efx_mac_addr_set(sa->nic, addr->addr_bytes);
25903ed2119SAndrew Rybchenko 		if (rc != 0)
26003ed2119SAndrew Rybchenko 			goto fail_mac_addr_set;
26103ed2119SAndrew Rybchenko 
26203ed2119SAndrew Rybchenko 		sfc_log_init(sa, "set MAC filters");
263f3de3840SIvan Malov 		port->promisc = (sa->eth_dev->data->promiscuous != 0) ?
264f3de3840SIvan Malov 				B_TRUE : B_FALSE;
265f3de3840SIvan Malov 		port->allmulti = (sa->eth_dev->data->all_multicast != 0) ?
266f3de3840SIvan Malov 				 B_TRUE : B_FALSE;
26798608e18SIgor Romanov 		rc = sfc_set_rx_mode_unchecked(sa);
26803ed2119SAndrew Rybchenko 		if (rc != 0)
26903ed2119SAndrew Rybchenko 			goto fail_mac_filter_set;
27003ed2119SAndrew Rybchenko 
271295f647aSIvan Malov 		sfc_log_init(sa, "set multicast address list");
272295f647aSIvan Malov 		rc = efx_mac_multicast_list_set(sa->nic, port->mcast_addrs,
273295f647aSIvan Malov 						port->nb_mcast_addrs);
274295f647aSIvan Malov 		if (rc != 0)
275295f647aSIvan Malov 			goto fail_mcast_address_list_set;
27684a9b481SIvan Malov 	}
277295f647aSIvan Malov 
278e8acb329SIvan Malov 	if (port->mac_stats_reset_pending) {
279e8acb329SIvan Malov 		rc = sfc_port_reset_mac_stats(sa);
280e8acb329SIvan Malov 		if (rc != 0)
281e8acb329SIvan Malov 			sfc_err(sa, "statistics reset failed (requested "
282e8acb329SIvan Malov 				    "before the port was started)");
283e8acb329SIvan Malov 
284e8acb329SIvan Malov 		port->mac_stats_reset_pending = B_FALSE;
285e8acb329SIvan Malov 	}
286e8acb329SIvan Malov 
2877d466e5fSIvan Ilchenko 	sfc_port_fill_mac_stats_info(sa);
28873280c1eSIvan Malov 
289e56fa9c2SIvan Malov 	port->mac_stats_update_generation = 0;
290e56fa9c2SIvan Malov 
291e56fa9c2SIvan Malov 	if (port->mac_stats_update_period_ms != 0) {
292e56fa9c2SIvan Malov 		/*
293e56fa9c2SIvan Malov 		 * Update MAC stats using periodic DMA;
294e56fa9c2SIvan Malov 		 * any positive update interval different from
295e56fa9c2SIvan Malov 		 * 1000 ms can be set only on SFN8xxx provided
296e56fa9c2SIvan Malov 		 * that FW version is 6.2.1.1033 or higher
2971caab2f1SAndrew Rybchenko 		 */
2981caab2f1SAndrew Rybchenko 		sfc_log_init(sa, "request MAC stats DMA'ing");
2991caab2f1SAndrew Rybchenko 		rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
300e56fa9c2SIvan Malov 					    port->mac_stats_update_period_ms,
301e56fa9c2SIvan Malov 					    B_FALSE);
302178fc0d3SIvan Malov 		if (rc == 0) {
303178fc0d3SIvan Malov 			port->mac_stats_periodic_dma_supported = B_TRUE;
304178fc0d3SIvan Malov 		} else if (rc == EOPNOTSUPP) {
305178fc0d3SIvan Malov 			port->mac_stats_periodic_dma_supported = B_FALSE;
306178fc0d3SIvan Malov 			port->mac_stats_last_request_timestamp = 0;
307178fc0d3SIvan Malov 		} else {
3081caab2f1SAndrew Rybchenko 			goto fail_mac_stats_periodic;
309e56fa9c2SIvan Malov 		}
310178fc0d3SIvan Malov 	}
3111caab2f1SAndrew Rybchenko 
3123b257f7eSIvan Malov 	if ((port->mac_stats_update_period_ms != 0) &&
3133b257f7eSIvan Malov 	    port->mac_stats_periodic_dma_supported) {
3143b257f7eSIvan Malov 		/*
3153b257f7eSIvan Malov 		 * Request an explicit MAC stats upload immediately to
3163b257f7eSIvan Malov 		 * preclude bogus figures readback if the user decides
3173b257f7eSIvan Malov 		 * to read stats before periodic DMA is really started
3183b257f7eSIvan Malov 		 */
3193b257f7eSIvan Malov 		rc = efx_mac_stats_upload(sa->nic, &port->mac_stats_dma_mem);
3203b257f7eSIvan Malov 		if (rc != 0)
3213b257f7eSIvan Malov 			goto fail_mac_stats_upload;
3223b257f7eSIvan Malov 	}
3233b257f7eSIvan Malov 
32403ed2119SAndrew Rybchenko 	sfc_log_init(sa, "disable MAC drain");
32503ed2119SAndrew Rybchenko 	rc = efx_mac_drain(sa->nic, B_FALSE);
32603ed2119SAndrew Rybchenko 	if (rc != 0)
32703ed2119SAndrew Rybchenko 		goto fail_mac_drain;
32803ed2119SAndrew Rybchenko 
329f08a2377SAndrew Rybchenko 	/* Synchronize link status knowledge */
330f08a2377SAndrew Rybchenko 	rc = sfc_port_init_dev_link(sa);
331f08a2377SAndrew Rybchenko 	if (rc != 0)
332f08a2377SAndrew Rybchenko 		goto fail_port_init_dev_link;
333f08a2377SAndrew Rybchenko 
33403ed2119SAndrew Rybchenko 	sfc_log_init(sa, "done");
33503ed2119SAndrew Rybchenko 	return 0;
33603ed2119SAndrew Rybchenko 
337f08a2377SAndrew Rybchenko fail_port_init_dev_link:
338f08a2377SAndrew Rybchenko 	(void)efx_mac_drain(sa->nic, B_TRUE);
339f08a2377SAndrew Rybchenko 
34003ed2119SAndrew Rybchenko fail_mac_drain:
34104a04943SDenis Pryazhennikov fail_include_fcs_set:
3426636afdfSAndrew Rybchenko fail_mac_stats_upload:
3431caab2f1SAndrew Rybchenko 	(void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem,
3441caab2f1SAndrew Rybchenko 				     0, B_FALSE);
3451caab2f1SAndrew Rybchenko 
3461caab2f1SAndrew Rybchenko fail_mac_stats_periodic:
347295f647aSIvan Malov fail_mcast_address_list_set:
34803ed2119SAndrew Rybchenko fail_mac_filter_set:
34903ed2119SAndrew Rybchenko fail_mac_addr_set:
35003ed2119SAndrew Rybchenko fail_mac_pdu_set:
351d23f3a89SAndrew Rybchenko fail_phy_adv_cap_set:
352cdbb29cfSAndrew Rybchenko fail_mac_fcntl_set:
353*62082124SArtemii Morozov fail_mac_vlan_strip_set:
354b16cf4b2SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
355b16cf4b2SAndrew Rybchenko fail_loopback_set:
356b16cf4b2SAndrew Rybchenko #endif
35703ed2119SAndrew Rybchenko 	efx_port_fini(sa->nic);
35803ed2119SAndrew Rybchenko 
35903ed2119SAndrew Rybchenko fail_port_init:
36003ed2119SAndrew Rybchenko 	efx_filter_fini(sa->nic);
36103ed2119SAndrew Rybchenko 
36203ed2119SAndrew Rybchenko fail_filter_init:
36303ed2119SAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
36403ed2119SAndrew Rybchenko 	return rc;
36503ed2119SAndrew Rybchenko }
36603ed2119SAndrew Rybchenko 
36703ed2119SAndrew Rybchenko void
sfc_port_stop(struct sfc_adapter * sa)36803ed2119SAndrew Rybchenko sfc_port_stop(struct sfc_adapter *sa)
36903ed2119SAndrew Rybchenko {
37003ed2119SAndrew Rybchenko 	sfc_log_init(sa, "entry");
37103ed2119SAndrew Rybchenko 
37203ed2119SAndrew Rybchenko 	efx_mac_drain(sa->nic, B_TRUE);
3731caab2f1SAndrew Rybchenko 
3741caab2f1SAndrew Rybchenko 	(void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem,
3751caab2f1SAndrew Rybchenko 				     0, B_FALSE);
3761caab2f1SAndrew Rybchenko 
3771827b073SIvan Ilchenko 	sfc_port_update_mac_stats(sa, B_TRUE);
3781827b073SIvan Ilchenko 
37903ed2119SAndrew Rybchenko 	efx_port_fini(sa->nic);
38003ed2119SAndrew Rybchenko 	efx_filter_fini(sa->nic);
38103ed2119SAndrew Rybchenko 
38203ed2119SAndrew Rybchenko 	sfc_log_init(sa, "done");
38303ed2119SAndrew Rybchenko }
38403ed2119SAndrew Rybchenko 
38503ed2119SAndrew Rybchenko int
sfc_port_configure(struct sfc_adapter * sa)386c577a525SAndrew Rybchenko sfc_port_configure(struct sfc_adapter *sa)
38703ed2119SAndrew Rybchenko {
38803ed2119SAndrew Rybchenko 	const struct rte_eth_dev_data *dev_data = sa->eth_dev->data;
38903ed2119SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
39004a04943SDenis Pryazhennikov 	const struct rte_eth_rxmode *rxmode = &dev_data->dev_conf.rxmode;
391c577a525SAndrew Rybchenko 
392c577a525SAndrew Rybchenko 	sfc_log_init(sa, "entry");
393c577a525SAndrew Rybchenko 
394c577a525SAndrew Rybchenko 	port->pdu = EFX_MAC_PDU(dev_data->mtu);
395c577a525SAndrew Rybchenko 
39604a04943SDenis Pryazhennikov 	if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC)
39704a04943SDenis Pryazhennikov 		port->include_fcs = true;
39804a04943SDenis Pryazhennikov 	else
39904a04943SDenis Pryazhennikov 		port->include_fcs = false;
40004a04943SDenis Pryazhennikov 
401*62082124SArtemii Morozov 	if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP)
402*62082124SArtemii Morozov 		port->vlan_strip = true;
403*62082124SArtemii Morozov 	else
404*62082124SArtemii Morozov 		port->vlan_strip = false;
405*62082124SArtemii Morozov 
406c577a525SAndrew Rybchenko 	return 0;
407c577a525SAndrew Rybchenko }
408c577a525SAndrew Rybchenko 
409c577a525SAndrew Rybchenko void
sfc_port_close(struct sfc_adapter * sa)410c577a525SAndrew Rybchenko sfc_port_close(struct sfc_adapter *sa)
411c577a525SAndrew Rybchenko {
412c577a525SAndrew Rybchenko 	sfc_log_init(sa, "entry");
413c577a525SAndrew Rybchenko }
414c577a525SAndrew Rybchenko 
415c577a525SAndrew Rybchenko int
sfc_port_attach(struct sfc_adapter * sa)416c577a525SAndrew Rybchenko sfc_port_attach(struct sfc_adapter *sa)
417c577a525SAndrew Rybchenko {
418c577a525SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
419642088ddSIvan Malov 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
4206d13ea8eSOlivier Matz 	const struct rte_ether_addr *from;
421c953aea9SAndrew Rybchenko 	uint32_t mac_nstats;
422c953aea9SAndrew Rybchenko 	size_t mac_stats_size;
423e56fa9c2SIvan Malov 	long kvarg_stats_update_period_ms;
4241caab2f1SAndrew Rybchenko 	int rc;
42503ed2119SAndrew Rybchenko 
42603ed2119SAndrew Rybchenko 	sfc_log_init(sa, "entry");
42703ed2119SAndrew Rybchenko 
428c577a525SAndrew Rybchenko 	efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask);
429c577a525SAndrew Rybchenko 
43003ed2119SAndrew Rybchenko 	/* Enable flow control by default */
43103ed2119SAndrew Rybchenko 	port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
43203ed2119SAndrew Rybchenko 	port->flow_ctrl_autoneg = B_TRUE;
43303ed2119SAndrew Rybchenko 
434642088ddSIvan Malov 	RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from));
4356d13ea8eSOlivier Matz 	from = (const struct rte_ether_addr *)(encp->enc_mac_addr);
436538da7a1SOlivier Matz 	rte_ether_addr_copy(from, &port->default_mac_addr);
437642088ddSIvan Malov 
438295f647aSIvan Malov 	port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX;
439295f647aSIvan Malov 	port->nb_mcast_addrs = 0;
440295f647aSIvan Malov 	port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf",
441295f647aSIvan Malov 					      port->max_mcast_addrs,
442295f647aSIvan Malov 					      EFX_MAC_ADDR_LEN, 0,
443295f647aSIvan Malov 					      sa->socket_id);
444295f647aSIvan Malov 	if (port->mcast_addrs == NULL) {
445295f647aSIvan Malov 		rc = ENOMEM;
446295f647aSIvan Malov 		goto fail_mcast_addr_list_buf_alloc;
447295f647aSIvan Malov 	}
448295f647aSIvan Malov 
4491caab2f1SAndrew Rybchenko 	rc = ENOMEM;
4501caab2f1SAndrew Rybchenko 	port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS,
4511caab2f1SAndrew Rybchenko 						sizeof(uint64_t), 0,
4521caab2f1SAndrew Rybchenko 						sa->socket_id);
4531caab2f1SAndrew Rybchenko 	if (port->mac_stats_buf == NULL)
4541caab2f1SAndrew Rybchenko 		goto fail_mac_stats_buf_alloc;
4551caab2f1SAndrew Rybchenko 
456c953aea9SAndrew Rybchenko 	mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats;
457c953aea9SAndrew Rybchenko 	mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE);
4583037e6cfSViacheslav Galaktionov 	rc = sfc_dma_alloc(sa, "mac_stats", 0, EFX_NIC_DMA_ADDR_MAC_STATS_BUF,
4593037e6cfSViacheslav Galaktionov 			   mac_stats_size,
4601caab2f1SAndrew Rybchenko 			   sa->socket_id, &port->mac_stats_dma_mem);
4611caab2f1SAndrew Rybchenko 	if (rc != 0)
4621caab2f1SAndrew Rybchenko 		goto fail_mac_stats_dma_alloc;
4631caab2f1SAndrew Rybchenko 
464e8acb329SIvan Malov 	port->mac_stats_reset_pending = B_FALSE;
465e8acb329SIvan Malov 
466e56fa9c2SIvan Malov 	kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF;
467e56fa9c2SIvan Malov 
468e56fa9c2SIvan Malov 	rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS,
469e56fa9c2SIvan Malov 				sfc_kvarg_long_handler,
470e56fa9c2SIvan Malov 				&kvarg_stats_update_period_ms);
471e56fa9c2SIvan Malov 	if ((rc == 0) &&
472e56fa9c2SIvan Malov 	    ((kvarg_stats_update_period_ms < 0) ||
473e56fa9c2SIvan Malov 	     (kvarg_stats_update_period_ms > UINT16_MAX))) {
474e56fa9c2SIvan Malov 		sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' "
475e56fa9c2SIvan Malov 			    "was set (%ld);", kvarg_stats_update_period_ms);
476e56fa9c2SIvan Malov 		sfc_err(sa, "it must not be less than 0 "
477e56fa9c2SIvan Malov 			    "or greater than %" PRIu16, UINT16_MAX);
478e56fa9c2SIvan Malov 		rc = EINVAL;
479e56fa9c2SIvan Malov 		goto fail_kvarg_stats_update_period_ms;
480e56fa9c2SIvan Malov 	} else if (rc != 0) {
481e56fa9c2SIvan Malov 		goto fail_kvarg_stats_update_period_ms;
482e56fa9c2SIvan Malov 	}
483e56fa9c2SIvan Malov 
484e56fa9c2SIvan Malov 	port->mac_stats_update_period_ms = kvarg_stats_update_period_ms;
485e56fa9c2SIvan Malov 
4865efa8fc1SDenis Pryazhennikov 	/*
4875efa8fc1SDenis Pryazhennikov 	 * Set default FEC mode.
4885efa8fc1SDenis Pryazhennikov 	 * I.e. advertise everything supported (*_FEC=1), but do not request
4895efa8fc1SDenis Pryazhennikov 	 * anything explicitly (*_FEC_REQUESTED=0).
4905efa8fc1SDenis Pryazhennikov 	 */
4915efa8fc1SDenis Pryazhennikov 	port->fec_cfg = port->phy_adv_cap_mask &
4925efa8fc1SDenis Pryazhennikov 		(EFX_PHY_CAP_FEC_BIT(BASER_FEC) |
4935efa8fc1SDenis Pryazhennikov 		 EFX_PHY_CAP_FEC_BIT(RS_FEC) |
4945efa8fc1SDenis Pryazhennikov 		 EFX_PHY_CAP_FEC_BIT(25G_BASER_FEC));
4955efa8fc1SDenis Pryazhennikov 	port->fec_auto = true;
4965efa8fc1SDenis Pryazhennikov 
49703ed2119SAndrew Rybchenko 	sfc_log_init(sa, "done");
49803ed2119SAndrew Rybchenko 	return 0;
4991caab2f1SAndrew Rybchenko 
500e56fa9c2SIvan Malov fail_kvarg_stats_update_period_ms:
5011883f4b8SAndrew Rybchenko 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
5021883f4b8SAndrew Rybchenko 
5031caab2f1SAndrew Rybchenko fail_mac_stats_dma_alloc:
5041caab2f1SAndrew Rybchenko 	rte_free(port->mac_stats_buf);
5058ae36890SAndrew Rybchenko 
5061caab2f1SAndrew Rybchenko fail_mac_stats_buf_alloc:
5078ae36890SAndrew Rybchenko 	rte_free(port->mcast_addrs);
5088ae36890SAndrew Rybchenko 
509295f647aSIvan Malov fail_mcast_addr_list_buf_alloc:
5101caab2f1SAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
5111caab2f1SAndrew Rybchenko 	return rc;
51203ed2119SAndrew Rybchenko }
51303ed2119SAndrew Rybchenko 
51403ed2119SAndrew Rybchenko void
sfc_port_detach(struct sfc_adapter * sa)515c577a525SAndrew Rybchenko sfc_port_detach(struct sfc_adapter *sa)
51603ed2119SAndrew Rybchenko {
5171caab2f1SAndrew Rybchenko 	struct sfc_port *port = &sa->port;
5181caab2f1SAndrew Rybchenko 
51903ed2119SAndrew Rybchenko 	sfc_log_init(sa, "entry");
52003ed2119SAndrew Rybchenko 
5211caab2f1SAndrew Rybchenko 	sfc_dma_free(sa, &port->mac_stats_dma_mem);
5221caab2f1SAndrew Rybchenko 	rte_free(port->mac_stats_buf);
5231caab2f1SAndrew Rybchenko 
5248ae36890SAndrew Rybchenko 	rte_free(port->mcast_addrs);
5258ae36890SAndrew Rybchenko 
52603ed2119SAndrew Rybchenko 	sfc_log_init(sa, "done");
52703ed2119SAndrew Rybchenko }
528886f8d8aSArtem Andreev 
52998608e18SIgor Romanov static boolean_t
sfc_get_requested_all_ucast(struct sfc_port * port)53098608e18SIgor Romanov sfc_get_requested_all_ucast(struct sfc_port *port)
53198608e18SIgor Romanov {
53298608e18SIgor Romanov 	return port->promisc;
53398608e18SIgor Romanov }
53498608e18SIgor Romanov 
53598608e18SIgor Romanov static boolean_t
sfc_get_requested_all_mcast(struct sfc_port * port)53698608e18SIgor Romanov sfc_get_requested_all_mcast(struct sfc_port *port)
53798608e18SIgor Romanov {
53898608e18SIgor Romanov 	return port->promisc || port->allmulti;
53998608e18SIgor Romanov }
54098608e18SIgor Romanov 
54198608e18SIgor Romanov int
sfc_set_rx_mode_unchecked(struct sfc_adapter * sa)54298608e18SIgor Romanov sfc_set_rx_mode_unchecked(struct sfc_adapter *sa)
54398608e18SIgor Romanov {
54498608e18SIgor Romanov 	struct sfc_port *port = &sa->port;
54598608e18SIgor Romanov 	boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
54698608e18SIgor Romanov 	boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
54798608e18SIgor Romanov 	int rc;
54898608e18SIgor Romanov 
54998608e18SIgor Romanov 	rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE,
55098608e18SIgor Romanov 				requested_all_mcast, B_TRUE);
55198608e18SIgor Romanov 	if (rc != 0)
55298608e18SIgor Romanov 		return rc;
55398608e18SIgor Romanov 
55498608e18SIgor Romanov 	return 0;
55598608e18SIgor Romanov }
55698608e18SIgor Romanov 
557f3de3840SIvan Malov int
sfc_set_rx_mode(struct sfc_adapter * sa)558f3de3840SIvan Malov sfc_set_rx_mode(struct sfc_adapter *sa)
559f3de3840SIvan Malov {
560f3de3840SIvan Malov 	struct sfc_port *port = &sa->port;
56198608e18SIgor Romanov 	boolean_t old_all_ucast;
56298608e18SIgor Romanov 	boolean_t old_all_mcast;
56398608e18SIgor Romanov 	boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port);
56498608e18SIgor Romanov 	boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port);
56598608e18SIgor Romanov 	boolean_t actual_all_ucast;
56698608e18SIgor Romanov 	boolean_t actual_all_mcast;
567f3de3840SIvan Malov 	int rc;
568f3de3840SIvan Malov 
56998608e18SIgor Romanov 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast,
57098608e18SIgor Romanov 					   &old_all_mcast);
571f3de3840SIvan Malov 
57298608e18SIgor Romanov 	rc = sfc_set_rx_mode_unchecked(sa);
57398608e18SIgor Romanov 	if (rc != 0)
574f3de3840SIvan Malov 		return rc;
57598608e18SIgor Romanov 
57698608e18SIgor Romanov 	efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast,
57798608e18SIgor Romanov 					   &actual_all_mcast);
57898608e18SIgor Romanov 
57998608e18SIgor Romanov 	if (actual_all_ucast != requested_all_ucast ||
58098608e18SIgor Romanov 	    actual_all_mcast != requested_all_mcast) {
58198608e18SIgor Romanov 		/*
58298608e18SIgor Romanov 		 * MAC filter set succeeded but not all requested modes
58398608e18SIgor Romanov 		 * were applied. The rollback is necessary to bring back the
58498608e18SIgor Romanov 		 * consistent old state.
58598608e18SIgor Romanov 		 */
58698608e18SIgor Romanov 		(void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE,
58798608e18SIgor Romanov 					 old_all_mcast, B_TRUE);
58898608e18SIgor Romanov 
58998608e18SIgor Romanov 		return EPERM;
59098608e18SIgor Romanov 	}
59198608e18SIgor Romanov 
59298608e18SIgor Romanov 	return 0;
593f3de3840SIvan Malov }
594f3de3840SIvan Malov 
595886f8d8aSArtem Andreev void
sfc_port_link_mode_to_info(efx_link_mode_t link_mode,struct rte_eth_link * link_info)596886f8d8aSArtem Andreev sfc_port_link_mode_to_info(efx_link_mode_t link_mode,
597886f8d8aSArtem Andreev 			   struct rte_eth_link *link_info)
598886f8d8aSArtem Andreev {
599886f8d8aSArtem Andreev 	SFC_ASSERT(link_mode < EFX_LINK_NMODES);
600886f8d8aSArtem Andreev 
601886f8d8aSArtem Andreev 	memset(link_info, 0, sizeof(*link_info));
602886f8d8aSArtem Andreev 	if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN))
603295968d1SFerruh Yigit 		link_info->link_status = RTE_ETH_LINK_DOWN;
604886f8d8aSArtem Andreev 	else
605295968d1SFerruh Yigit 		link_info->link_status = RTE_ETH_LINK_UP;
606886f8d8aSArtem Andreev 
607886f8d8aSArtem Andreev 	switch (link_mode) {
608886f8d8aSArtem Andreev 	case EFX_LINK_10HDX:
609295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_10M;
610295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
611886f8d8aSArtem Andreev 		break;
612886f8d8aSArtem Andreev 	case EFX_LINK_10FDX:
613295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_10M;
614295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
615886f8d8aSArtem Andreev 		break;
616886f8d8aSArtem Andreev 	case EFX_LINK_100HDX:
617295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_100M;
618295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
619886f8d8aSArtem Andreev 		break;
620886f8d8aSArtem Andreev 	case EFX_LINK_100FDX:
621295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_100M;
622295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
623886f8d8aSArtem Andreev 		break;
624886f8d8aSArtem Andreev 	case EFX_LINK_1000HDX:
625295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_1G;
626295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
627886f8d8aSArtem Andreev 		break;
628886f8d8aSArtem Andreev 	case EFX_LINK_1000FDX:
629295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_1G;
630295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
631886f8d8aSArtem Andreev 		break;
632886f8d8aSArtem Andreev 	case EFX_LINK_10000FDX:
633295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_10G;
634295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
635886f8d8aSArtem Andreev 		break;
636f82e33afSAndrew Rybchenko 	case EFX_LINK_25000FDX:
637295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_25G;
638295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
639f82e33afSAndrew Rybchenko 		break;
640886f8d8aSArtem Andreev 	case EFX_LINK_40000FDX:
641295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_40G;
642295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
643886f8d8aSArtem Andreev 		break;
644f82e33afSAndrew Rybchenko 	case EFX_LINK_50000FDX:
645295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_50G;
646295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
647f82e33afSAndrew Rybchenko 		break;
648f82e33afSAndrew Rybchenko 	case EFX_LINK_100000FDX:
649295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_100G;
650295968d1SFerruh Yigit 		link_info->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
651f82e33afSAndrew Rybchenko 		break;
652886f8d8aSArtem Andreev 	default:
653886f8d8aSArtem Andreev 		SFC_ASSERT(B_FALSE);
654886f8d8aSArtem Andreev 		/* FALLTHROUGH */
655886f8d8aSArtem Andreev 	case EFX_LINK_UNKNOWN:
656886f8d8aSArtem Andreev 	case EFX_LINK_DOWN:
657295968d1SFerruh Yigit 		link_info->link_speed  = RTE_ETH_SPEED_NUM_NONE;
658886f8d8aSArtem Andreev 		link_info->link_duplex = 0;
659886f8d8aSArtem Andreev 		break;
660886f8d8aSArtem Andreev 	}
661886f8d8aSArtem Andreev 
662295968d1SFerruh Yigit 	link_info->link_autoneg = RTE_ETH_LINK_AUTONEG;
663886f8d8aSArtem Andreev }
66421ca2629SIvan Ilchenko 
66521ca2629SIvan Ilchenko int
sfc_port_get_mac_stats(struct sfc_adapter * sa,struct rte_eth_xstat * xstats,unsigned int xstats_count,unsigned int * nb_written)66621ca2629SIvan Ilchenko sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats,
66721ca2629SIvan Ilchenko 		       unsigned int xstats_count, unsigned int *nb_written)
66821ca2629SIvan Ilchenko {
66921ca2629SIvan Ilchenko 	struct sfc_port *port = &sa->port;
67021ca2629SIvan Ilchenko 	uint64_t *mac_stats;
67121ca2629SIvan Ilchenko 	unsigned int i;
67221ca2629SIvan Ilchenko 	int nstats = 0;
67321ca2629SIvan Ilchenko 	int ret;
67421ca2629SIvan Ilchenko 
67521ca2629SIvan Ilchenko 	sfc_adapter_lock(sa);
67621ca2629SIvan Ilchenko 
67721ca2629SIvan Ilchenko 	ret = sfc_port_update_mac_stats(sa, B_FALSE);
67821ca2629SIvan Ilchenko 	if (ret != 0) {
67921ca2629SIvan Ilchenko 		SFC_ASSERT(ret > 0);
68021ca2629SIvan Ilchenko 		ret = -ret;
68121ca2629SIvan Ilchenko 		goto unlock;
68221ca2629SIvan Ilchenko 	}
68321ca2629SIvan Ilchenko 
68421ca2629SIvan Ilchenko 	mac_stats = port->mac_stats_buf;
68521ca2629SIvan Ilchenko 
68621ca2629SIvan Ilchenko 	for (i = 0; i < EFX_MAC_NSTATS; ++i) {
68721ca2629SIvan Ilchenko 		if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) {
68821ca2629SIvan Ilchenko 			if (nstats < (int)xstats_count) {
68921ca2629SIvan Ilchenko 				xstats[nstats].id = nstats;
69021ca2629SIvan Ilchenko 				xstats[nstats].value = mac_stats[i];
69121ca2629SIvan Ilchenko 				(*nb_written)++;
69221ca2629SIvan Ilchenko 			}
69321ca2629SIvan Ilchenko 			nstats++;
69421ca2629SIvan Ilchenko 		}
69521ca2629SIvan Ilchenko 	}
69621ca2629SIvan Ilchenko 	ret = nstats;
69721ca2629SIvan Ilchenko 
69821ca2629SIvan Ilchenko unlock:
69921ca2629SIvan Ilchenko 	sfc_adapter_unlock(sa);
70021ca2629SIvan Ilchenko 
70121ca2629SIvan Ilchenko 	return ret;
70221ca2629SIvan Ilchenko }
70321ca2629SIvan Ilchenko 
70421ca2629SIvan Ilchenko int
sfc_port_get_mac_stats_by_id(struct sfc_adapter * sa,const uint64_t * ids,uint64_t * values,unsigned int n)70521ca2629SIvan Ilchenko sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids,
70621ca2629SIvan Ilchenko 			     uint64_t *values, unsigned int n)
70721ca2629SIvan Ilchenko {
70821ca2629SIvan Ilchenko 	struct sfc_port *port = &sa->port;
70921ca2629SIvan Ilchenko 	uint64_t *mac_stats;
71021ca2629SIvan Ilchenko 	unsigned int i;
71121ca2629SIvan Ilchenko 	int ret;
71221ca2629SIvan Ilchenko 	int rc;
71321ca2629SIvan Ilchenko 
71421ca2629SIvan Ilchenko 	sfc_adapter_lock(sa);
71521ca2629SIvan Ilchenko 
71621ca2629SIvan Ilchenko 	rc = sfc_port_update_mac_stats(sa, B_FALSE);
71721ca2629SIvan Ilchenko 	if (rc != 0) {
71821ca2629SIvan Ilchenko 		SFC_ASSERT(rc > 0);
71921ca2629SIvan Ilchenko 		ret = -rc;
72021ca2629SIvan Ilchenko 		goto unlock;
72121ca2629SIvan Ilchenko 	}
72221ca2629SIvan Ilchenko 
72321ca2629SIvan Ilchenko 	mac_stats = port->mac_stats_buf;
72421ca2629SIvan Ilchenko 
72521ca2629SIvan Ilchenko 	SFC_ASSERT(port->mac_stats_nb_supported <=
72621ca2629SIvan Ilchenko 		   RTE_DIM(port->mac_stats_by_id));
72721ca2629SIvan Ilchenko 
72821ca2629SIvan Ilchenko 	for (i = 0; i < n; i++) {
729fdd7719eSIvan Ilchenko 		if (ids[i] < port->mac_stats_nb_supported)
73021ca2629SIvan Ilchenko 			values[i] = mac_stats[port->mac_stats_by_id[ids[i]]];
73121ca2629SIvan Ilchenko 	}
73221ca2629SIvan Ilchenko 
733fdd7719eSIvan Ilchenko 	ret = 0;
73421ca2629SIvan Ilchenko 
73521ca2629SIvan Ilchenko unlock:
73621ca2629SIvan Ilchenko 	sfc_adapter_unlock(sa);
73721ca2629SIvan Ilchenko 
73821ca2629SIvan Ilchenko 	return ret;
73921ca2629SIvan Ilchenko }
740