xref: /dpdk/drivers/net/sfc/sfc.c (revision bc712f1c86fc9c2bb5bb41a80e12f34e224f4c6d)
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.
5ba641f20SAndrew Rybchenko  *
6ba641f20SAndrew Rybchenko  * This software was jointly developed between OKTET Labs (under contract
7ba641f20SAndrew Rybchenko  * for Solarflare) and Solarflare Communications, Inc.
8ba641f20SAndrew Rybchenko  */
9ba641f20SAndrew Rybchenko 
10ba641f20SAndrew Rybchenko /* sysconf() */
11ba641f20SAndrew Rybchenko #include <unistd.h>
12ba641f20SAndrew Rybchenko 
13ba641f20SAndrew Rybchenko #include <rte_errno.h>
14e77f9f19SAndrew Rybchenko #include <rte_alarm.h>
15ba641f20SAndrew Rybchenko 
16ba641f20SAndrew Rybchenko #include "efx.h"
17ba641f20SAndrew Rybchenko 
18ba641f20SAndrew Rybchenko #include "sfc.h"
191b0236e2SAndrew Rybchenko #include "sfc_debug.h"
20ba641f20SAndrew Rybchenko #include "sfc_log.h"
2158294ee6SAndrew Rybchenko #include "sfc_ev.h"
22a8e64c6bSAndrew Rybchenko #include "sfc_rx.h"
23983ce116SIgor Romanov #include "sfc_mae_counter.h"
24a8ad8cf8SIvan Malov #include "sfc_tx.h"
259e7fc8b8SRoman Zhukov #include "sfc_kvargs.h"
265a1ae82dSAndrew Rybchenko #include "sfc_tweak.h"
27fdd7719eSIvan Ilchenko #include "sfc_sw_stats.h"
2826706314SViacheslav Galaktionov #include "sfc_switch.h"
293037e6cfSViacheslav Galaktionov #include "sfc_nic_dma.h"
30ba641f20SAndrew Rybchenko 
3152e80b1bSIgor Romanov bool
3252e80b1bSIgor Romanov sfc_repr_supported(const struct sfc_adapter *sa)
3352e80b1bSIgor Romanov {
3452e80b1bSIgor Romanov 	if (!sa->switchdev)
3552e80b1bSIgor Romanov 		return false;
3652e80b1bSIgor Romanov 
3752e80b1bSIgor Romanov 	/*
3852e80b1bSIgor Romanov 	 * Representor proxy should use service lcore on PF's socket
3952e80b1bSIgor Romanov 	 * (sa->socket_id) to be efficient. But the proxy will fall back
4052e80b1bSIgor Romanov 	 * to any socket if it is not possible to get the service core
4152e80b1bSIgor Romanov 	 * on the same socket. Check that at least service core on any
4252e80b1bSIgor Romanov 	 * socket is available.
4352e80b1bSIgor Romanov 	 */
4452e80b1bSIgor Romanov 	if (sfc_get_service_lcore(SOCKET_ID_ANY) == RTE_MAX_LCORE)
4552e80b1bSIgor Romanov 		return false;
4652e80b1bSIgor Romanov 
4752e80b1bSIgor Romanov 	return true;
4852e80b1bSIgor Romanov }
4952e80b1bSIgor Romanov 
50689a5674SIgor Romanov bool
51689a5674SIgor Romanov sfc_repr_available(const struct sfc_adapter_shared *sas)
52689a5674SIgor Romanov {
53689a5674SIgor Romanov 	return sas->nb_repr_rxq > 0 && sas->nb_repr_txq > 0;
54689a5674SIgor Romanov }
55689a5674SIgor Romanov 
56ba641f20SAndrew Rybchenko int
573037e6cfSViacheslav Galaktionov sfc_dma_alloc(struct sfc_adapter *sa, const char *name, uint16_t id,
583037e6cfSViacheslav Galaktionov 	      efx_nic_dma_addr_type_t addr_type, size_t len, int socket_id,
593037e6cfSViacheslav Galaktionov 	      efsys_mem_t *esmp)
60ba641f20SAndrew Rybchenko {
61ba641f20SAndrew Rybchenko 	const struct rte_memzone *mz;
623037e6cfSViacheslav Galaktionov 	int rc;
63ba641f20SAndrew Rybchenko 
646b9a30d9SFerruh Yigit 	sfc_log_init(sa, "name=%s id=%u len=%zu socket_id=%d",
65ba641f20SAndrew Rybchenko 		     name, id, len, socket_id);
66ba641f20SAndrew Rybchenko 
67ba641f20SAndrew Rybchenko 	mz = rte_eth_dma_zone_reserve(sa->eth_dev, name, id, len,
68ba641f20SAndrew Rybchenko 				      sysconf(_SC_PAGESIZE), socket_id);
69ba641f20SAndrew Rybchenko 	if (mz == NULL) {
70ba641f20SAndrew Rybchenko 		sfc_err(sa, "cannot reserve DMA zone for %s:%u %#x@%d: %s",
71ba641f20SAndrew Rybchenko 			name, (unsigned int)id, (unsigned int)len, socket_id,
72ba641f20SAndrew Rybchenko 			rte_strerror(rte_errno));
73ba641f20SAndrew Rybchenko 		return ENOMEM;
74ba641f20SAndrew Rybchenko 	}
753037e6cfSViacheslav Galaktionov 	if (mz->iova == RTE_BAD_IOVA) {
76ba641f20SAndrew Rybchenko 		(void)rte_memzone_free(mz);
77ba641f20SAndrew Rybchenko 		return EFAULT;
78ba641f20SAndrew Rybchenko 	}
79ba641f20SAndrew Rybchenko 
803037e6cfSViacheslav Galaktionov 	rc = sfc_nic_dma_mz_map(sa, mz, addr_type, &esmp->esm_addr);
813037e6cfSViacheslav Galaktionov 	if (rc != 0) {
823037e6cfSViacheslav Galaktionov 		(void)rte_memzone_free(mz);
833037e6cfSViacheslav Galaktionov 		return rc;
843037e6cfSViacheslav Galaktionov 	}
853037e6cfSViacheslav Galaktionov 
86ba641f20SAndrew Rybchenko 	esmp->esm_mz = mz;
87ba641f20SAndrew Rybchenko 	esmp->esm_base = mz->addr;
88ba641f20SAndrew Rybchenko 
892d98a5a6SAndrew Rybchenko 	sfc_info(sa,
902d98a5a6SAndrew Rybchenko 		 "DMA name=%s id=%u len=%lu socket_id=%d => virt=%p iova=%lx",
912d98a5a6SAndrew Rybchenko 		 name, id, len, socket_id, esmp->esm_base,
922d98a5a6SAndrew Rybchenko 		 (unsigned long)esmp->esm_addr);
932d98a5a6SAndrew Rybchenko 
94ba641f20SAndrew Rybchenko 	return 0;
95ba641f20SAndrew Rybchenko }
96ba641f20SAndrew Rybchenko 
97ba641f20SAndrew Rybchenko void
98ba641f20SAndrew Rybchenko sfc_dma_free(const struct sfc_adapter *sa, efsys_mem_t *esmp)
99ba641f20SAndrew Rybchenko {
100ba641f20SAndrew Rybchenko 	int rc;
101ba641f20SAndrew Rybchenko 
102ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "name=%s", esmp->esm_mz->name);
103ba641f20SAndrew Rybchenko 
104ba641f20SAndrew Rybchenko 	rc = rte_memzone_free(esmp->esm_mz);
105ba641f20SAndrew Rybchenko 	if (rc != 0)
106ba641f20SAndrew Rybchenko 		sfc_err(sa, "rte_memzone_free(() failed: %d", rc);
107ba641f20SAndrew Rybchenko 
108ba641f20SAndrew Rybchenko 	memset(esmp, 0, sizeof(*esmp));
109ba641f20SAndrew Rybchenko }
110ba641f20SAndrew Rybchenko 
111d23f3a89SAndrew Rybchenko static uint32_t
112d23f3a89SAndrew Rybchenko sfc_phy_cap_from_link_speeds(uint32_t speeds)
113d23f3a89SAndrew Rybchenko {
114d23f3a89SAndrew Rybchenko 	uint32_t phy_caps = 0;
115d23f3a89SAndrew Rybchenko 
116295968d1SFerruh Yigit 	if (~speeds & RTE_ETH_LINK_SPEED_FIXED) {
117d23f3a89SAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_AN);
118d23f3a89SAndrew Rybchenko 		/*
119d23f3a89SAndrew Rybchenko 		 * If no speeds are specified in the mask, any supported
120d23f3a89SAndrew Rybchenko 		 * may be negotiated
121d23f3a89SAndrew Rybchenko 		 */
122295968d1SFerruh Yigit 		if (speeds == RTE_ETH_LINK_SPEED_AUTONEG)
123d23f3a89SAndrew Rybchenko 			phy_caps |=
124d23f3a89SAndrew Rybchenko 				(1 << EFX_PHY_CAP_1000FDX) |
125d23f3a89SAndrew Rybchenko 				(1 << EFX_PHY_CAP_10000FDX) |
126f82e33afSAndrew Rybchenko 				(1 << EFX_PHY_CAP_25000FDX) |
127f82e33afSAndrew Rybchenko 				(1 << EFX_PHY_CAP_40000FDX) |
128f82e33afSAndrew Rybchenko 				(1 << EFX_PHY_CAP_50000FDX) |
129f82e33afSAndrew Rybchenko 				(1 << EFX_PHY_CAP_100000FDX);
130d23f3a89SAndrew Rybchenko 	}
131295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_1G)
132d23f3a89SAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_1000FDX);
133295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_10G)
134d23f3a89SAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_10000FDX);
135295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_25G)
136f82e33afSAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_25000FDX);
137295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_40G)
138d23f3a89SAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_40000FDX);
139295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_50G)
140f82e33afSAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_50000FDX);
141295968d1SFerruh Yigit 	if (speeds & RTE_ETH_LINK_SPEED_100G)
142f82e33afSAndrew Rybchenko 		phy_caps |= (1 << EFX_PHY_CAP_100000FDX);
143d23f3a89SAndrew Rybchenko 
144d23f3a89SAndrew Rybchenko 	return phy_caps;
145d23f3a89SAndrew Rybchenko }
146d23f3a89SAndrew Rybchenko 
147c7cb2d7aSAndrew Rybchenko /*
148c7cb2d7aSAndrew Rybchenko  * Check requested device level configuration.
149c7cb2d7aSAndrew Rybchenko  * Receive and transmit configuration is checked in corresponding
150c7cb2d7aSAndrew Rybchenko  * modules.
151c7cb2d7aSAndrew Rybchenko  */
152c7cb2d7aSAndrew Rybchenko static int
153c7cb2d7aSAndrew Rybchenko sfc_check_conf(struct sfc_adapter *sa)
154c7cb2d7aSAndrew Rybchenko {
155c7cb2d7aSAndrew Rybchenko 	const struct rte_eth_conf *conf = &sa->eth_dev->data->dev_conf;
156c7cb2d7aSAndrew Rybchenko 	int rc = 0;
157c7cb2d7aSAndrew Rybchenko 
158d23f3a89SAndrew Rybchenko 	sa->port.phy_adv_cap =
159d23f3a89SAndrew Rybchenko 		sfc_phy_cap_from_link_speeds(conf->link_speeds) &
160d23f3a89SAndrew Rybchenko 		sa->port.phy_adv_cap_mask;
161d23f3a89SAndrew Rybchenko 	if ((sa->port.phy_adv_cap & ~(1 << EFX_PHY_CAP_AN)) == 0) {
162d23f3a89SAndrew Rybchenko 		sfc_err(sa, "No link speeds from mask %#x are supported",
163d23f3a89SAndrew Rybchenko 			conf->link_speeds);
164c7cb2d7aSAndrew Rybchenko 		rc = EINVAL;
165c7cb2d7aSAndrew Rybchenko 	}
166c7cb2d7aSAndrew Rybchenko 
167b16cf4b2SAndrew Rybchenko #if !EFSYS_OPT_LOOPBACK
168c7cb2d7aSAndrew Rybchenko 	if (conf->lpbk_mode != 0) {
169c7cb2d7aSAndrew Rybchenko 		sfc_err(sa, "Loopback not supported");
170c7cb2d7aSAndrew Rybchenko 		rc = EINVAL;
171c7cb2d7aSAndrew Rybchenko 	}
172b16cf4b2SAndrew Rybchenko #endif
173c7cb2d7aSAndrew Rybchenko 
174c7cb2d7aSAndrew Rybchenko 	if (conf->dcb_capability_en != 0) {
175c7cb2d7aSAndrew Rybchenko 		sfc_err(sa, "Priority-based flow control not supported");
176c7cb2d7aSAndrew Rybchenko 		rc = EINVAL;
177c7cb2d7aSAndrew Rybchenko 	}
178c7cb2d7aSAndrew Rybchenko 
1793b809c27SAndrew Rybchenko 	if ((conf->intr_conf.lsc != 0) &&
1803b809c27SAndrew Rybchenko 	    (sa->intr.type != EFX_INTR_LINE) &&
1813b809c27SAndrew Rybchenko 	    (sa->intr.type != EFX_INTR_MESSAGE)) {
182c7cb2d7aSAndrew Rybchenko 		sfc_err(sa, "Link status change interrupt not supported");
183c7cb2d7aSAndrew Rybchenko 		rc = EINVAL;
184c7cb2d7aSAndrew Rybchenko 	}
185c7cb2d7aSAndrew Rybchenko 
1864279b54eSGeorgiy Levashov 	if (conf->intr_conf.rxq != 0 &&
1874279b54eSGeorgiy Levashov 	    (sa->priv.dp_rx->features & SFC_DP_RX_FEAT_INTR) == 0) {
188c7cb2d7aSAndrew Rybchenko 		sfc_err(sa, "Receive queue interrupt not supported");
189c7cb2d7aSAndrew Rybchenko 		rc = EINVAL;
190c7cb2d7aSAndrew Rybchenko 	}
191c7cb2d7aSAndrew Rybchenko 
192c7cb2d7aSAndrew Rybchenko 	return rc;
193c7cb2d7aSAndrew Rybchenko }
194c7cb2d7aSAndrew Rybchenko 
19591831d40SAndrew Rybchenko /*
19691831d40SAndrew Rybchenko  * Find out maximum number of receive and transmit queues which could be
19791831d40SAndrew Rybchenko  * advertised.
19891831d40SAndrew Rybchenko  *
19991831d40SAndrew Rybchenko  * NIC is kept initialized on success to allow other modules acquire
20091831d40SAndrew Rybchenko  * defaults and capabilities.
20191831d40SAndrew Rybchenko  */
20291831d40SAndrew Rybchenko static int
20391831d40SAndrew Rybchenko sfc_estimate_resource_limits(struct sfc_adapter *sa)
20491831d40SAndrew Rybchenko {
20591831d40SAndrew Rybchenko 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
206983ce116SIgor Romanov 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
20791831d40SAndrew Rybchenko 	efx_drv_limits_t limits;
20891831d40SAndrew Rybchenko 	int rc;
20991831d40SAndrew Rybchenko 	uint32_t evq_allocated;
21091831d40SAndrew Rybchenko 	uint32_t rxq_allocated;
21191831d40SAndrew Rybchenko 	uint32_t txq_allocated;
21291831d40SAndrew Rybchenko 
21391831d40SAndrew Rybchenko 	memset(&limits, 0, sizeof(limits));
21491831d40SAndrew Rybchenko 
21591831d40SAndrew Rybchenko 	/* Request at least one Rx and Tx queue */
21691831d40SAndrew Rybchenko 	limits.edl_min_rxq_count = 1;
21791831d40SAndrew Rybchenko 	limits.edl_min_txq_count = 1;
21891831d40SAndrew Rybchenko 	/* Management event queue plus event queue for each Tx and Rx queue */
21991831d40SAndrew Rybchenko 	limits.edl_min_evq_count =
22091831d40SAndrew Rybchenko 		1 + limits.edl_min_rxq_count + limits.edl_min_txq_count;
22191831d40SAndrew Rybchenko 
22291831d40SAndrew Rybchenko 	/* Divide by number of functions to guarantee that all functions
22391831d40SAndrew Rybchenko 	 * will get promised resources
22491831d40SAndrew Rybchenko 	 */
22591831d40SAndrew Rybchenko 	/* FIXME Divide by number of functions (not 2) below */
22691831d40SAndrew Rybchenko 	limits.edl_max_evq_count = encp->enc_evq_limit / 2;
22791831d40SAndrew Rybchenko 	SFC_ASSERT(limits.edl_max_evq_count >= limits.edl_min_rxq_count);
22891831d40SAndrew Rybchenko 
22991831d40SAndrew Rybchenko 	/* Split equally between receive and transmit */
23091831d40SAndrew Rybchenko 	limits.edl_max_rxq_count =
23191831d40SAndrew Rybchenko 		MIN(encp->enc_rxq_limit, (limits.edl_max_evq_count - 1) / 2);
23291831d40SAndrew Rybchenko 	SFC_ASSERT(limits.edl_max_rxq_count >= limits.edl_min_rxq_count);
23391831d40SAndrew Rybchenko 
23491831d40SAndrew Rybchenko 	limits.edl_max_txq_count =
23591831d40SAndrew Rybchenko 		MIN(encp->enc_txq_limit,
23691831d40SAndrew Rybchenko 		    limits.edl_max_evq_count - 1 - limits.edl_max_rxq_count);
2371f014258SIvan Malov 
2384f936666SIvan Malov 	if (sa->tso && encp->enc_fw_assisted_tso_v2_enabled)
2391f014258SIvan Malov 		limits.edl_max_txq_count =
2401f014258SIvan Malov 			MIN(limits.edl_max_txq_count,
2411f014258SIvan Malov 			    encp->enc_fw_assisted_tso_v2_n_contexts /
2421f014258SIvan Malov 			    encp->enc_hw_pf_count);
2431f014258SIvan Malov 
24491831d40SAndrew Rybchenko 	SFC_ASSERT(limits.edl_max_txq_count >= limits.edl_min_rxq_count);
24591831d40SAndrew Rybchenko 
24691831d40SAndrew Rybchenko 	/* Configure the minimum required resources needed for the
24791831d40SAndrew Rybchenko 	 * driver to operate, and the maximum desired resources that the
24891831d40SAndrew Rybchenko 	 * driver is capable of using.
24991831d40SAndrew Rybchenko 	 */
25091831d40SAndrew Rybchenko 	efx_nic_set_drv_limits(sa->nic, &limits);
25191831d40SAndrew Rybchenko 
25291831d40SAndrew Rybchenko 	sfc_log_init(sa, "init nic");
25391831d40SAndrew Rybchenko 	rc = efx_nic_init(sa->nic);
25491831d40SAndrew Rybchenko 	if (rc != 0)
25591831d40SAndrew Rybchenko 		goto fail_nic_init;
25691831d40SAndrew Rybchenko 
25791831d40SAndrew Rybchenko 	/* Find resource dimensions assigned by firmware to this function */
25891831d40SAndrew Rybchenko 	rc = efx_nic_get_vi_pool(sa->nic, &evq_allocated, &rxq_allocated,
25991831d40SAndrew Rybchenko 				 &txq_allocated);
26091831d40SAndrew Rybchenko 	if (rc != 0)
26191831d40SAndrew Rybchenko 		goto fail_get_vi_pool;
26291831d40SAndrew Rybchenko 
26391831d40SAndrew Rybchenko 	/* It still may allocate more than maximum, ensure limit */
26491831d40SAndrew Rybchenko 	evq_allocated = MIN(evq_allocated, limits.edl_max_evq_count);
26591831d40SAndrew Rybchenko 	rxq_allocated = MIN(rxq_allocated, limits.edl_max_rxq_count);
26691831d40SAndrew Rybchenko 	txq_allocated = MIN(txq_allocated, limits.edl_max_txq_count);
26791831d40SAndrew Rybchenko 
268983ce116SIgor Romanov 	/*
269983ce116SIgor Romanov 	 * Subtract management EVQ not used for traffic
270983ce116SIgor Romanov 	 * The resource allocation strategy is as follows:
271983ce116SIgor Romanov 	 * - one EVQ for management
272983ce116SIgor Romanov 	 * - one EVQ for each ethdev RXQ
273983ce116SIgor Romanov 	 * - one EVQ for each ethdev TXQ
274983ce116SIgor Romanov 	 * - one EVQ and one RXQ for optional MAE counters.
275983ce116SIgor Romanov 	 */
276983ce116SIgor Romanov 	if (evq_allocated == 0) {
277983ce116SIgor Romanov 		sfc_err(sa, "count of allocated EvQ is 0");
278983ce116SIgor Romanov 		rc = ENOMEM;
279983ce116SIgor Romanov 		goto fail_allocate_evq;
280983ce116SIgor Romanov 	}
28191831d40SAndrew Rybchenko 	evq_allocated--;
28291831d40SAndrew Rybchenko 
283983ce116SIgor Romanov 	/*
284983ce116SIgor Romanov 	 * Reserve absolutely required minimum.
285983ce116SIgor Romanov 	 * Right now we use separate EVQ for Rx and Tx.
286983ce116SIgor Romanov 	 */
287983ce116SIgor Romanov 	if (rxq_allocated > 0 && evq_allocated > 0) {
288983ce116SIgor Romanov 		sa->rxq_max = 1;
289983ce116SIgor Romanov 		rxq_allocated--;
290983ce116SIgor Romanov 		evq_allocated--;
291983ce116SIgor Romanov 	}
292983ce116SIgor Romanov 	if (txq_allocated > 0 && evq_allocated > 0) {
293983ce116SIgor Romanov 		sa->txq_max = 1;
294983ce116SIgor Romanov 		txq_allocated--;
295983ce116SIgor Romanov 		evq_allocated--;
296983ce116SIgor Romanov 	}
297983ce116SIgor Romanov 
298983ce116SIgor Romanov 	if (sfc_mae_counter_rxq_required(sa) &&
299983ce116SIgor Romanov 	    rxq_allocated > 0 && evq_allocated > 0) {
300983ce116SIgor Romanov 		rxq_allocated--;
301983ce116SIgor Romanov 		evq_allocated--;
302983ce116SIgor Romanov 		sas->counters_rxq_allocated = true;
303983ce116SIgor Romanov 	} else {
304983ce116SIgor Romanov 		sas->counters_rxq_allocated = false;
305983ce116SIgor Romanov 	}
306983ce116SIgor Romanov 
307689a5674SIgor Romanov 	if (sfc_repr_supported(sa) &&
308689a5674SIgor Romanov 	    evq_allocated >= SFC_REPR_PROXY_NB_RXQ_MIN +
309689a5674SIgor Romanov 	    SFC_REPR_PROXY_NB_TXQ_MIN &&
310689a5674SIgor Romanov 	    rxq_allocated >= SFC_REPR_PROXY_NB_RXQ_MIN &&
311689a5674SIgor Romanov 	    txq_allocated >= SFC_REPR_PROXY_NB_TXQ_MIN) {
312689a5674SIgor Romanov 		unsigned int extra;
313689a5674SIgor Romanov 
314689a5674SIgor Romanov 		txq_allocated -= SFC_REPR_PROXY_NB_TXQ_MIN;
315689a5674SIgor Romanov 		rxq_allocated -= SFC_REPR_PROXY_NB_RXQ_MIN;
316689a5674SIgor Romanov 		evq_allocated -= SFC_REPR_PROXY_NB_RXQ_MIN +
317689a5674SIgor Romanov 			SFC_REPR_PROXY_NB_TXQ_MIN;
318689a5674SIgor Romanov 
319689a5674SIgor Romanov 		sas->nb_repr_rxq = SFC_REPR_PROXY_NB_RXQ_MIN;
320689a5674SIgor Romanov 		sas->nb_repr_txq = SFC_REPR_PROXY_NB_TXQ_MIN;
321689a5674SIgor Romanov 
322689a5674SIgor Romanov 		/* Allocate extra representor RxQs up to the maximum */
323689a5674SIgor Romanov 		extra = MIN(evq_allocated, rxq_allocated);
324689a5674SIgor Romanov 		extra = MIN(extra,
325689a5674SIgor Romanov 			    SFC_REPR_PROXY_NB_RXQ_MAX - sas->nb_repr_rxq);
326689a5674SIgor Romanov 		evq_allocated -= extra;
327689a5674SIgor Romanov 		rxq_allocated -= extra;
328689a5674SIgor Romanov 		sas->nb_repr_rxq += extra;
329689a5674SIgor Romanov 
330689a5674SIgor Romanov 		/* Allocate extra representor TxQs up to the maximum */
331689a5674SIgor Romanov 		extra = MIN(evq_allocated, txq_allocated);
332689a5674SIgor Romanov 		extra = MIN(extra,
333689a5674SIgor Romanov 			    SFC_REPR_PROXY_NB_TXQ_MAX - sas->nb_repr_txq);
334689a5674SIgor Romanov 		evq_allocated -= extra;
335689a5674SIgor Romanov 		txq_allocated -= extra;
336689a5674SIgor Romanov 		sas->nb_repr_txq += extra;
337689a5674SIgor Romanov 	} else {
338689a5674SIgor Romanov 		sas->nb_repr_rxq = 0;
339689a5674SIgor Romanov 		sas->nb_repr_txq = 0;
340689a5674SIgor Romanov 	}
341689a5674SIgor Romanov 
342983ce116SIgor Romanov 	/* Add remaining allocated queues */
343983ce116SIgor Romanov 	sa->rxq_max += MIN(rxq_allocated, evq_allocated / 2);
344983ce116SIgor Romanov 	sa->txq_max += MIN(txq_allocated, evq_allocated - sa->rxq_max);
34591831d40SAndrew Rybchenko 
34691831d40SAndrew Rybchenko 	/* Keep NIC initialized */
34791831d40SAndrew Rybchenko 	return 0;
34891831d40SAndrew Rybchenko 
349983ce116SIgor Romanov fail_allocate_evq:
35091831d40SAndrew Rybchenko fail_get_vi_pool:
35191831d40SAndrew Rybchenko 	efx_nic_fini(sa->nic);
352ba77f3e1SIgor Romanov fail_nic_init:
35391831d40SAndrew Rybchenko 	return rc;
35491831d40SAndrew Rybchenko }
35591831d40SAndrew Rybchenko 
35691831d40SAndrew Rybchenko static int
35791831d40SAndrew Rybchenko sfc_set_drv_limits(struct sfc_adapter *sa)
35891831d40SAndrew Rybchenko {
359689a5674SIgor Romanov 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
36091831d40SAndrew Rybchenko 	const struct rte_eth_dev_data *data = sa->eth_dev->data;
361689a5674SIgor Romanov 	uint32_t rxq_reserved = sfc_nb_reserved_rxq(sas);
362689a5674SIgor Romanov 	uint32_t txq_reserved = sfc_nb_txq_reserved(sas);
36391831d40SAndrew Rybchenko 	efx_drv_limits_t lim;
36491831d40SAndrew Rybchenko 
36591831d40SAndrew Rybchenko 	memset(&lim, 0, sizeof(lim));
36691831d40SAndrew Rybchenko 
367983ce116SIgor Romanov 	/*
368983ce116SIgor Romanov 	 * Limits are strict since take into account initial estimation.
3697be78d02SJosh Soref 	 * Resource allocation strategy is described in
370983ce116SIgor Romanov 	 * sfc_estimate_resource_limits().
371983ce116SIgor Romanov 	 */
37291831d40SAndrew Rybchenko 	lim.edl_min_evq_count = lim.edl_max_evq_count =
373689a5674SIgor Romanov 		1 + data->nb_rx_queues + data->nb_tx_queues +
374689a5674SIgor Romanov 		rxq_reserved + txq_reserved;
375983ce116SIgor Romanov 	lim.edl_min_rxq_count = lim.edl_max_rxq_count =
376983ce116SIgor Romanov 		data->nb_rx_queues + rxq_reserved;
377689a5674SIgor Romanov 	lim.edl_min_txq_count = lim.edl_max_txq_count =
378689a5674SIgor Romanov 		data->nb_tx_queues + txq_reserved;
37991831d40SAndrew Rybchenko 
38091831d40SAndrew Rybchenko 	return efx_nic_set_drv_limits(sa->nic, &lim);
38191831d40SAndrew Rybchenko }
38291831d40SAndrew Rybchenko 
383b1ffa211SAndrew Rybchenko static int
3842f44752cSAndrew Rybchenko sfc_set_fw_subvariant(struct sfc_adapter *sa)
3852f44752cSAndrew Rybchenko {
386113a14a6SAndrew Rybchenko 	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
3872f44752cSAndrew Rybchenko 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
3882f44752cSAndrew Rybchenko 	uint64_t tx_offloads = sa->eth_dev->data->dev_conf.txmode.offloads;
3892f44752cSAndrew Rybchenko 	unsigned int txq_index;
3902f44752cSAndrew Rybchenko 	efx_nic_fw_subvariant_t req_fw_subvariant;
3912f44752cSAndrew Rybchenko 	efx_nic_fw_subvariant_t cur_fw_subvariant;
3922f44752cSAndrew Rybchenko 	int rc;
3932f44752cSAndrew Rybchenko 
3942f44752cSAndrew Rybchenko 	if (!encp->enc_fw_subvariant_no_tx_csum_supported) {
3952f44752cSAndrew Rybchenko 		sfc_info(sa, "no-Tx-checksum subvariant not supported");
3962f44752cSAndrew Rybchenko 		return 0;
3972f44752cSAndrew Rybchenko 	}
3982f44752cSAndrew Rybchenko 
399113a14a6SAndrew Rybchenko 	for (txq_index = 0; txq_index < sas->txq_count; ++txq_index) {
400113a14a6SAndrew Rybchenko 		struct sfc_txq_info *txq_info = &sas->txq_info[txq_index];
4012f44752cSAndrew Rybchenko 
40229e4237dSAndrew Rybchenko 		if (txq_info->state & SFC_TXQ_INITIALIZED)
403b57870f2SAndrew Rybchenko 			tx_offloads |= txq_info->offloads;
4042f44752cSAndrew Rybchenko 	}
4052f44752cSAndrew Rybchenko 
406295968d1SFerruh Yigit 	if (tx_offloads & (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
407295968d1SFerruh Yigit 			   RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
408295968d1SFerruh Yigit 			   RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
409295968d1SFerruh Yigit 			   RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM))
4102f44752cSAndrew Rybchenko 		req_fw_subvariant = EFX_NIC_FW_SUBVARIANT_DEFAULT;
4112f44752cSAndrew Rybchenko 	else
4122f44752cSAndrew Rybchenko 		req_fw_subvariant = EFX_NIC_FW_SUBVARIANT_NO_TX_CSUM;
4132f44752cSAndrew Rybchenko 
4142f44752cSAndrew Rybchenko 	rc = efx_nic_get_fw_subvariant(sa->nic, &cur_fw_subvariant);
4152f44752cSAndrew Rybchenko 	if (rc != 0) {
4162f44752cSAndrew Rybchenko 		sfc_err(sa, "failed to get FW subvariant: %d", rc);
4172f44752cSAndrew Rybchenko 		return rc;
4182f44752cSAndrew Rybchenko 	}
4192f44752cSAndrew Rybchenko 	sfc_info(sa, "FW subvariant is %u vs required %u",
4202f44752cSAndrew Rybchenko 		 cur_fw_subvariant, req_fw_subvariant);
4212f44752cSAndrew Rybchenko 
4222f44752cSAndrew Rybchenko 	if (cur_fw_subvariant == req_fw_subvariant)
4232f44752cSAndrew Rybchenko 		return 0;
4242f44752cSAndrew Rybchenko 
4252f44752cSAndrew Rybchenko 	rc = efx_nic_set_fw_subvariant(sa->nic, req_fw_subvariant);
4262f44752cSAndrew Rybchenko 	if (rc != 0) {
4272f44752cSAndrew Rybchenko 		sfc_err(sa, "failed to set FW subvariant %u: %d",
4282f44752cSAndrew Rybchenko 			req_fw_subvariant, rc);
4292f44752cSAndrew Rybchenko 		return rc;
4302f44752cSAndrew Rybchenko 	}
4312f44752cSAndrew Rybchenko 	sfc_info(sa, "FW subvariant set to %u", req_fw_subvariant);
4322f44752cSAndrew Rybchenko 
4332f44752cSAndrew Rybchenko 	return 0;
4342f44752cSAndrew Rybchenko }
4352f44752cSAndrew Rybchenko 
4362f44752cSAndrew Rybchenko static int
437b1ffa211SAndrew Rybchenko sfc_try_start(struct sfc_adapter *sa)
43893fcf09bSAndrew Rybchenko {
43936c35355SAndrew Rybchenko 	const efx_nic_cfg_t *encp;
44093fcf09bSAndrew Rybchenko 	int rc;
44193fcf09bSAndrew Rybchenko 
44293fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "entry");
44393fcf09bSAndrew Rybchenko 
44493fcf09bSAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
445ac478689SIgor Romanov 	SFC_ASSERT(sa->state == SFC_ETHDEV_STARTING);
44693fcf09bSAndrew Rybchenko 
4472f44752cSAndrew Rybchenko 	sfc_log_init(sa, "set FW subvariant");
4482f44752cSAndrew Rybchenko 	rc = sfc_set_fw_subvariant(sa);
4492f44752cSAndrew Rybchenko 	if (rc != 0)
4502f44752cSAndrew Rybchenko 		goto fail_set_fw_subvariant;
4512f44752cSAndrew Rybchenko 
45291831d40SAndrew Rybchenko 	sfc_log_init(sa, "set resource limits");
45391831d40SAndrew Rybchenko 	rc = sfc_set_drv_limits(sa);
45491831d40SAndrew Rybchenko 	if (rc != 0)
45591831d40SAndrew Rybchenko 		goto fail_set_drv_limits;
45691831d40SAndrew Rybchenko 
45793fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "init nic");
45893fcf09bSAndrew Rybchenko 	rc = efx_nic_init(sa->nic);
45993fcf09bSAndrew Rybchenko 	if (rc != 0)
46093fcf09bSAndrew Rybchenko 		goto fail_nic_init;
46193fcf09bSAndrew Rybchenko 
4623037e6cfSViacheslav Galaktionov 	sfc_log_init(sa, "reconfigure NIC DMA");
4633037e6cfSViacheslav Galaktionov 	rc = efx_nic_dma_reconfigure(sa->nic);
4643037e6cfSViacheslav Galaktionov 	if (rc != 0) {
4653037e6cfSViacheslav Galaktionov 		sfc_err(sa, "cannot reconfigure NIC DMA: %s", rte_strerror(rc));
4663037e6cfSViacheslav Galaktionov 		goto fail_nic_dma_reconfigure;
4673037e6cfSViacheslav Galaktionov 	}
4683037e6cfSViacheslav Galaktionov 
46936c35355SAndrew Rybchenko 	encp = efx_nic_cfg_get(sa->nic);
4702646d42fSAndrew Rybchenko 
4712646d42fSAndrew Rybchenko 	/*
4722646d42fSAndrew Rybchenko 	 * Refresh (since it may change on NIC reset/restart) a copy of
4732646d42fSAndrew Rybchenko 	 * supported tunnel encapsulations in shared memory to be used
4742646d42fSAndrew Rybchenko 	 * on supported Rx packet type classes get.
4752646d42fSAndrew Rybchenko 	 */
4762646d42fSAndrew Rybchenko 	sa->priv.shared->tunnel_encaps =
4772646d42fSAndrew Rybchenko 		encp->enc_tunnel_encapsulations_supported;
4782646d42fSAndrew Rybchenko 
47936c35355SAndrew Rybchenko 	if (encp->enc_tunnel_encapsulations_supported != 0) {
48036c35355SAndrew Rybchenko 		sfc_log_init(sa, "apply tunnel config");
48136c35355SAndrew Rybchenko 		rc = efx_tunnel_reconfigure(sa->nic);
48236c35355SAndrew Rybchenko 		if (rc != 0)
48336c35355SAndrew Rybchenko 			goto fail_tunnel_reconfigure;
48436c35355SAndrew Rybchenko 	}
48536c35355SAndrew Rybchenko 
48606bc1977SAndrew Rybchenko 	rc = sfc_intr_start(sa);
48706bc1977SAndrew Rybchenko 	if (rc != 0)
48806bc1977SAndrew Rybchenko 		goto fail_intr_start;
48906bc1977SAndrew Rybchenko 
49058294ee6SAndrew Rybchenko 	rc = sfc_ev_start(sa);
49158294ee6SAndrew Rybchenko 	if (rc != 0)
49258294ee6SAndrew Rybchenko 		goto fail_ev_start;
49358294ee6SAndrew Rybchenko 
494*bc712f1cSDenis Pryazhennikov 	rc = sfc_tbls_start(sa);
495*bc712f1cSDenis Pryazhennikov 	if (rc != 0)
496*bc712f1cSDenis Pryazhennikov 		goto fail_tbls_start;
497*bc712f1cSDenis Pryazhennikov 
49803ed2119SAndrew Rybchenko 	rc = sfc_port_start(sa);
49903ed2119SAndrew Rybchenko 	if (rc != 0)
50003ed2119SAndrew Rybchenko 		goto fail_port_start;
50103ed2119SAndrew Rybchenko 
50228944ac0SAndrew Rybchenko 	rc = sfc_rx_start(sa);
50328944ac0SAndrew Rybchenko 	if (rc != 0)
50428944ac0SAndrew Rybchenko 		goto fail_rx_start;
50528944ac0SAndrew Rybchenko 
506fed9aeb4SIvan Malov 	rc = sfc_tx_start(sa);
507fed9aeb4SIvan Malov 	if (rc != 0)
508fed9aeb4SIvan Malov 		goto fail_tx_start;
509fed9aeb4SIvan Malov 
510a9825ccfSRoman Zhukov 	rc = sfc_flow_start(sa);
511a9825ccfSRoman Zhukov 	if (rc != 0)
512a9825ccfSRoman Zhukov 		goto fail_flows_insert;
513a9825ccfSRoman Zhukov 
51452e80b1bSIgor Romanov 	rc = sfc_repr_proxy_start(sa);
51552e80b1bSIgor Romanov 	if (rc != 0)
51652e80b1bSIgor Romanov 		goto fail_repr_proxy_start;
51752e80b1bSIgor Romanov 
51893fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "done");
51993fcf09bSAndrew Rybchenko 	return 0;
52093fcf09bSAndrew Rybchenko 
52152e80b1bSIgor Romanov fail_repr_proxy_start:
52252e80b1bSIgor Romanov 	sfc_flow_stop(sa);
52352e80b1bSIgor Romanov 
524a9825ccfSRoman Zhukov fail_flows_insert:
525a9825ccfSRoman Zhukov 	sfc_tx_stop(sa);
526a9825ccfSRoman Zhukov 
527fed9aeb4SIvan Malov fail_tx_start:
528fed9aeb4SIvan Malov 	sfc_rx_stop(sa);
529fed9aeb4SIvan Malov 
53028944ac0SAndrew Rybchenko fail_rx_start:
53128944ac0SAndrew Rybchenko 	sfc_port_stop(sa);
53228944ac0SAndrew Rybchenko 
533*bc712f1cSDenis Pryazhennikov fail_tbls_start:
53403ed2119SAndrew Rybchenko 	sfc_ev_stop(sa);
53503ed2119SAndrew Rybchenko 
536*bc712f1cSDenis Pryazhennikov fail_port_start:
537*bc712f1cSDenis Pryazhennikov 	sfc_tbls_stop(sa);
538*bc712f1cSDenis Pryazhennikov 
53958294ee6SAndrew Rybchenko fail_ev_start:
54058294ee6SAndrew Rybchenko 	sfc_intr_stop(sa);
54158294ee6SAndrew Rybchenko 
54206bc1977SAndrew Rybchenko fail_intr_start:
54336c35355SAndrew Rybchenko fail_tunnel_reconfigure:
5443037e6cfSViacheslav Galaktionov fail_nic_dma_reconfigure:
54506bc1977SAndrew Rybchenko 	efx_nic_fini(sa->nic);
54606bc1977SAndrew Rybchenko 
54793fcf09bSAndrew Rybchenko fail_nic_init:
54891831d40SAndrew Rybchenko fail_set_drv_limits:
5492f44752cSAndrew Rybchenko fail_set_fw_subvariant:
550b1ffa211SAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
551b1ffa211SAndrew Rybchenko 	return rc;
552b1ffa211SAndrew Rybchenko }
553b1ffa211SAndrew Rybchenko 
554b1ffa211SAndrew Rybchenko int
555b1ffa211SAndrew Rybchenko sfc_start(struct sfc_adapter *sa)
556b1ffa211SAndrew Rybchenko {
557b1ffa211SAndrew Rybchenko 	unsigned int start_tries = 3;
558b1ffa211SAndrew Rybchenko 	int rc;
559b1ffa211SAndrew Rybchenko 
560b1ffa211SAndrew Rybchenko 	sfc_log_init(sa, "entry");
561b1ffa211SAndrew Rybchenko 
562b1ffa211SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
563b1ffa211SAndrew Rybchenko 
564b1ffa211SAndrew Rybchenko 	switch (sa->state) {
565ac478689SIgor Romanov 	case SFC_ETHDEV_CONFIGURED:
566b1ffa211SAndrew Rybchenko 		break;
567ac478689SIgor Romanov 	case SFC_ETHDEV_STARTED:
56891d16276SIvan Malov 		sfc_notice(sa, "already started");
569b1ffa211SAndrew Rybchenko 		return 0;
570b1ffa211SAndrew Rybchenko 	default:
571b1ffa211SAndrew Rybchenko 		rc = EINVAL;
572b1ffa211SAndrew Rybchenko 		goto fail_bad_state;
573b1ffa211SAndrew Rybchenko 	}
574b1ffa211SAndrew Rybchenko 
575ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_STARTING;
576b1ffa211SAndrew Rybchenko 
577dd45b880SAndrew Rybchenko 	rc = 0;
578b1ffa211SAndrew Rybchenko 	do {
579dd45b880SAndrew Rybchenko 		/*
580dd45b880SAndrew Rybchenko 		 * FIXME Try to recreate vSwitch on start retry.
581dd45b880SAndrew Rybchenko 		 * vSwitch is absent after MC reboot like events and
582dd45b880SAndrew Rybchenko 		 * we should recreate it. May be we need proper
583dd45b880SAndrew Rybchenko 		 * indication instead of guessing.
584dd45b880SAndrew Rybchenko 		 */
585dd45b880SAndrew Rybchenko 		if (rc != 0) {
586dd45b880SAndrew Rybchenko 			sfc_sriov_vswitch_destroy(sa);
587dd45b880SAndrew Rybchenko 			rc = sfc_sriov_vswitch_create(sa);
588dd45b880SAndrew Rybchenko 			if (rc != 0)
589dd45b880SAndrew Rybchenko 				goto fail_sriov_vswitch_create;
590dd45b880SAndrew Rybchenko 		}
591b1ffa211SAndrew Rybchenko 		rc = sfc_try_start(sa);
592b1ffa211SAndrew Rybchenko 	} while ((--start_tries > 0) &&
593b1ffa211SAndrew Rybchenko 		 (rc == EIO || rc == EAGAIN || rc == ENOENT || rc == EINVAL));
594b1ffa211SAndrew Rybchenko 
595b1ffa211SAndrew Rybchenko 	if (rc != 0)
596b1ffa211SAndrew Rybchenko 		goto fail_try_start;
597b1ffa211SAndrew Rybchenko 
598ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_STARTED;
599b1ffa211SAndrew Rybchenko 	sfc_log_init(sa, "done");
600b1ffa211SAndrew Rybchenko 	return 0;
601b1ffa211SAndrew Rybchenko 
602b1ffa211SAndrew Rybchenko fail_try_start:
603dd45b880SAndrew Rybchenko fail_sriov_vswitch_create:
604ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_CONFIGURED;
60593fcf09bSAndrew Rybchenko fail_bad_state:
60693fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
60793fcf09bSAndrew Rybchenko 	return rc;
60893fcf09bSAndrew Rybchenko }
60993fcf09bSAndrew Rybchenko 
61093fcf09bSAndrew Rybchenko void
61193fcf09bSAndrew Rybchenko sfc_stop(struct sfc_adapter *sa)
61293fcf09bSAndrew Rybchenko {
61393fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "entry");
61493fcf09bSAndrew Rybchenko 
61593fcf09bSAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
61693fcf09bSAndrew Rybchenko 
61793fcf09bSAndrew Rybchenko 	switch (sa->state) {
618ac478689SIgor Romanov 	case SFC_ETHDEV_STARTED:
61993fcf09bSAndrew Rybchenko 		break;
620ac478689SIgor Romanov 	case SFC_ETHDEV_CONFIGURED:
62191d16276SIvan Malov 		sfc_notice(sa, "already stopped");
62293fcf09bSAndrew Rybchenko 		return;
62393fcf09bSAndrew Rybchenko 	default:
62493fcf09bSAndrew Rybchenko 		sfc_err(sa, "stop in unexpected state %u", sa->state);
62593fcf09bSAndrew Rybchenko 		SFC_ASSERT(B_FALSE);
62693fcf09bSAndrew Rybchenko 		return;
62793fcf09bSAndrew Rybchenko 	}
62893fcf09bSAndrew Rybchenko 
629ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_STOPPING;
63093fcf09bSAndrew Rybchenko 
63152e80b1bSIgor Romanov 	sfc_repr_proxy_stop(sa);
632a9825ccfSRoman Zhukov 	sfc_flow_stop(sa);
633fed9aeb4SIvan Malov 	sfc_tx_stop(sa);
63428944ac0SAndrew Rybchenko 	sfc_rx_stop(sa);
63503ed2119SAndrew Rybchenko 	sfc_port_stop(sa);
636*bc712f1cSDenis Pryazhennikov 	sfc_tbls_stop(sa);
63758294ee6SAndrew Rybchenko 	sfc_ev_stop(sa);
63806bc1977SAndrew Rybchenko 	sfc_intr_stop(sa);
63993fcf09bSAndrew Rybchenko 	efx_nic_fini(sa->nic);
64093fcf09bSAndrew Rybchenko 
641ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_CONFIGURED;
64293fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "done");
64393fcf09bSAndrew Rybchenko }
64493fcf09bSAndrew Rybchenko 
645e77f9f19SAndrew Rybchenko static int
646e77f9f19SAndrew Rybchenko sfc_restart(struct sfc_adapter *sa)
647e77f9f19SAndrew Rybchenko {
648e77f9f19SAndrew Rybchenko 	int rc;
649e77f9f19SAndrew Rybchenko 
650e77f9f19SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
651e77f9f19SAndrew Rybchenko 
652ac478689SIgor Romanov 	if (sa->state != SFC_ETHDEV_STARTED)
653e77f9f19SAndrew Rybchenko 		return EINVAL;
654e77f9f19SAndrew Rybchenko 
655e77f9f19SAndrew Rybchenko 	sfc_stop(sa);
656e77f9f19SAndrew Rybchenko 
657e77f9f19SAndrew Rybchenko 	rc = sfc_start(sa);
658e77f9f19SAndrew Rybchenko 	if (rc != 0)
659e77f9f19SAndrew Rybchenko 		sfc_err(sa, "restart failed");
660e77f9f19SAndrew Rybchenko 
661e77f9f19SAndrew Rybchenko 	return rc;
662e77f9f19SAndrew Rybchenko }
663e77f9f19SAndrew Rybchenko 
664e77f9f19SAndrew Rybchenko static void
665e77f9f19SAndrew Rybchenko sfc_restart_if_required(void *arg)
666e77f9f19SAndrew Rybchenko {
667e77f9f19SAndrew Rybchenko 	struct sfc_adapter *sa = arg;
668e77f9f19SAndrew Rybchenko 
669e77f9f19SAndrew Rybchenko 	/* If restart is scheduled, clear the flag and do it */
670e77f9f19SAndrew Rybchenko 	if (rte_atomic32_cmpset((volatile uint32_t *)&sa->restart_required,
671e77f9f19SAndrew Rybchenko 				1, 0)) {
672e77f9f19SAndrew Rybchenko 		sfc_adapter_lock(sa);
673ac478689SIgor Romanov 		if (sa->state == SFC_ETHDEV_STARTED)
674e77f9f19SAndrew Rybchenko 			(void)sfc_restart(sa);
675e77f9f19SAndrew Rybchenko 		sfc_adapter_unlock(sa);
676e77f9f19SAndrew Rybchenko 	}
677e77f9f19SAndrew Rybchenko }
678e77f9f19SAndrew Rybchenko 
679e77f9f19SAndrew Rybchenko void
680e77f9f19SAndrew Rybchenko sfc_schedule_restart(struct sfc_adapter *sa)
681e77f9f19SAndrew Rybchenko {
682e77f9f19SAndrew Rybchenko 	int rc;
683e77f9f19SAndrew Rybchenko 
684e77f9f19SAndrew Rybchenko 	/* Schedule restart alarm if it is not scheduled yet */
685e77f9f19SAndrew Rybchenko 	if (!rte_atomic32_test_and_set(&sa->restart_required))
686e77f9f19SAndrew Rybchenko 		return;
687e77f9f19SAndrew Rybchenko 
688e77f9f19SAndrew Rybchenko 	rc = rte_eal_alarm_set(1, sfc_restart_if_required, sa);
689e77f9f19SAndrew Rybchenko 	if (rc == -ENOTSUP)
690e77f9f19SAndrew Rybchenko 		sfc_warn(sa, "alarms are not supported, restart is pending");
691e77f9f19SAndrew Rybchenko 	else if (rc != 0)
692e77f9f19SAndrew Rybchenko 		sfc_err(sa, "cannot arm restart alarm (rc=%d)", rc);
693e77f9f19SAndrew Rybchenko 	else
69491d16276SIvan Malov 		sfc_notice(sa, "restart scheduled");
695e77f9f19SAndrew Rybchenko }
696e77f9f19SAndrew Rybchenko 
69793fcf09bSAndrew Rybchenko int
698aaa3f5f0SAndrew Rybchenko sfc_configure(struct sfc_adapter *sa)
699aaa3f5f0SAndrew Rybchenko {
700c7cb2d7aSAndrew Rybchenko 	int rc;
701c7cb2d7aSAndrew Rybchenko 
702aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "entry");
703aaa3f5f0SAndrew Rybchenko 
704aaa3f5f0SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
705aaa3f5f0SAndrew Rybchenko 
706ac478689SIgor Romanov 	SFC_ASSERT(sa->state == SFC_ETHDEV_INITIALIZED ||
707ac478689SIgor Romanov 		   sa->state == SFC_ETHDEV_CONFIGURED);
708ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_CONFIGURING;
709aaa3f5f0SAndrew Rybchenko 
710c7cb2d7aSAndrew Rybchenko 	rc = sfc_check_conf(sa);
711c7cb2d7aSAndrew Rybchenko 	if (rc != 0)
712c7cb2d7aSAndrew Rybchenko 		goto fail_check_conf;
713c7cb2d7aSAndrew Rybchenko 
71452597396SAndrew Rybchenko 	rc = sfc_intr_configure(sa);
71506bc1977SAndrew Rybchenko 	if (rc != 0)
71652597396SAndrew Rybchenko 		goto fail_intr_configure;
71706bc1977SAndrew Rybchenko 
718c577a525SAndrew Rybchenko 	rc = sfc_port_configure(sa);
71903ed2119SAndrew Rybchenko 	if (rc != 0)
720c577a525SAndrew Rybchenko 		goto fail_port_configure;
72103ed2119SAndrew Rybchenko 
722f7637d4dSAndrew Rybchenko 	rc = sfc_rx_configure(sa);
723a8e64c6bSAndrew Rybchenko 	if (rc != 0)
724f7637d4dSAndrew Rybchenko 		goto fail_rx_configure;
725a8e64c6bSAndrew Rybchenko 
726df64eaddSAndrew Rybchenko 	rc = sfc_tx_configure(sa);
727a8ad8cf8SIvan Malov 	if (rc != 0)
728df64eaddSAndrew Rybchenko 		goto fail_tx_configure;
729a8ad8cf8SIvan Malov 
730fdd7719eSIvan Ilchenko 	rc = sfc_sw_xstats_configure(sa);
731fdd7719eSIvan Ilchenko 	if (rc != 0)
732fdd7719eSIvan Ilchenko 		goto fail_sw_xstats_configure;
733fdd7719eSIvan Ilchenko 
734ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_CONFIGURED;
735aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "done");
736aaa3f5f0SAndrew Rybchenko 	return 0;
737c7cb2d7aSAndrew Rybchenko 
738fdd7719eSIvan Ilchenko fail_sw_xstats_configure:
739fdd7719eSIvan Ilchenko 	sfc_tx_close(sa);
740fdd7719eSIvan Ilchenko 
741df64eaddSAndrew Rybchenko fail_tx_configure:
742f7637d4dSAndrew Rybchenko 	sfc_rx_close(sa);
743a8ad8cf8SIvan Malov 
744f7637d4dSAndrew Rybchenko fail_rx_configure:
745c577a525SAndrew Rybchenko 	sfc_port_close(sa);
746a8e64c6bSAndrew Rybchenko 
747c577a525SAndrew Rybchenko fail_port_configure:
74852597396SAndrew Rybchenko 	sfc_intr_close(sa);
74958294ee6SAndrew Rybchenko 
75052597396SAndrew Rybchenko fail_intr_configure:
751c7cb2d7aSAndrew Rybchenko fail_check_conf:
752ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_INITIALIZED;
753c7cb2d7aSAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
754c7cb2d7aSAndrew Rybchenko 	return rc;
755aaa3f5f0SAndrew Rybchenko }
756aaa3f5f0SAndrew Rybchenko 
757aaa3f5f0SAndrew Rybchenko void
758aaa3f5f0SAndrew Rybchenko sfc_close(struct sfc_adapter *sa)
759aaa3f5f0SAndrew Rybchenko {
760aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "entry");
761aaa3f5f0SAndrew Rybchenko 
762aaa3f5f0SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
763aaa3f5f0SAndrew Rybchenko 
764ac478689SIgor Romanov 	SFC_ASSERT(sa->state == SFC_ETHDEV_CONFIGURED);
765ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_CLOSING;
766aaa3f5f0SAndrew Rybchenko 
767fdd7719eSIvan Ilchenko 	sfc_sw_xstats_close(sa);
768df64eaddSAndrew Rybchenko 	sfc_tx_close(sa);
769f7637d4dSAndrew Rybchenko 	sfc_rx_close(sa);
770c577a525SAndrew Rybchenko 	sfc_port_close(sa);
77152597396SAndrew Rybchenko 	sfc_intr_close(sa);
77206bc1977SAndrew Rybchenko 
773ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_INITIALIZED;
774aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "done");
775aaa3f5f0SAndrew Rybchenko }
776aaa3f5f0SAndrew Rybchenko 
777ba641f20SAndrew Rybchenko static int
778fe4dad21SIgor Romanov sfc_mem_bar_init(struct sfc_adapter *sa, const efx_bar_region_t *mem_ebrp)
779ba641f20SAndrew Rybchenko {
780ba641f20SAndrew Rybchenko 	struct rte_eth_dev *eth_dev = sa->eth_dev;
781c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
782ba641f20SAndrew Rybchenko 	efsys_bar_t *ebp = &sa->mem_bar;
783fe4dad21SIgor Romanov 	struct rte_mem_resource *res =
784fe4dad21SIgor Romanov 		&pci_dev->mem_resource[mem_ebrp->ebr_index];
785ba641f20SAndrew Rybchenko 
786ba641f20SAndrew Rybchenko 	SFC_BAR_LOCK_INIT(ebp, eth_dev->data->name);
787fe4dad21SIgor Romanov 	ebp->esb_rid = mem_ebrp->ebr_index;
788ba641f20SAndrew Rybchenko 	ebp->esb_dev = pci_dev;
789ba641f20SAndrew Rybchenko 	ebp->esb_base = res->addr;
790e285f30dSIgor Romanov 
791e285f30dSIgor Romanov 	sa->fcw_offset = mem_ebrp->ebr_offset;
792e285f30dSIgor Romanov 
793ba641f20SAndrew Rybchenko 	return 0;
794ba641f20SAndrew Rybchenko }
795ba641f20SAndrew Rybchenko 
796ba641f20SAndrew Rybchenko static void
797ba641f20SAndrew Rybchenko sfc_mem_bar_fini(struct sfc_adapter *sa)
798ba641f20SAndrew Rybchenko {
799ba641f20SAndrew Rybchenko 	efsys_bar_t *ebp = &sa->mem_bar;
800ba641f20SAndrew Rybchenko 
801ba641f20SAndrew Rybchenko 	SFC_BAR_LOCK_DESTROY(ebp);
802ba641f20SAndrew Rybchenko 	memset(ebp, 0, sizeof(*ebp));
803ba641f20SAndrew Rybchenko }
804ba641f20SAndrew Rybchenko 
8054ec1fc3bSIvan Malov /*
8064ec1fc3bSIvan Malov  * A fixed RSS key which has a property of being symmetric
8074ec1fc3bSIvan Malov  * (symmetrical flows are distributed to the same CPU)
8084ec1fc3bSIvan Malov  * and also known to give a uniform distribution
8094ec1fc3bSIvan Malov  * (a good distribution of traffic between different CPUs)
8104ec1fc3bSIvan Malov  */
81137a42c61SAndrew Rybchenko static const uint8_t default_rss_key[EFX_RSS_KEY_SIZE] = {
8124ec1fc3bSIvan Malov 	0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
8134ec1fc3bSIvan Malov 	0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
8144ec1fc3bSIvan Malov 	0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
8154ec1fc3bSIvan Malov 	0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
8164ec1fc3bSIvan Malov 	0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
8174ec1fc3bSIvan Malov };
8184ec1fc3bSIvan Malov 
8194ec1fc3bSIvan Malov static int
82001764b20SIvan Malov sfc_rss_attach(struct sfc_adapter *sa)
8214ec1fc3bSIvan Malov {
822e295f175SAndrew Rybchenko 	struct sfc_rss *rss = &sfc_sa2shared(sa)->rss;
8234ec1fc3bSIvan Malov 	int rc;
8244ec1fc3bSIvan Malov 
8254ec1fc3bSIvan Malov 	rc = efx_intr_init(sa->nic, sa->intr.type, NULL);
8264ec1fc3bSIvan Malov 	if (rc != 0)
8274ec1fc3bSIvan Malov 		goto fail_intr_init;
8284ec1fc3bSIvan Malov 
8294ec1fc3bSIvan Malov 	rc = efx_ev_init(sa->nic);
8304ec1fc3bSIvan Malov 	if (rc != 0)
8314ec1fc3bSIvan Malov 		goto fail_ev_init;
8324ec1fc3bSIvan Malov 
8334ec1fc3bSIvan Malov 	rc = efx_rx_init(sa->nic);
8344ec1fc3bSIvan Malov 	if (rc != 0)
8354ec1fc3bSIvan Malov 		goto fail_rx_init;
8364ec1fc3bSIvan Malov 
837d1482e21SIvan Malov 	rc = efx_rx_scale_default_support_get(sa->nic, &rss->context_type);
8384ec1fc3bSIvan Malov 	if (rc != 0)
8394ec1fc3bSIvan Malov 		goto fail_scale_support_get;
8404ec1fc3bSIvan Malov 
841d1482e21SIvan Malov 	rc = efx_rx_hash_default_support_get(sa->nic, &rss->hash_support);
8424ec1fc3bSIvan Malov 	if (rc != 0)
8434ec1fc3bSIvan Malov 		goto fail_hash_support_get;
8444ec1fc3bSIvan Malov 
84501764b20SIvan Malov 	rc = sfc_rx_hash_init(sa);
84601764b20SIvan Malov 	if (rc != 0)
84701764b20SIvan Malov 		goto fail_rx_hash_init;
84801764b20SIvan Malov 
8494ec1fc3bSIvan Malov 	efx_rx_fini(sa->nic);
8504ec1fc3bSIvan Malov 	efx_ev_fini(sa->nic);
8514ec1fc3bSIvan Malov 	efx_intr_fini(sa->nic);
8524ec1fc3bSIvan Malov 
853d1482e21SIvan Malov 	rte_memcpy(rss->key, default_rss_key, sizeof(rss->key));
8546da67e70SIvan Malov 	memset(&rss->dummy_ctx, 0, sizeof(rss->dummy_ctx));
8556da67e70SIvan Malov 	rss->dummy_ctx.conf.qid_span = 1;
8566da67e70SIvan Malov 	rss->dummy_ctx.dummy = true;
8574ec1fc3bSIvan Malov 
8584ec1fc3bSIvan Malov 	return 0;
8594ec1fc3bSIvan Malov 
86001764b20SIvan Malov fail_rx_hash_init:
8614ec1fc3bSIvan Malov fail_hash_support_get:
8624ec1fc3bSIvan Malov fail_scale_support_get:
86300b94c1cSIvan Malov 	efx_rx_fini(sa->nic);
86400b94c1cSIvan Malov 
8654ec1fc3bSIvan Malov fail_rx_init:
8664ec1fc3bSIvan Malov 	efx_ev_fini(sa->nic);
8674ec1fc3bSIvan Malov 
8684ec1fc3bSIvan Malov fail_ev_init:
8694ec1fc3bSIvan Malov 	efx_intr_fini(sa->nic);
8704ec1fc3bSIvan Malov 
8714ec1fc3bSIvan Malov fail_intr_init:
8724ec1fc3bSIvan Malov 	return rc;
8734ec1fc3bSIvan Malov }
8744ec1fc3bSIvan Malov 
87501764b20SIvan Malov static void
87601764b20SIvan Malov sfc_rss_detach(struct sfc_adapter *sa)
87701764b20SIvan Malov {
87801764b20SIvan Malov 	sfc_rx_hash_fini(sa);
87901764b20SIvan Malov }
88001764b20SIvan Malov 
881ba641f20SAndrew Rybchenko int
882ba641f20SAndrew Rybchenko sfc_attach(struct sfc_adapter *sa)
883ba641f20SAndrew Rybchenko {
884a8ad8cf8SIvan Malov 	const efx_nic_cfg_t *encp;
885329472d4SAndrew Rybchenko 	efx_nic_t *enp = sa->nic;
886ba641f20SAndrew Rybchenko 	int rc;
887ba641f20SAndrew Rybchenko 
888ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "entry");
889ba641f20SAndrew Rybchenko 
890ba641f20SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
891ba641f20SAndrew Rybchenko 
892ba641f20SAndrew Rybchenko 	efx_mcdi_new_epoch(enp);
893ba641f20SAndrew Rybchenko 
894ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "reset nic");
895ba641f20SAndrew Rybchenko 	rc = efx_nic_reset(enp);
896ba641f20SAndrew Rybchenko 	if (rc != 0)
897ba641f20SAndrew Rybchenko 		goto fail_nic_reset;
898ba641f20SAndrew Rybchenko 
899dd45b880SAndrew Rybchenko 	rc = sfc_sriov_attach(sa);
900dd45b880SAndrew Rybchenko 	if (rc != 0)
901dd45b880SAndrew Rybchenko 		goto fail_sriov_attach;
902dd45b880SAndrew Rybchenko 
90336c35355SAndrew Rybchenko 	/*
90436c35355SAndrew Rybchenko 	 * Probed NIC is sufficient for tunnel init.
90536c35355SAndrew Rybchenko 	 * Initialize tunnel support to be able to use libefx
90636c35355SAndrew Rybchenko 	 * efx_tunnel_config_udp_{add,remove}() in any state and
90736c35355SAndrew Rybchenko 	 * efx_tunnel_reconfigure() on start up.
90836c35355SAndrew Rybchenko 	 */
90936c35355SAndrew Rybchenko 	rc = efx_tunnel_init(enp);
91036c35355SAndrew Rybchenko 	if (rc != 0)
91136c35355SAndrew Rybchenko 		goto fail_tunnel_init;
91236c35355SAndrew Rybchenko 
9131f014258SIvan Malov 	encp = efx_nic_cfg_get(sa->nic);
9141f014258SIvan Malov 
9152646d42fSAndrew Rybchenko 	/*
9162646d42fSAndrew Rybchenko 	 * Make a copy of supported tunnel encapsulations in shared
9172646d42fSAndrew Rybchenko 	 * memory to be used on supported Rx packet type classes get.
9182646d42fSAndrew Rybchenko 	 */
9192646d42fSAndrew Rybchenko 	sa->priv.shared->tunnel_encaps =
9202646d42fSAndrew Rybchenko 		encp->enc_tunnel_encapsulations_supported;
9212646d42fSAndrew Rybchenko 
922295968d1SFerruh Yigit 	if (sfc_dp_tx_offload_capa(sa->priv.dp_tx) & RTE_ETH_TX_OFFLOAD_TCP_TSO) {
9234f936666SIvan Malov 		sa->tso = encp->enc_fw_assisted_tso_v2_enabled ||
9244f936666SIvan Malov 			  encp->enc_tso_v3_enabled;
9251f014258SIvan Malov 		if (!sa->tso)
9269906cb29SIvan Malov 			sfc_info(sa, "TSO support isn't available on this adapter");
927b3b667c9SAndrew Rybchenko 	}
9281f014258SIvan Malov 
9299aa0afd1SAndrew Rybchenko 	if (sa->tso &&
9309aa0afd1SAndrew Rybchenko 	    (sfc_dp_tx_offload_capa(sa->priv.dp_tx) &
931295968d1SFerruh Yigit 	     (RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
932295968d1SFerruh Yigit 	      RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO)) != 0) {
93377cb0071SIvan Malov 		sa->tso_encap = encp->enc_fw_assisted_tso_v2_encap_enabled ||
93477cb0071SIvan Malov 				encp->enc_tso_v3_enabled;
935c1ce2ba2SIvan Malov 		if (!sa->tso_encap)
936c1ce2ba2SIvan Malov 			sfc_info(sa, "Encapsulated TSO support isn't available on this adapter");
937c1ce2ba2SIvan Malov 	}
938c1ce2ba2SIvan Malov 
93991831d40SAndrew Rybchenko 	sfc_log_init(sa, "estimate resource limits");
94091831d40SAndrew Rybchenko 	rc = sfc_estimate_resource_limits(sa);
941ba641f20SAndrew Rybchenko 	if (rc != 0)
94291831d40SAndrew Rybchenko 		goto fail_estimate_rsrc_limits;
943ba641f20SAndrew Rybchenko 
944d5371f3dSIgor Romanov 	sa->evq_max_entries = encp->enc_evq_max_nevs;
945d5371f3dSIgor Romanov 	SFC_ASSERT(rte_is_power_of_2(sa->evq_max_entries));
946d5371f3dSIgor Romanov 
947d5371f3dSIgor Romanov 	sa->evq_min_entries = encp->enc_evq_min_nevs;
948d5371f3dSIgor Romanov 	SFC_ASSERT(rte_is_power_of_2(sa->evq_min_entries));
949d5371f3dSIgor Romanov 
950048a0d1aSIgor Romanov 	sa->rxq_max_entries = encp->enc_rxq_max_ndescs;
951048a0d1aSIgor Romanov 	SFC_ASSERT(rte_is_power_of_2(sa->rxq_max_entries));
952048a0d1aSIgor Romanov 
953048a0d1aSIgor Romanov 	sa->rxq_min_entries = encp->enc_rxq_min_ndescs;
954048a0d1aSIgor Romanov 	SFC_ASSERT(rte_is_power_of_2(sa->rxq_min_entries));
955048a0d1aSIgor Romanov 
956a8ad8cf8SIvan Malov 	sa->txq_max_entries = encp->enc_txq_max_ndescs;
957a8ad8cf8SIvan Malov 	SFC_ASSERT(rte_is_power_of_2(sa->txq_max_entries));
958a8ad8cf8SIvan Malov 
9599dbd28dfSIgor Romanov 	sa->txq_min_entries = encp->enc_txq_min_ndescs;
9609dbd28dfSIgor Romanov 	SFC_ASSERT(rte_is_power_of_2(sa->txq_min_entries));
9619dbd28dfSIgor Romanov 
96206bc1977SAndrew Rybchenko 	rc = sfc_intr_attach(sa);
96306bc1977SAndrew Rybchenko 	if (rc != 0)
96406bc1977SAndrew Rybchenko 		goto fail_intr_attach;
96506bc1977SAndrew Rybchenko 
96647995190SAndrew Rybchenko 	rc = sfc_ev_attach(sa);
96747995190SAndrew Rybchenko 	if (rc != 0)
96847995190SAndrew Rybchenko 		goto fail_ev_attach;
96947995190SAndrew Rybchenko 
970c577a525SAndrew Rybchenko 	rc = sfc_port_attach(sa);
971c577a525SAndrew Rybchenko 	if (rc != 0)
972c577a525SAndrew Rybchenko 		goto fail_port_attach;
973d23f3a89SAndrew Rybchenko 
97401764b20SIvan Malov 	rc = sfc_rss_attach(sa);
9754ec1fc3bSIvan Malov 	if (rc != 0)
97601764b20SIvan Malov 		goto fail_rss_attach;
9774ec1fc3bSIvan Malov 
9786da67e70SIvan Malov 	rc = sfc_flow_rss_attach(sa);
9796da67e70SIvan Malov 	if (rc != 0)
9806da67e70SIvan Malov 		goto fail_flow_rss_attach;
9816da67e70SIvan Malov 
982791f57acSAndrew Rybchenko 	rc = sfc_filter_attach(sa);
983791f57acSAndrew Rybchenko 	if (rc != 0)
984791f57acSAndrew Rybchenko 		goto fail_filter_attach;
985791f57acSAndrew Rybchenko 
986983ce116SIgor Romanov 	rc = sfc_mae_counter_rxq_attach(sa);
987983ce116SIgor Romanov 	if (rc != 0)
988983ce116SIgor Romanov 		goto fail_mae_counter_rxq_attach;
989983ce116SIgor Romanov 
99002b234adSIvan Malov 	rc = sfc_mae_attach(sa);
99102b234adSIvan Malov 	if (rc != 0)
99202b234adSIvan Malov 		goto fail_mae_attach;
99302b234adSIvan Malov 
994*bc712f1cSDenis Pryazhennikov 	rc = sfc_tbls_attach(sa);
995*bc712f1cSDenis Pryazhennikov 	if (rc != 0)
996*bc712f1cSDenis Pryazhennikov 		goto fail_tables_attach;
997*bc712f1cSDenis Pryazhennikov 
998c8617ddaSIgor Romanov 	rc = sfc_mae_switchdev_init(sa);
999c8617ddaSIgor Romanov 	if (rc != 0)
1000c8617ddaSIgor Romanov 		goto fail_mae_switchdev_init;
1001c8617ddaSIgor Romanov 
100252e80b1bSIgor Romanov 	rc = sfc_repr_proxy_attach(sa);
100352e80b1bSIgor Romanov 	if (rc != 0)
100452e80b1bSIgor Romanov 		goto fail_repr_proxy_attach;
100552e80b1bSIgor Romanov 
1006ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "fini nic");
1007ba641f20SAndrew Rybchenko 	efx_nic_fini(enp);
1008ba641f20SAndrew Rybchenko 
1009a9825ccfSRoman Zhukov 	sfc_flow_init(sa);
1010a9825ccfSRoman Zhukov 
1011fdd7719eSIvan Ilchenko 	rc = sfc_sw_xstats_init(sa);
1012fdd7719eSIvan Ilchenko 	if (rc != 0)
1013fdd7719eSIvan Ilchenko 		goto fail_sw_xstats_init;
1014fdd7719eSIvan Ilchenko 
1015dd45b880SAndrew Rybchenko 	/*
1016dd45b880SAndrew Rybchenko 	 * Create vSwitch to be able to use VFs when PF is not started yet
1017dd45b880SAndrew Rybchenko 	 * as DPDK port. VFs should be able to talk to each other even
1018dd45b880SAndrew Rybchenko 	 * if PF is down.
1019dd45b880SAndrew Rybchenko 	 */
1020dd45b880SAndrew Rybchenko 	rc = sfc_sriov_vswitch_create(sa);
1021dd45b880SAndrew Rybchenko 	if (rc != 0)
1022dd45b880SAndrew Rybchenko 		goto fail_sriov_vswitch_create;
1023dd45b880SAndrew Rybchenko 
1024ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_INITIALIZED;
1025ba641f20SAndrew Rybchenko 
1026ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "done");
1027ba641f20SAndrew Rybchenko 	return 0;
1028ba641f20SAndrew Rybchenko 
1029dd45b880SAndrew Rybchenko fail_sriov_vswitch_create:
1030fdd7719eSIvan Ilchenko 	sfc_sw_xstats_close(sa);
1031fdd7719eSIvan Ilchenko 
1032fdd7719eSIvan Ilchenko fail_sw_xstats_init:
1033dd45b880SAndrew Rybchenko 	sfc_flow_fini(sa);
103452e80b1bSIgor Romanov 	sfc_repr_proxy_detach(sa);
103552e80b1bSIgor Romanov 
103652e80b1bSIgor Romanov fail_repr_proxy_attach:
1037c8617ddaSIgor Romanov 	sfc_mae_switchdev_fini(sa);
1038c8617ddaSIgor Romanov 
1039c8617ddaSIgor Romanov fail_mae_switchdev_init:
1040*bc712f1cSDenis Pryazhennikov 	sfc_tbls_detach(sa);
1041*bc712f1cSDenis Pryazhennikov 
1042*bc712f1cSDenis Pryazhennikov fail_tables_attach:
104302b234adSIvan Malov 	sfc_mae_detach(sa);
104402b234adSIvan Malov 
104502b234adSIvan Malov fail_mae_attach:
1046983ce116SIgor Romanov 	sfc_mae_counter_rxq_detach(sa);
1047983ce116SIgor Romanov 
1048983ce116SIgor Romanov fail_mae_counter_rxq_attach:
1049dd45b880SAndrew Rybchenko 	sfc_filter_detach(sa);
1050dd45b880SAndrew Rybchenko 
1051791f57acSAndrew Rybchenko fail_filter_attach:
10526da67e70SIvan Malov 	sfc_flow_rss_detach(sa);
10536da67e70SIvan Malov 
10546da67e70SIvan Malov fail_flow_rss_attach:
105501764b20SIvan Malov 	sfc_rss_detach(sa);
105601764b20SIvan Malov 
105701764b20SIvan Malov fail_rss_attach:
1058c577a525SAndrew Rybchenko 	sfc_port_detach(sa);
1059c577a525SAndrew Rybchenko 
1060c577a525SAndrew Rybchenko fail_port_attach:
106147995190SAndrew Rybchenko 	sfc_ev_detach(sa);
106247995190SAndrew Rybchenko 
106347995190SAndrew Rybchenko fail_ev_attach:
10644ec1fc3bSIvan Malov 	sfc_intr_detach(sa);
10654ec1fc3bSIvan Malov 
106606bc1977SAndrew Rybchenko fail_intr_attach:
10674ec1fc3bSIvan Malov 	efx_nic_fini(sa->nic);
10684ec1fc3bSIvan Malov 
106991831d40SAndrew Rybchenko fail_estimate_rsrc_limits:
107036c35355SAndrew Rybchenko fail_tunnel_init:
107136c35355SAndrew Rybchenko 	efx_tunnel_fini(sa->nic);
1072dd45b880SAndrew Rybchenko 	sfc_sriov_detach(sa);
107336c35355SAndrew Rybchenko 
1074dd45b880SAndrew Rybchenko fail_sriov_attach:
1075ba641f20SAndrew Rybchenko fail_nic_reset:
1076329472d4SAndrew Rybchenko 
1077329472d4SAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
1078329472d4SAndrew Rybchenko 	return rc;
1079329472d4SAndrew Rybchenko }
1080329472d4SAndrew Rybchenko 
1081329472d4SAndrew Rybchenko void
1082c377f1adSIgor Romanov sfc_pre_detach(struct sfc_adapter *sa)
1083c377f1adSIgor Romanov {
1084c377f1adSIgor Romanov 	sfc_log_init(sa, "entry");
1085c377f1adSIgor Romanov 
1086c377f1adSIgor Romanov 	SFC_ASSERT(!sfc_adapter_is_locked(sa));
1087c377f1adSIgor Romanov 
1088c377f1adSIgor Romanov 	sfc_repr_proxy_pre_detach(sa);
1089c377f1adSIgor Romanov 
1090c377f1adSIgor Romanov 	sfc_log_init(sa, "done");
1091c377f1adSIgor Romanov }
1092c377f1adSIgor Romanov 
1093c377f1adSIgor Romanov void
1094329472d4SAndrew Rybchenko sfc_detach(struct sfc_adapter *sa)
1095329472d4SAndrew Rybchenko {
1096329472d4SAndrew Rybchenko 	sfc_log_init(sa, "entry");
1097329472d4SAndrew Rybchenko 
1098329472d4SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
1099329472d4SAndrew Rybchenko 
1100dd45b880SAndrew Rybchenko 	sfc_sriov_vswitch_destroy(sa);
1101dd45b880SAndrew Rybchenko 
1102329472d4SAndrew Rybchenko 	sfc_flow_fini(sa);
1103329472d4SAndrew Rybchenko 
110452e80b1bSIgor Romanov 	sfc_repr_proxy_detach(sa);
1105c8617ddaSIgor Romanov 	sfc_mae_switchdev_fini(sa);
1106*bc712f1cSDenis Pryazhennikov 	sfc_tbls_detach(sa);
110702b234adSIvan Malov 	sfc_mae_detach(sa);
1108983ce116SIgor Romanov 	sfc_mae_counter_rxq_detach(sa);
1109329472d4SAndrew Rybchenko 	sfc_filter_detach(sa);
11106da67e70SIvan Malov 	sfc_flow_rss_detach(sa);
111101764b20SIvan Malov 	sfc_rss_detach(sa);
1112c577a525SAndrew Rybchenko 	sfc_port_detach(sa);
111347995190SAndrew Rybchenko 	sfc_ev_detach(sa);
1114329472d4SAndrew Rybchenko 	sfc_intr_detach(sa);
111536c35355SAndrew Rybchenko 	efx_tunnel_fini(sa->nic);
1116dd45b880SAndrew Rybchenko 	sfc_sriov_detach(sa);
1117329472d4SAndrew Rybchenko 
1118ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_UNINITIALIZED;
1119329472d4SAndrew Rybchenko }
1120329472d4SAndrew Rybchenko 
11219e7fc8b8SRoman Zhukov static int
11229e7fc8b8SRoman Zhukov sfc_kvarg_fv_variant_handler(__rte_unused const char *key,
11239e7fc8b8SRoman Zhukov 			     const char *value_str, void *opaque)
11249e7fc8b8SRoman Zhukov {
11259e7fc8b8SRoman Zhukov 	uint32_t *value = opaque;
11269e7fc8b8SRoman Zhukov 
11279e7fc8b8SRoman Zhukov 	if (strcasecmp(value_str, SFC_KVARG_FW_VARIANT_DONT_CARE) == 0)
11289e7fc8b8SRoman Zhukov 		*value = EFX_FW_VARIANT_DONT_CARE;
11299e7fc8b8SRoman Zhukov 	else if (strcasecmp(value_str, SFC_KVARG_FW_VARIANT_FULL_FEATURED) == 0)
11309e7fc8b8SRoman Zhukov 		*value = EFX_FW_VARIANT_FULL_FEATURED;
11319e7fc8b8SRoman Zhukov 	else if (strcasecmp(value_str, SFC_KVARG_FW_VARIANT_LOW_LATENCY) == 0)
11329e7fc8b8SRoman Zhukov 		*value = EFX_FW_VARIANT_LOW_LATENCY;
11339e7fc8b8SRoman Zhukov 	else if (strcasecmp(value_str, SFC_KVARG_FW_VARIANT_PACKED_STREAM) == 0)
11349e7fc8b8SRoman Zhukov 		*value = EFX_FW_VARIANT_PACKED_STREAM;
11356e899accSAndrew Rybchenko 	else if (strcasecmp(value_str, SFC_KVARG_FW_VARIANT_DPDK) == 0)
11366e899accSAndrew Rybchenko 		*value = EFX_FW_VARIANT_DPDK;
11379e7fc8b8SRoman Zhukov 	else
11389e7fc8b8SRoman Zhukov 		return -EINVAL;
11399e7fc8b8SRoman Zhukov 
11409e7fc8b8SRoman Zhukov 	return 0;
11419e7fc8b8SRoman Zhukov }
11429e7fc8b8SRoman Zhukov 
11439e7fc8b8SRoman Zhukov static int
11449e7fc8b8SRoman Zhukov sfc_get_fw_variant(struct sfc_adapter *sa, efx_fw_variant_t *efv)
11459e7fc8b8SRoman Zhukov {
11469e7fc8b8SRoman Zhukov 	efx_nic_fw_info_t enfi;
11479e7fc8b8SRoman Zhukov 	int rc;
11489e7fc8b8SRoman Zhukov 
11499e7fc8b8SRoman Zhukov 	rc = efx_nic_get_fw_version(sa->nic, &enfi);
11509e7fc8b8SRoman Zhukov 	if (rc != 0)
11519e7fc8b8SRoman Zhukov 		return rc;
11529e7fc8b8SRoman Zhukov 	else if (!enfi.enfi_dpcpu_fw_ids_valid)
11539e7fc8b8SRoman Zhukov 		return ENOTSUP;
11549e7fc8b8SRoman Zhukov 
11559e7fc8b8SRoman Zhukov 	/*
11569e7fc8b8SRoman Zhukov 	 * Firmware variant can be uniquely identified by the RxDPCPU
11579e7fc8b8SRoman Zhukov 	 * firmware id
11589e7fc8b8SRoman Zhukov 	 */
11599e7fc8b8SRoman Zhukov 	switch (enfi.enfi_rx_dpcpu_fw_id) {
11609e7fc8b8SRoman Zhukov 	case EFX_RXDP_FULL_FEATURED_FW_ID:
11619e7fc8b8SRoman Zhukov 		*efv = EFX_FW_VARIANT_FULL_FEATURED;
11629e7fc8b8SRoman Zhukov 		break;
11639e7fc8b8SRoman Zhukov 
11649e7fc8b8SRoman Zhukov 	case EFX_RXDP_LOW_LATENCY_FW_ID:
11659e7fc8b8SRoman Zhukov 		*efv = EFX_FW_VARIANT_LOW_LATENCY;
11669e7fc8b8SRoman Zhukov 		break;
11679e7fc8b8SRoman Zhukov 
11689e7fc8b8SRoman Zhukov 	case EFX_RXDP_PACKED_STREAM_FW_ID:
11699e7fc8b8SRoman Zhukov 		*efv = EFX_FW_VARIANT_PACKED_STREAM;
11709e7fc8b8SRoman Zhukov 		break;
11719e7fc8b8SRoman Zhukov 
11726e899accSAndrew Rybchenko 	case EFX_RXDP_DPDK_FW_ID:
11736e899accSAndrew Rybchenko 		*efv = EFX_FW_VARIANT_DPDK;
11746e899accSAndrew Rybchenko 		break;
11756e899accSAndrew Rybchenko 
11769e7fc8b8SRoman Zhukov 	default:
11779e7fc8b8SRoman Zhukov 		/*
11789e7fc8b8SRoman Zhukov 		 * Other firmware variants are not considered, since they are
11799e7fc8b8SRoman Zhukov 		 * not supported in the device parameters
11809e7fc8b8SRoman Zhukov 		 */
11819e7fc8b8SRoman Zhukov 		*efv = EFX_FW_VARIANT_DONT_CARE;
11829e7fc8b8SRoman Zhukov 		break;
11839e7fc8b8SRoman Zhukov 	}
11849e7fc8b8SRoman Zhukov 
11859e7fc8b8SRoman Zhukov 	return 0;
11869e7fc8b8SRoman Zhukov }
11879e7fc8b8SRoman Zhukov 
11889e7fc8b8SRoman Zhukov static const char *
11899e7fc8b8SRoman Zhukov sfc_fw_variant2str(efx_fw_variant_t efv)
11909e7fc8b8SRoman Zhukov {
11919e7fc8b8SRoman Zhukov 	switch (efv) {
11929e7fc8b8SRoman Zhukov 	case EFX_RXDP_FULL_FEATURED_FW_ID:
11939e7fc8b8SRoman Zhukov 		return SFC_KVARG_FW_VARIANT_FULL_FEATURED;
11949e7fc8b8SRoman Zhukov 	case EFX_RXDP_LOW_LATENCY_FW_ID:
11959e7fc8b8SRoman Zhukov 		return SFC_KVARG_FW_VARIANT_LOW_LATENCY;
11969e7fc8b8SRoman Zhukov 	case EFX_RXDP_PACKED_STREAM_FW_ID:
11979e7fc8b8SRoman Zhukov 		return SFC_KVARG_FW_VARIANT_PACKED_STREAM;
11986e899accSAndrew Rybchenko 	case EFX_RXDP_DPDK_FW_ID:
11996e899accSAndrew Rybchenko 		return SFC_KVARG_FW_VARIANT_DPDK;
12009e7fc8b8SRoman Zhukov 	default:
12019e7fc8b8SRoman Zhukov 		return "unknown";
12029e7fc8b8SRoman Zhukov 	}
12039e7fc8b8SRoman Zhukov }
12049e7fc8b8SRoman Zhukov 
12059e7fc8b8SRoman Zhukov static int
12065a1ae82dSAndrew Rybchenko sfc_kvarg_rxd_wait_timeout_ns(struct sfc_adapter *sa)
12075a1ae82dSAndrew Rybchenko {
12085a1ae82dSAndrew Rybchenko 	int rc;
12095a1ae82dSAndrew Rybchenko 	long value;
12105a1ae82dSAndrew Rybchenko 
12115a1ae82dSAndrew Rybchenko 	value = SFC_RXD_WAIT_TIMEOUT_NS_DEF;
12125a1ae82dSAndrew Rybchenko 
12135a1ae82dSAndrew Rybchenko 	rc = sfc_kvargs_process(sa, SFC_KVARG_RXD_WAIT_TIMEOUT_NS,
12145a1ae82dSAndrew Rybchenko 				sfc_kvarg_long_handler, &value);
12155a1ae82dSAndrew Rybchenko 	if (rc != 0)
12165a1ae82dSAndrew Rybchenko 		return rc;
12175a1ae82dSAndrew Rybchenko 
12185a1ae82dSAndrew Rybchenko 	if (value < 0 ||
12195a1ae82dSAndrew Rybchenko 	    (unsigned long)value > EFX_RXQ_ES_SUPER_BUFFER_HOL_BLOCK_MAX) {
12205a1ae82dSAndrew Rybchenko 		sfc_err(sa, "wrong '" SFC_KVARG_RXD_WAIT_TIMEOUT_NS "' "
12215a1ae82dSAndrew Rybchenko 			    "was set (%ld);", value);
12225a1ae82dSAndrew Rybchenko 		sfc_err(sa, "it must not be less than 0 or greater than %u",
12235a1ae82dSAndrew Rybchenko 			    EFX_RXQ_ES_SUPER_BUFFER_HOL_BLOCK_MAX);
12245a1ae82dSAndrew Rybchenko 		return EINVAL;
12255a1ae82dSAndrew Rybchenko 	}
12265a1ae82dSAndrew Rybchenko 
12275a1ae82dSAndrew Rybchenko 	sa->rxd_wait_timeout_ns = value;
12285a1ae82dSAndrew Rybchenko 	return 0;
12295a1ae82dSAndrew Rybchenko }
12305a1ae82dSAndrew Rybchenko 
12315a1ae82dSAndrew Rybchenko static int
12329e7fc8b8SRoman Zhukov sfc_nic_probe(struct sfc_adapter *sa)
12339e7fc8b8SRoman Zhukov {
12349e7fc8b8SRoman Zhukov 	efx_nic_t *enp = sa->nic;
12359e7fc8b8SRoman Zhukov 	efx_fw_variant_t preferred_efv;
12369e7fc8b8SRoman Zhukov 	efx_fw_variant_t efv;
12379e7fc8b8SRoman Zhukov 	int rc;
12389e7fc8b8SRoman Zhukov 
12399e7fc8b8SRoman Zhukov 	preferred_efv = EFX_FW_VARIANT_DONT_CARE;
12409e7fc8b8SRoman Zhukov 	rc = sfc_kvargs_process(sa, SFC_KVARG_FW_VARIANT,
12419e7fc8b8SRoman Zhukov 				sfc_kvarg_fv_variant_handler,
12429e7fc8b8SRoman Zhukov 				&preferred_efv);
12439e7fc8b8SRoman Zhukov 	if (rc != 0) {
12449e7fc8b8SRoman Zhukov 		sfc_err(sa, "invalid %s parameter value", SFC_KVARG_FW_VARIANT);
12459e7fc8b8SRoman Zhukov 		return rc;
12469e7fc8b8SRoman Zhukov 	}
12479e7fc8b8SRoman Zhukov 
12485a1ae82dSAndrew Rybchenko 	rc = sfc_kvarg_rxd_wait_timeout_ns(sa);
12495a1ae82dSAndrew Rybchenko 	if (rc != 0)
12505a1ae82dSAndrew Rybchenko 		return rc;
12515a1ae82dSAndrew Rybchenko 
12529e7fc8b8SRoman Zhukov 	rc = efx_nic_probe(enp, preferred_efv);
12539e7fc8b8SRoman Zhukov 	if (rc == EACCES) {
12549e7fc8b8SRoman Zhukov 		/* Unprivileged functions cannot set FW variant */
12559e7fc8b8SRoman Zhukov 		rc = efx_nic_probe(enp, EFX_FW_VARIANT_DONT_CARE);
12569e7fc8b8SRoman Zhukov 	}
12579e7fc8b8SRoman Zhukov 	if (rc != 0)
12589e7fc8b8SRoman Zhukov 		return rc;
12599e7fc8b8SRoman Zhukov 
12609e7fc8b8SRoman Zhukov 	rc = sfc_get_fw_variant(sa, &efv);
12619e7fc8b8SRoman Zhukov 	if (rc == ENOTSUP) {
12629e7fc8b8SRoman Zhukov 		sfc_warn(sa, "FW variant can not be obtained");
12639e7fc8b8SRoman Zhukov 		return 0;
12649e7fc8b8SRoman Zhukov 	}
12659e7fc8b8SRoman Zhukov 	if (rc != 0)
12669e7fc8b8SRoman Zhukov 		return rc;
12679e7fc8b8SRoman Zhukov 
12689e7fc8b8SRoman Zhukov 	/* Check that firmware variant was changed to the requested one */
12699e7fc8b8SRoman Zhukov 	if (preferred_efv != EFX_FW_VARIANT_DONT_CARE && preferred_efv != efv) {
12709e7fc8b8SRoman Zhukov 		sfc_warn(sa, "FW variant has not changed to the requested %s",
12719e7fc8b8SRoman Zhukov 			 sfc_fw_variant2str(preferred_efv));
12729e7fc8b8SRoman Zhukov 	}
12739e7fc8b8SRoman Zhukov 
12749e7fc8b8SRoman Zhukov 	sfc_notice(sa, "running FW variant is %s", sfc_fw_variant2str(efv));
12759e7fc8b8SRoman Zhukov 
12769e7fc8b8SRoman Zhukov 	return 0;
12779e7fc8b8SRoman Zhukov }
12789e7fc8b8SRoman Zhukov 
1279329472d4SAndrew Rybchenko int
1280329472d4SAndrew Rybchenko sfc_probe(struct sfc_adapter *sa)
1281329472d4SAndrew Rybchenko {
1282fe4dad21SIgor Romanov 	efx_bar_region_t mem_ebrp;
12837178fbdcSVijay Kumar Srivastava 	struct rte_eth_dev *eth_dev = sa->eth_dev;
12847178fbdcSVijay Kumar Srivastava 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
1285329472d4SAndrew Rybchenko 	efx_nic_t *enp;
1286329472d4SAndrew Rybchenko 	int rc;
1287329472d4SAndrew Rybchenko 
1288329472d4SAndrew Rybchenko 	sfc_log_init(sa, "entry");
1289329472d4SAndrew Rybchenko 
1290329472d4SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
1291329472d4SAndrew Rybchenko 
1292329472d4SAndrew Rybchenko 	sa->socket_id = rte_socket_id();
1293e77f9f19SAndrew Rybchenko 	rte_atomic32_init(&sa->restart_required);
1294329472d4SAndrew Rybchenko 
1295329472d4SAndrew Rybchenko 	sfc_log_init(sa, "get family");
12967178fbdcSVijay Kumar Srivastava 	rc = sfc_efx_family(pci_dev, &mem_ebrp, &sa->family);
12977178fbdcSVijay Kumar Srivastava 
1298329472d4SAndrew Rybchenko 	if (rc != 0)
1299329472d4SAndrew Rybchenko 		goto fail_family;
1300fe4dad21SIgor Romanov 	sfc_log_init(sa,
1301fe4dad21SIgor Romanov 		     "family is %u, membar is %u, function control window offset is %lu",
1302fe4dad21SIgor Romanov 		     sa->family, mem_ebrp.ebr_index, mem_ebrp.ebr_offset);
1303e434de5dSAndy Moreton 
1304e434de5dSAndy Moreton 	sfc_log_init(sa, "init mem bar");
1305fe4dad21SIgor Romanov 	rc = sfc_mem_bar_init(sa, &mem_ebrp);
1306e434de5dSAndy Moreton 	if (rc != 0)
1307e434de5dSAndy Moreton 		goto fail_mem_bar_init;
1308329472d4SAndrew Rybchenko 
1309329472d4SAndrew Rybchenko 	sfc_log_init(sa, "create nic");
1310329472d4SAndrew Rybchenko 	rte_spinlock_init(&sa->nic_lock);
1311329472d4SAndrew Rybchenko 	rc = efx_nic_create(sa->family, (efsys_identifier_t *)sa,
1312fe4dad21SIgor Romanov 			    &sa->mem_bar, mem_ebrp.ebr_offset,
1313341bd4e0SIgor Romanov 			    &sa->nic_lock, &enp);
1314329472d4SAndrew Rybchenko 	if (rc != 0)
1315329472d4SAndrew Rybchenko 		goto fail_nic_create;
1316329472d4SAndrew Rybchenko 	sa->nic = enp;
1317329472d4SAndrew Rybchenko 
1318329472d4SAndrew Rybchenko 	rc = sfc_mcdi_init(sa);
1319329472d4SAndrew Rybchenko 	if (rc != 0)
1320329472d4SAndrew Rybchenko 		goto fail_mcdi_init;
1321329472d4SAndrew Rybchenko 
1322329472d4SAndrew Rybchenko 	sfc_log_init(sa, "probe nic");
13239e7fc8b8SRoman Zhukov 	rc = sfc_nic_probe(sa);
1324329472d4SAndrew Rybchenko 	if (rc != 0)
1325329472d4SAndrew Rybchenko 		goto fail_nic_probe;
1326329472d4SAndrew Rybchenko 
1327329472d4SAndrew Rybchenko 	sfc_log_init(sa, "done");
1328329472d4SAndrew Rybchenko 	return 0;
1329ba641f20SAndrew Rybchenko 
1330ba641f20SAndrew Rybchenko fail_nic_probe:
1331ba641f20SAndrew Rybchenko 	sfc_mcdi_fini(sa);
1332ba641f20SAndrew Rybchenko 
1333ba641f20SAndrew Rybchenko fail_mcdi_init:
1334ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "destroy nic");
1335ba641f20SAndrew Rybchenko 	sa->nic = NULL;
1336ba641f20SAndrew Rybchenko 	efx_nic_destroy(enp);
1337ba641f20SAndrew Rybchenko 
1338ba641f20SAndrew Rybchenko fail_nic_create:
1339ba641f20SAndrew Rybchenko 	sfc_mem_bar_fini(sa);
1340ba641f20SAndrew Rybchenko 
1341ba641f20SAndrew Rybchenko fail_mem_bar_init:
1342e434de5dSAndy Moreton fail_family:
1343ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
1344ba641f20SAndrew Rybchenko 	return rc;
1345ba641f20SAndrew Rybchenko }
1346ba641f20SAndrew Rybchenko 
1347ba641f20SAndrew Rybchenko void
1348329472d4SAndrew Rybchenko sfc_unprobe(struct sfc_adapter *sa)
1349ba641f20SAndrew Rybchenko {
1350ba641f20SAndrew Rybchenko 	efx_nic_t *enp = sa->nic;
1351ba641f20SAndrew Rybchenko 
1352ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "entry");
1353ba641f20SAndrew Rybchenko 
1354ba641f20SAndrew Rybchenko 	SFC_ASSERT(sfc_adapter_is_locked(sa));
1355ba641f20SAndrew Rybchenko 
1356ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "unprobe nic");
1357ba641f20SAndrew Rybchenko 	efx_nic_unprobe(enp);
1358ba641f20SAndrew Rybchenko 
1359ba641f20SAndrew Rybchenko 	sfc_mcdi_fini(sa);
1360ba641f20SAndrew Rybchenko 
1361e77f9f19SAndrew Rybchenko 	/*
1362e77f9f19SAndrew Rybchenko 	 * Make sure there is no pending alarm to restart since we are
1363e77f9f19SAndrew Rybchenko 	 * going to free device private which is passed as the callback
1364e77f9f19SAndrew Rybchenko 	 * opaque data. A new alarm cannot be scheduled since MCDI is
1365e77f9f19SAndrew Rybchenko 	 * shut down.
1366e77f9f19SAndrew Rybchenko 	 */
1367e77f9f19SAndrew Rybchenko 	rte_eal_alarm_cancel(sfc_restart_if_required, sa);
1368e77f9f19SAndrew Rybchenko 
136926706314SViacheslav Galaktionov 	sfc_mae_clear_switch_port(sa->mae.switch_domain_id,
137026706314SViacheslav Galaktionov 				  sa->mae.switch_port_id);
137126706314SViacheslav Galaktionov 
1372ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "destroy nic");
1373ba641f20SAndrew Rybchenko 	sa->nic = NULL;
1374ba641f20SAndrew Rybchenko 	efx_nic_destroy(enp);
1375ba641f20SAndrew Rybchenko 
1376ba641f20SAndrew Rybchenko 	sfc_mem_bar_fini(sa);
1377ba641f20SAndrew Rybchenko 
1378a9825ccfSRoman Zhukov 	sfc_flow_fini(sa);
1379ac478689SIgor Romanov 	sa->state = SFC_ETHDEV_UNINITIALIZED;
1380ba641f20SAndrew Rybchenko }
1381dad99d92SIvan Malov 
1382dad99d92SIvan Malov uint32_t
1383e2c3639aSAndrew Rybchenko sfc_register_logtype(const struct rte_pci_addr *pci_addr,
1384e2c3639aSAndrew Rybchenko 		     const char *lt_prefix_str, uint32_t ll_default)
1385dad99d92SIvan Malov {
1386dad99d92SIvan Malov 	size_t lt_prefix_str_size = strlen(lt_prefix_str);
1387dad99d92SIvan Malov 	size_t lt_str_size_max;
1388dad99d92SIvan Malov 	char *lt_str = NULL;
1389dad99d92SIvan Malov 	int ret;
1390dad99d92SIvan Malov 
1391dad99d92SIvan Malov 	if (SIZE_MAX - PCI_PRI_STR_SIZE - 1 > lt_prefix_str_size) {
1392dad99d92SIvan Malov 		++lt_prefix_str_size; /* Reserve space for prefix separator */
1393dad99d92SIvan Malov 		lt_str_size_max = lt_prefix_str_size + PCI_PRI_STR_SIZE + 1;
1394dad99d92SIvan Malov 	} else {
139542c807feSStephen Hemminger 		return sfc_logtype_driver;
1396dad99d92SIvan Malov 	}
1397dad99d92SIvan Malov 
1398dad99d92SIvan Malov 	lt_str = rte_zmalloc("logtype_str", lt_str_size_max, 0);
1399dad99d92SIvan Malov 	if (lt_str == NULL)
140042c807feSStephen Hemminger 		return sfc_logtype_driver;
1401dad99d92SIvan Malov 
1402dad99d92SIvan Malov 	strncpy(lt_str, lt_prefix_str, lt_prefix_str_size);
1403dad99d92SIvan Malov 	lt_str[lt_prefix_str_size - 1] = '.';
1404e2c3639aSAndrew Rybchenko 	rte_pci_device_name(pci_addr, lt_str + lt_prefix_str_size,
1405dad99d92SIvan Malov 			    lt_str_size_max - lt_prefix_str_size);
1406dad99d92SIvan Malov 	lt_str[lt_str_size_max - 1] = '\0';
1407dad99d92SIvan Malov 
1408dad99d92SIvan Malov 	ret = rte_log_register_type_and_pick_level(lt_str, ll_default);
1409dad99d92SIvan Malov 	rte_free(lt_str);
1410dad99d92SIvan Malov 
141142c807feSStephen Hemminger 	if (ret < 0)
141242c807feSStephen Hemminger 		return sfc_logtype_driver;
141342c807feSStephen Hemminger 
141442c807feSStephen Hemminger 	return ret;
1415dad99d92SIvan Malov }
1416e86b48aaSIvan Malov 
1417e86b48aaSIvan Malov struct sfc_hw_switch_id {
1418e86b48aaSIvan Malov 	char	board_sn[RTE_SIZEOF_FIELD(efx_nic_board_info_t, enbi_serial)];
1419e86b48aaSIvan Malov };
1420e86b48aaSIvan Malov 
1421e86b48aaSIvan Malov int
1422e86b48aaSIvan Malov sfc_hw_switch_id_init(struct sfc_adapter *sa,
1423e86b48aaSIvan Malov 		      struct sfc_hw_switch_id **idp)
1424e86b48aaSIvan Malov {
1425e86b48aaSIvan Malov 	efx_nic_board_info_t board_info;
1426e86b48aaSIvan Malov 	struct sfc_hw_switch_id *id;
1427e86b48aaSIvan Malov 	int rc;
1428e86b48aaSIvan Malov 
1429e86b48aaSIvan Malov 	if (idp == NULL)
1430e86b48aaSIvan Malov 		return EINVAL;
1431e86b48aaSIvan Malov 
1432e86b48aaSIvan Malov 	id = rte_zmalloc("sfc_hw_switch_id", sizeof(*id), 0);
1433e86b48aaSIvan Malov 	if (id == NULL)
1434e86b48aaSIvan Malov 		return ENOMEM;
1435e86b48aaSIvan Malov 
1436e86b48aaSIvan Malov 	rc = efx_nic_get_board_info(sa->nic, &board_info);
1437e86b48aaSIvan Malov 	if (rc != 0)
1438e86b48aaSIvan Malov 		return rc;
1439e86b48aaSIvan Malov 
1440e86b48aaSIvan Malov 	memcpy(id->board_sn, board_info.enbi_serial, sizeof(id->board_sn));
1441e86b48aaSIvan Malov 
1442e86b48aaSIvan Malov 	*idp = id;
1443e86b48aaSIvan Malov 
1444e86b48aaSIvan Malov 	return 0;
1445e86b48aaSIvan Malov }
1446e86b48aaSIvan Malov 
1447e86b48aaSIvan Malov void
1448e86b48aaSIvan Malov sfc_hw_switch_id_fini(__rte_unused struct sfc_adapter *sa,
1449e86b48aaSIvan Malov 		      struct sfc_hw_switch_id *id)
1450e86b48aaSIvan Malov {
1451e86b48aaSIvan Malov 	rte_free(id);
1452e86b48aaSIvan Malov }
1453e86b48aaSIvan Malov 
1454e86b48aaSIvan Malov bool
1455e86b48aaSIvan Malov sfc_hw_switch_ids_equal(const struct sfc_hw_switch_id *left,
1456e86b48aaSIvan Malov 			const struct sfc_hw_switch_id *right)
1457e86b48aaSIvan Malov {
1458380f3552SIvan Malov 	return strncmp(left->board_sn, right->board_sn,
1459380f3552SIvan Malov 		       sizeof(left->board_sn)) == 0;
1460e86b48aaSIvan Malov }
1461