xref: /dpdk/drivers/net/nfp/nfp_ethdev.c (revision 4dcbf32ffefd84dbb5924de3b2c6dd517f7809c8)
1646ea79cSHeinrich Kuhn /* SPDX-License-Identifier: BSD-3-Clause
2646ea79cSHeinrich Kuhn  * Copyright (c) 2014-2021 Netronome Systems, Inc.
3646ea79cSHeinrich Kuhn  * All rights reserved.
4646ea79cSHeinrich Kuhn  *
5646ea79cSHeinrich Kuhn  * Small portions derived from code Copyright(c) 2010-2015 Intel Corporation.
6646ea79cSHeinrich Kuhn  */
7646ea79cSHeinrich Kuhn 
88ba461d1SPeng Zhang #include <unistd.h>
98ba461d1SPeng Zhang 
105a95b024SChaoyong He #include <eal_firmware.h>
11851f03e1SHeinrich Kuhn #include <rte_alarm.h>
12b301fd73SPeng Zhang #include <rte_kvargs.h>
1320086cb8SPeng Zhang #include <rte_pci.h>
14646ea79cSHeinrich Kuhn 
155a95b024SChaoyong He #include "flower/nfp_flower.h"
165a95b024SChaoyong He #include "nfd3/nfp_nfd3.h"
175a95b024SChaoyong He #include "nfdk/nfp_nfdk.h"
18646ea79cSHeinrich Kuhn #include "nfpcore/nfp_cpp.h"
19a2bc299dSPeng Zhang #include "nfpcore/nfp_elf.h"
20646ea79cSHeinrich Kuhn #include "nfpcore/nfp_hwinfo.h"
21646ea79cSHeinrich Kuhn #include "nfpcore/nfp_rtsym.h"
22646ea79cSHeinrich Kuhn #include "nfpcore/nfp_nsp.h"
23796f1aecSChaoyong He #include "nfpcore/nfp6000_pcie.h"
248ba461d1SPeng Zhang #include "nfpcore/nfp_resource.h"
256b4273a0SLong Wu #include "nfpcore/nfp_sync.h"
26646ea79cSHeinrich Kuhn 
27646ea79cSHeinrich Kuhn #include "nfp_cpp_bridge.h"
2854713740SChang Miao #include "nfp_ipsec.h"
295a95b024SChaoyong He #include "nfp_logs.h"
308153bc6fSChaoyong He #include "nfp_net_flow.h"
31fb6befdfSLong Wu #include "nfp_rxtx_vec.h"
32b1880421SChaoyong He 
33c7a6970fSZerun Fu /* 64-bit per app capabilities */
34c7a6970fSZerun Fu #define NFP_NET_APP_CAP_SP_INDIFF       RTE_BIT64(0) /* Indifferent to port speed */
35c7a6970fSZerun Fu 
36d505ee1dSChaoyong He #define NFP_PF_DRIVER_NAME net_nfp_pf
37b301fd73SPeng Zhang #define NFP_PF_FORCE_RELOAD_FW   "force_reload_fw"
38c50bf4f0SLong Wu #define NFP_CPP_SERVICE_ENABLE   "cpp_service_enable"
39bb24eb38SPeng Zhang #define NFP_QUEUE_PER_VF     1
40b301fd73SPeng Zhang 
416484c847SChaoyong He struct nfp_net_init {
426484c847SChaoyong He 	/** Sequential physical port number, only valid for CoreNIC firmware */
436484c847SChaoyong He 	uint8_t idx;
446484c847SChaoyong He 
456484c847SChaoyong He 	/** Internal port number as seen from NFP */
466484c847SChaoyong He 	uint8_t nfp_idx;
476484c847SChaoyong He 
486484c847SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
496484c847SChaoyong He };
506484c847SChaoyong He 
51b301fd73SPeng Zhang static int
52b301fd73SPeng Zhang nfp_devarg_handle_int(const char *key,
53b301fd73SPeng Zhang 		const char *value,
54b301fd73SPeng Zhang 		void *extra_args)
55b301fd73SPeng Zhang {
56b301fd73SPeng Zhang 	char *end_ptr;
57b301fd73SPeng Zhang 	uint64_t *num = extra_args;
58b301fd73SPeng Zhang 
59b301fd73SPeng Zhang 	if (value == NULL)
60b301fd73SPeng Zhang 		return -EPERM;
61b301fd73SPeng Zhang 
62b301fd73SPeng Zhang 	*num = strtoul(value, &end_ptr, 10);
63b301fd73SPeng Zhang 	if (*num == ULONG_MAX) {
64b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "%s: '%s' is not a valid param.", key, value);
65b301fd73SPeng Zhang 		return -ERANGE;
66b301fd73SPeng Zhang 	} else if (value == end_ptr) {
67b301fd73SPeng Zhang 		return -EPERM;
68b301fd73SPeng Zhang 	}
69b301fd73SPeng Zhang 
70b301fd73SPeng Zhang 	return 0;
71b301fd73SPeng Zhang }
72b301fd73SPeng Zhang 
731a114cd0SLong Wu static int
741a114cd0SLong Wu nfp_devarg_parse_bool_para(struct rte_kvargs *kvlist,
751a114cd0SLong Wu 		const char *key_match,
761a114cd0SLong Wu 		bool *value_ret)
77b301fd73SPeng Zhang {
78b301fd73SPeng Zhang 	int ret;
791a114cd0SLong Wu 	uint32_t count;
80b301fd73SPeng Zhang 	uint64_t value;
81b301fd73SPeng Zhang 
821a114cd0SLong Wu 	count = rte_kvargs_count(kvlist, key_match);
831a114cd0SLong Wu 	if (count == 0)
841a114cd0SLong Wu 		return 0;
85b301fd73SPeng Zhang 
861a114cd0SLong Wu 	if (count > 1) {
87b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Too much bool arguments: %s.", key_match);
881a114cd0SLong Wu 		return -EINVAL;
89b301fd73SPeng Zhang 	}
90b301fd73SPeng Zhang 
911a114cd0SLong Wu 	ret = rte_kvargs_process(kvlist, key_match, &nfp_devarg_handle_int, &value);
921a114cd0SLong Wu 	if (ret != 0)
931a114cd0SLong Wu 		return -EINVAL;
941a114cd0SLong Wu 
951a114cd0SLong Wu 	if (value == 1) {
961a114cd0SLong Wu 		*value_ret = true;
971a114cd0SLong Wu 	} else if (value == 0) {
981a114cd0SLong Wu 		*value_ret = false;
991a114cd0SLong Wu 	} else {
100b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "The param does not work, the format is %s=0/1.",
1011a114cd0SLong Wu 				key_match);
1021a114cd0SLong Wu 		return -EINVAL;
1031a114cd0SLong Wu 	}
1041a114cd0SLong Wu 
1051a114cd0SLong Wu 	return 0;
1061a114cd0SLong Wu }
1071a114cd0SLong Wu 
1081a114cd0SLong Wu static int
109b301fd73SPeng Zhang nfp_devargs_parse(struct nfp_devargs *nfp_devargs_param,
110b301fd73SPeng Zhang 		const struct rte_devargs *devargs)
111b301fd73SPeng Zhang {
1121a114cd0SLong Wu 	int ret;
113b301fd73SPeng Zhang 	struct rte_kvargs *kvlist;
114b301fd73SPeng Zhang 
115b301fd73SPeng Zhang 	if (devargs == NULL)
1161a114cd0SLong Wu 		return 0;
117b301fd73SPeng Zhang 
118b301fd73SPeng Zhang 	kvlist = rte_kvargs_parse(devargs->args, NULL);
119b301fd73SPeng Zhang 	if (kvlist == NULL)
1201a114cd0SLong Wu 		return -EINVAL;
121b301fd73SPeng Zhang 
1221a114cd0SLong Wu 	ret = nfp_devarg_parse_bool_para(kvlist, NFP_PF_FORCE_RELOAD_FW,
1231a114cd0SLong Wu 			&nfp_devargs_param->force_reload_fw);
1241a114cd0SLong Wu 	if (ret != 0)
1251a114cd0SLong Wu 		goto exit;
126b301fd73SPeng Zhang 
127c50bf4f0SLong Wu 	ret = nfp_devarg_parse_bool_para(kvlist, NFP_CPP_SERVICE_ENABLE,
128c50bf4f0SLong Wu 			&nfp_devargs_param->cpp_service_enable);
129c50bf4f0SLong Wu 	if (ret != 0)
130c50bf4f0SLong Wu 		goto exit;
131c50bf4f0SLong Wu 
1321a114cd0SLong Wu exit:
133b301fd73SPeng Zhang 	rte_kvargs_free(kvlist);
1341a114cd0SLong Wu 
1351a114cd0SLong Wu 	return ret;
136b301fd73SPeng Zhang }
137d505ee1dSChaoyong He 
138a243128bSChaoyong He static void
139f4d24fe9SChaoyong He nfp_net_pf_read_mac(struct nfp_app_fw_nic *app_fw_nic,
140a9fa1da7SChaoyong He 		uint16_t port,
141a9fa1da7SChaoyong He 		struct nfp_net_hw_priv *hw_priv)
142646ea79cSHeinrich Kuhn {
14349952141SChaoyong He 	struct nfp_net_hw *hw;
144646ea79cSHeinrich Kuhn 	struct nfp_eth_table *nfp_eth_table;
145646ea79cSHeinrich Kuhn 
146646ea79cSHeinrich Kuhn 	/* Grab a pointer to the correct physical port */
147968ec1c3SChaoyong He 	hw = app_fw_nic->ports[port];
148646ea79cSHeinrich Kuhn 
149ff9f5a56SChaoyong He 	nfp_eth_table = hw_priv->pf_dev->nfp_eth_table;
150646ea79cSHeinrich Kuhn 
151ef759759SChaoyong He 	rte_ether_addr_copy(&nfp_eth_table->ports[port].mac_addr, &hw->super.mac_addr);
152646ea79cSHeinrich Kuhn }
153646ea79cSHeinrich Kuhn 
154009f43d5SZerun Fu static uint32_t
155009f43d5SZerun Fu nfp_net_speed_bitmap2speed(uint32_t speeds_bitmap)
156009f43d5SZerun Fu {
157009f43d5SZerun Fu 	switch (speeds_bitmap) {
158009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M_HD:
159009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
160009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M:
161009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
162009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M_HD:
163009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
164009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M:
165009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
166009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_1G:
167009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_1G;
168009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_2_5G:
169009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_2_5G;
170009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_5G:
171009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_5G;
172009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10G:
173009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10G;
174009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_20G:
175009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_20G;
176009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_25G:
177009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_25G;
178009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_40G:
179009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_40G;
180009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_50G:
181009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_50G;
182009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_56G:
183009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_56G;
184009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100G:
185009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100G;
186009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_200G:
187009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_200G;
188009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_400G:
189009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_400G;
190009f43d5SZerun Fu 	default:
191009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_NONE;
192009f43d5SZerun Fu 	}
193009f43d5SZerun Fu }
194009f43d5SZerun Fu 
195009f43d5SZerun Fu static int
196009f43d5SZerun Fu nfp_net_nfp4000_speed_configure_check(uint16_t port_id,
197009f43d5SZerun Fu 		uint32_t configure_speed,
198009f43d5SZerun Fu 		struct nfp_eth_table *nfp_eth_table)
199009f43d5SZerun Fu {
200009f43d5SZerun Fu 	switch (port_id) {
201009f43d5SZerun Fu 	case 0:
202009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_25G &&
203009f43d5SZerun Fu 				nfp_eth_table->ports[1].speed == RTE_ETH_SPEED_NUM_10G) {
204009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
205009f43d5SZerun Fu 			return -ENOTSUP;
206009f43d5SZerun Fu 		}
207009f43d5SZerun Fu 		break;
208009f43d5SZerun Fu 	case 1:
209009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_10G &&
210009f43d5SZerun Fu 				nfp_eth_table->ports[0].speed == RTE_ETH_SPEED_NUM_25G) {
211009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
212009f43d5SZerun Fu 			return -ENOTSUP;
213009f43d5SZerun Fu 		}
214009f43d5SZerun Fu 		break;
215009f43d5SZerun Fu 	default:
216009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "The port id is invalid.");
217009f43d5SZerun Fu 		return -EINVAL;
218009f43d5SZerun Fu 	}
219009f43d5SZerun Fu 
220009f43d5SZerun Fu 	return 0;
221009f43d5SZerun Fu }
222009f43d5SZerun Fu 
223009f43d5SZerun Fu static int
2244ef9e4e6SZerun Fu nfp_net_speed_autoneg_set(struct nfp_net_hw_priv *hw_priv,
2254ef9e4e6SZerun Fu 		struct nfp_eth_table_port *eth_port)
2264ef9e4e6SZerun Fu {
2274ef9e4e6SZerun Fu 	int ret;
2284ef9e4e6SZerun Fu 	struct nfp_nsp *nsp;
2294ef9e4e6SZerun Fu 
2304ef9e4e6SZerun Fu 	nsp = nfp_eth_config_start(hw_priv->pf_dev->cpp, eth_port->index);
2314ef9e4e6SZerun Fu 	if (nsp == NULL) {
2324ef9e4e6SZerun Fu 		PMD_DRV_LOG(ERR, "Could not get NSP.");
2334ef9e4e6SZerun Fu 		return -EIO;
2344ef9e4e6SZerun Fu 	}
2354ef9e4e6SZerun Fu 
2364ef9e4e6SZerun Fu 	ret = nfp_eth_set_aneg(nsp, NFP_ANEG_AUTO);
2374ef9e4e6SZerun Fu 	if (ret != 0) {
2384ef9e4e6SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set ANEG enable.");
2394ef9e4e6SZerun Fu 		nfp_eth_config_cleanup_end(nsp);
2404ef9e4e6SZerun Fu 		return ret;
2414ef9e4e6SZerun Fu 	}
2424ef9e4e6SZerun Fu 
2434ef9e4e6SZerun Fu 	return nfp_eth_config_commit_end(nsp);
2444ef9e4e6SZerun Fu }
2454ef9e4e6SZerun Fu 
2464ef9e4e6SZerun Fu static int
2474ef9e4e6SZerun Fu nfp_net_speed_fixed_set(struct nfp_net_hw_priv *hw_priv,
2484ef9e4e6SZerun Fu 		struct nfp_eth_table_port *eth_port,
2494ef9e4e6SZerun Fu 		uint32_t configure_speed)
2504ef9e4e6SZerun Fu {
2514ef9e4e6SZerun Fu 	int ret;
2524ef9e4e6SZerun Fu 	struct nfp_nsp *nsp;
2534ef9e4e6SZerun Fu 
2544ef9e4e6SZerun Fu 	nsp = nfp_eth_config_start(hw_priv->pf_dev->cpp, eth_port->index);
2554ef9e4e6SZerun Fu 	if (nsp == NULL) {
2564ef9e4e6SZerun Fu 		PMD_DRV_LOG(ERR, "Could not get NSP.");
2574ef9e4e6SZerun Fu 		return -EIO;
2584ef9e4e6SZerun Fu 	}
2594ef9e4e6SZerun Fu 
2604ef9e4e6SZerun Fu 	ret = nfp_eth_set_aneg(nsp, NFP_ANEG_DISABLED);
2614ef9e4e6SZerun Fu 	if (ret != 0) {
2624ef9e4e6SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set ANEG disable.");
2634ef9e4e6SZerun Fu 		goto config_cleanup;
2644ef9e4e6SZerun Fu 	}
2654ef9e4e6SZerun Fu 
2664ef9e4e6SZerun Fu 	ret = nfp_eth_set_speed(nsp, configure_speed);
2674ef9e4e6SZerun Fu 	if (ret != 0) {
2684ef9e4e6SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set speed.");
2694ef9e4e6SZerun Fu 		goto config_cleanup;
2704ef9e4e6SZerun Fu 	}
2714ef9e4e6SZerun Fu 
2724ef9e4e6SZerun Fu 	return nfp_eth_config_commit_end(nsp);
2734ef9e4e6SZerun Fu 
2744ef9e4e6SZerun Fu config_cleanup:
2754ef9e4e6SZerun Fu 	nfp_eth_config_cleanup_end(nsp);
2764ef9e4e6SZerun Fu 
2774ef9e4e6SZerun Fu 	return ret;
2784ef9e4e6SZerun Fu }
2794ef9e4e6SZerun Fu 
2804ef9e4e6SZerun Fu static int
281ff9f5a56SChaoyong He nfp_net_speed_configure(struct rte_eth_dev *dev)
282009f43d5SZerun Fu {
283009f43d5SZerun Fu 	int ret;
284c33504deSQin Ke 	uint8_t idx;
285009f43d5SZerun Fu 	uint32_t speed_capa;
286009f43d5SZerun Fu 	uint32_t link_speeds;
287009f43d5SZerun Fu 	uint32_t configure_speed;
288009f43d5SZerun Fu 	struct nfp_eth_table_port *eth_port;
289009f43d5SZerun Fu 	struct nfp_eth_table *nfp_eth_table;
290ff9f5a56SChaoyong He 	struct nfp_net_hw *net_hw = dev->data->dev_private;
291ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv = dev->process_private;
292009f43d5SZerun Fu 
293c33504deSQin Ke 	idx = nfp_net_get_idx(dev);
294ff9f5a56SChaoyong He 	nfp_eth_table = hw_priv->pf_dev->nfp_eth_table;
295c33504deSQin Ke 	eth_port = &nfp_eth_table->ports[idx];
296009f43d5SZerun Fu 
297ff9f5a56SChaoyong He 	speed_capa = hw_priv->pf_dev->speed_capa;
298009f43d5SZerun Fu 	if (speed_capa == 0) {
299009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Speed_capa is invalid.");
300009f43d5SZerun Fu 		return -EINVAL;
301009f43d5SZerun Fu 	}
302009f43d5SZerun Fu 
303009f43d5SZerun Fu 	link_speeds = dev->data->dev_conf.link_speeds;
304009f43d5SZerun Fu 	configure_speed = nfp_net_speed_bitmap2speed(speed_capa & link_speeds);
305009f43d5SZerun Fu 	if (configure_speed == RTE_ETH_SPEED_NUM_NONE &&
306009f43d5SZerun Fu 			link_speeds != RTE_ETH_LINK_SPEED_AUTONEG) {
307009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Configured speed is invalid.");
308009f43d5SZerun Fu 		return -EINVAL;
309009f43d5SZerun Fu 	}
310009f43d5SZerun Fu 
311009f43d5SZerun Fu 	/* NFP4000 does not allow the port 0 25Gbps and port 1 10Gbps at the same time. */
312009f43d5SZerun Fu 	if (net_hw->device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) {
313c33504deSQin Ke 		ret = nfp_net_nfp4000_speed_configure_check(idx,
314009f43d5SZerun Fu 				configure_speed, nfp_eth_table);
315009f43d5SZerun Fu 		if (ret != 0) {
316009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to configure speed for NFP4000.");
317009f43d5SZerun Fu 			return ret;
318009f43d5SZerun Fu 		}
319009f43d5SZerun Fu 	}
320009f43d5SZerun Fu 
3214ef9e4e6SZerun Fu 	if (configure_speed == RTE_ETH_LINK_SPEED_AUTONEG) {
3224ef9e4e6SZerun Fu 		if (!eth_port->supp_aneg)
3234ef9e4e6SZerun Fu 			return 0;
324009f43d5SZerun Fu 
3254ef9e4e6SZerun Fu 		if (eth_port->aneg == NFP_ANEG_AUTO)
3264ef9e4e6SZerun Fu 			return 0;
3274ef9e4e6SZerun Fu 
3284ef9e4e6SZerun Fu 		ret = nfp_net_speed_autoneg_set(hw_priv, eth_port);
329009f43d5SZerun Fu 		if (ret != 0) {
3304ef9e4e6SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set speed autoneg.");
3314ef9e4e6SZerun Fu 			return ret;
332009f43d5SZerun Fu 		}
333009f43d5SZerun Fu 	} else {
3344ef9e4e6SZerun Fu 		if (eth_port->aneg == NFP_ANEG_DISABLED && configure_speed == eth_port->speed)
3354ef9e4e6SZerun Fu 			return 0;
3364ef9e4e6SZerun Fu 
3374ef9e4e6SZerun Fu 		ret = nfp_net_speed_fixed_set(hw_priv, eth_port, configure_speed);
338009f43d5SZerun Fu 		if (ret != 0) {
3394ef9e4e6SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set speed fixed.");
340009f43d5SZerun Fu 			return ret;
341009f43d5SZerun Fu 		}
3424ef9e4e6SZerun Fu 	}
3434ef9e4e6SZerun Fu 
344aaa57548SZerun Fu 	hw_priv->pf_dev->speed_updated = true;
345aaa57548SZerun Fu 
3464ef9e4e6SZerun Fu 	return 0;
3474ef9e4e6SZerun Fu }
348009f43d5SZerun Fu 
349646ea79cSHeinrich Kuhn static int
350646ea79cSHeinrich Kuhn nfp_net_start(struct rte_eth_dev *dev)
351646ea79cSHeinrich Kuhn {
35249952141SChaoyong He 	int ret;
35349952141SChaoyong He 	uint16_t i;
35472d1dea6SChaoyong He 	struct nfp_hw *hw;
35549952141SChaoyong He 	uint32_t new_ctrl;
35649952141SChaoyong He 	uint32_t update = 0;
3572e7c3612SQin Ke 	uint32_t cap_extend;
35849952141SChaoyong He 	uint32_t intr_vector;
35949952141SChaoyong He 	uint32_t ctrl_extend = 0;
36072d1dea6SChaoyong He 	struct nfp_net_hw *net_hw;
361646ea79cSHeinrich Kuhn 	struct nfp_pf_dev *pf_dev;
362646ea79cSHeinrich Kuhn 	struct rte_eth_rxmode *rxmode;
3635126a904SLong Wu 	struct rte_eth_txmode *txmode;
364ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
36549952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
36649952141SChaoyong He 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
36749952141SChaoyong He 	struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
368646ea79cSHeinrich Kuhn 
3699d723baaSChaoyong He 	net_hw = dev->data->dev_private;
370ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
371ff9f5a56SChaoyong He 	pf_dev = hw_priv->pf_dev;
372968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
37372d1dea6SChaoyong He 	hw = &net_hw->super;
374646ea79cSHeinrich Kuhn 
375646ea79cSHeinrich Kuhn 	/* Disabling queues just in case... */
376646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
377646ea79cSHeinrich Kuhn 
378646ea79cSHeinrich Kuhn 	/* Enabling the required queues in the device */
379646ea79cSHeinrich Kuhn 	nfp_net_enable_queues(dev);
380646ea79cSHeinrich Kuhn 
381009f43d5SZerun Fu 	/* Configure the port speed and the auto-negotiation mode. */
382ff9f5a56SChaoyong He 	ret = nfp_net_speed_configure(dev);
383009f43d5SZerun Fu 	if (ret < 0) {
384009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set the speed and auto-negotiation mode.");
385009f43d5SZerun Fu 		return ret;
386009f43d5SZerun Fu 	}
387009f43d5SZerun Fu 
38840688372SChaoyong He 	/* Check and configure queue intr-vector mapping */
389646ea79cSHeinrich Kuhn 	if (dev->data->dev_conf.intr_conf.rxq != 0) {
390968ec1c3SChaoyong He 		if (app_fw_nic->multiport) {
391646ea79cSHeinrich Kuhn 			PMD_INIT_LOG(ERR, "PMD rx interrupt is not supported "
392b6de4353SZerun Fu 					"with NFP multiport PF.");
393646ea79cSHeinrich Kuhn 				return -EINVAL;
394646ea79cSHeinrich Kuhn 		}
395b0c496abSChaoyong He 
396f4d24fe9SChaoyong He 		if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_UIO) {
397646ea79cSHeinrich Kuhn 			/*
398646ea79cSHeinrich Kuhn 			 * Better not to share LSC with RX interrupts.
39940688372SChaoyong He 			 * Unregistering LSC interrupt handler.
400646ea79cSHeinrich Kuhn 			 */
401e7978635SChaoyong He 			rte_intr_callback_unregister(intr_handle,
402646ea79cSHeinrich Kuhn 					nfp_net_dev_interrupt_handler, (void *)dev);
403646ea79cSHeinrich Kuhn 
404646ea79cSHeinrich Kuhn 			if (dev->data->nb_rx_queues > 1) {
405646ea79cSHeinrich Kuhn 				PMD_INIT_LOG(ERR, "PMD rx interrupt only "
406b6de4353SZerun Fu 						"supports 1 queue with UIO.");
407646ea79cSHeinrich Kuhn 				return -EIO;
408646ea79cSHeinrich Kuhn 			}
409646ea79cSHeinrich Kuhn 		}
410b0c496abSChaoyong He 
411646ea79cSHeinrich Kuhn 		intr_vector = dev->data->nb_rx_queues;
412c01e5c0cSChaoyong He 		if (rte_intr_efd_enable(intr_handle, intr_vector) != 0)
413646ea79cSHeinrich Kuhn 			return -1;
414646ea79cSHeinrich Kuhn 
415646ea79cSHeinrich Kuhn 		nfp_configure_rx_interrupt(dev, intr_handle);
416646ea79cSHeinrich Kuhn 		update = NFP_NET_CFG_UPDATE_MSIX;
417646ea79cSHeinrich Kuhn 	}
418646ea79cSHeinrich Kuhn 
419dbad6f64SPeng Zhang 	/* Checking MTU set */
42072d1dea6SChaoyong He 	if (dev->data->mtu > net_hw->flbufsz) {
421b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "MTU (%u) can not be larger than the current NFP_FRAME_SIZE (%u).",
42272d1dea6SChaoyong He 				dev->data->mtu, net_hw->flbufsz);
423dbad6f64SPeng Zhang 		return -ERANGE;
424dbad6f64SPeng Zhang 	}
425dbad6f64SPeng Zhang 
426646ea79cSHeinrich Kuhn 	rte_intr_enable(intr_handle);
427646ea79cSHeinrich Kuhn 
428646ea79cSHeinrich Kuhn 	new_ctrl = nfp_check_offloads(dev);
429646ea79cSHeinrich Kuhn 
430646ea79cSHeinrich Kuhn 	/* Writing configuration parameters in the device */
43172d1dea6SChaoyong He 	nfp_net_params_setup(net_hw);
432646ea79cSHeinrich Kuhn 
433c4de52ecSChaoyong He 	rxmode = &dev->data->dev_conf.rxmode;
434b8e15e9fSLong Wu 	if ((rxmode->offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH) != 0) {
435646ea79cSHeinrich Kuhn 		nfp_net_rss_config_default(dev);
436646ea79cSHeinrich Kuhn 		update |= NFP_NET_CFG_UPDATE_RSS;
43772d1dea6SChaoyong He 		new_ctrl |= nfp_net_cfg_ctrl_rss(hw->cap);
438646ea79cSHeinrich Kuhn 	}
439646ea79cSHeinrich Kuhn 
440646ea79cSHeinrich Kuhn 	/* Enable device */
441646ea79cSHeinrich Kuhn 	new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
442646ea79cSHeinrich Kuhn 
443646ea79cSHeinrich Kuhn 	update |= NFP_NET_CFG_UPDATE_GEN | NFP_NET_CFG_UPDATE_RING;
444646ea79cSHeinrich Kuhn 
4455126a904SLong Wu 	txmode = &dev->data->dev_conf.txmode;
446c55abf61SChaoyong He 
44772d1dea6SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_RINGCFG) != 0)
448646ea79cSHeinrich Kuhn 		new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG;
449646ea79cSHeinrich Kuhn 
450ff9da649SLong Wu 	if ((hw->cap & NFP_NET_CFG_CTRL_TXRWB) != 0)
451ff9da649SLong Wu 		new_ctrl |= NFP_NET_CFG_CTRL_TXRWB;
452ff9da649SLong Wu 
45372d1dea6SChaoyong He 	if (nfp_reconfig(hw, new_ctrl, update) != 0)
454646ea79cSHeinrich Kuhn 		return -EIO;
455646ea79cSHeinrich Kuhn 
4561e80c074SChaoyong He 	hw->ctrl = new_ctrl;
4571e80c074SChaoyong He 
4582e7c3612SQin Ke 	/* Enable packet type offload by extend ctrl word1. */
45972d1dea6SChaoyong He 	cap_extend = hw->cap_ext;
4602e7c3612SQin Ke 	if ((cap_extend & NFP_NET_CFG_CTRL_PKT_TYPE) != 0)
4612e7c3612SQin Ke 		ctrl_extend = NFP_NET_CFG_CTRL_PKT_TYPE;
4622e7c3612SQin Ke 
46353e1412dSLong Wu 	if ((rxmode->offloads & RTE_ETH_RX_OFFLOAD_SECURITY) != 0 ||
46453e1412dSLong Wu 			(txmode->offloads & RTE_ETH_TX_OFFLOAD_SECURITY) != 0) {
46554713740SChang Miao 		if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0)
4669177c800SChaoyong He 			ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC |
4679177c800SChaoyong He 					NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP |
4689177c800SChaoyong He 					NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP;
46953e1412dSLong Wu 	}
47054713740SChang Miao 
4718153bc6fSChaoyong He 	/* Enable flow steer by extend ctrl word1. */
4728153bc6fSChaoyong He 	if ((cap_extend & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
4738153bc6fSChaoyong He 		ctrl_extend |= NFP_NET_CFG_CTRL_FLOW_STEER;
4748153bc6fSChaoyong He 
4752e7c3612SQin Ke 	update = NFP_NET_CFG_UPDATE_GEN;
47672d1dea6SChaoyong He 	if (nfp_ext_reconfig(hw, ctrl_extend, update) != 0)
4772e7c3612SQin Ke 		return -EIO;
4782e7c3612SQin Ke 
47972d1dea6SChaoyong He 	hw->ctrl_ext = ctrl_extend;
480b4b6988aSChaoyong He 
481646ea79cSHeinrich Kuhn 	/*
482646ea79cSHeinrich Kuhn 	 * Allocating rte mbufs for configured rx queues.
48340688372SChaoyong He 	 * This requires queues being enabled before.
484646ea79cSHeinrich Kuhn 	 */
485c01e5c0cSChaoyong He 	if (nfp_net_rx_freelist_setup(dev) != 0) {
486646ea79cSHeinrich Kuhn 		ret = -ENOMEM;
487646ea79cSHeinrich Kuhn 		goto error;
488646ea79cSHeinrich Kuhn 	}
489646ea79cSHeinrich Kuhn 
490acb6bebfSChaoyong He 	/* Configure the physical port up */
4911580387eSChaoyong He 	ret = nfp_eth_set_configured(pf_dev->cpp, net_hw->nfp_idx, 1);
4921580387eSChaoyong He 	if (ret < 0)
4931580387eSChaoyong He 		goto error;
494646ea79cSHeinrich Kuhn 
495c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_rx_queues; i++)
496c46216e7SJie Hai 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
497c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_tx_queues; i++)
498c46216e7SJie Hai 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
499c46216e7SJie Hai 
500646ea79cSHeinrich Kuhn 	return 0;
501646ea79cSHeinrich Kuhn 
502646ea79cSHeinrich Kuhn error:
503646ea79cSHeinrich Kuhn 	/*
504646ea79cSHeinrich Kuhn 	 * An error returned by this function should mean the app
505646ea79cSHeinrich Kuhn 	 * exiting and then the system releasing all the memory
506646ea79cSHeinrich Kuhn 	 * allocated even memory coming from hugepages.
507646ea79cSHeinrich Kuhn 	 *
508646ea79cSHeinrich Kuhn 	 * The device could be enabled at this point with some queues
509646ea79cSHeinrich Kuhn 	 * ready for getting packets. This is true if the call to
510646ea79cSHeinrich Kuhn 	 * nfp_net_rx_freelist_setup() succeeds for some queues but
511646ea79cSHeinrich Kuhn 	 * fails for subsequent queues.
512646ea79cSHeinrich Kuhn 	 *
513646ea79cSHeinrich Kuhn 	 * This should make the app exiting but better if we tell the
514646ea79cSHeinrich Kuhn 	 * device first.
515646ea79cSHeinrich Kuhn 	 */
516646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
517646ea79cSHeinrich Kuhn 
518646ea79cSHeinrich Kuhn 	return ret;
519646ea79cSHeinrich Kuhn }
520646ea79cSHeinrich Kuhn 
521646ea79cSHeinrich Kuhn /* Set the link up. */
522646ea79cSHeinrich Kuhn static int
523646ea79cSHeinrich Kuhn nfp_net_set_link_up(struct rte_eth_dev *dev)
524646ea79cSHeinrich Kuhn {
5250ca4f216SChaoyong He 	int ret;
526646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
527ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
528646ea79cSHeinrich Kuhn 
5299d723baaSChaoyong He 	hw = dev->data->dev_private;
530ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
531646ea79cSHeinrich Kuhn 
5320ca4f216SChaoyong He 	ret = nfp_eth_set_configured(hw_priv->pf_dev->cpp, hw->nfp_idx, 1);
5330ca4f216SChaoyong He 	if (ret < 0)
5340ca4f216SChaoyong He 		return ret;
5350ca4f216SChaoyong He 
5360ca4f216SChaoyong He 	return 0;
537646ea79cSHeinrich Kuhn }
538646ea79cSHeinrich Kuhn 
539646ea79cSHeinrich Kuhn /* Set the link down. */
540646ea79cSHeinrich Kuhn static int
541646ea79cSHeinrich Kuhn nfp_net_set_link_down(struct rte_eth_dev *dev)
542646ea79cSHeinrich Kuhn {
5430ca4f216SChaoyong He 	int ret;
544646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
545ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
546646ea79cSHeinrich Kuhn 
5479d723baaSChaoyong He 	hw = dev->data->dev_private;
548ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
549646ea79cSHeinrich Kuhn 
5500ca4f216SChaoyong He 	ret = nfp_eth_set_configured(hw_priv->pf_dev->cpp, hw->nfp_idx, 0);
5510ca4f216SChaoyong He 	if (ret < 0)
5520ca4f216SChaoyong He 		return ret;
5530ca4f216SChaoyong He 
5540ca4f216SChaoyong He 	return 0;
555646ea79cSHeinrich Kuhn }
556646ea79cSHeinrich Kuhn 
5578ba461d1SPeng Zhang static void
5588ba461d1SPeng Zhang nfp_net_beat_timer(void *arg)
5598ba461d1SPeng Zhang {
5608ba461d1SPeng Zhang 	uint64_t cur_sec;
5618ba461d1SPeng Zhang 	struct nfp_multi_pf *multi_pf = arg;
5628ba461d1SPeng Zhang 
5638ba461d1SPeng Zhang 	cur_sec = rte_rdtsc();
5648ba461d1SPeng Zhang 	nn_writeq(cur_sec, multi_pf->beat_addr + NFP_BEAT_OFFSET(multi_pf->function_id));
5658ba461d1SPeng Zhang 
5668ba461d1SPeng Zhang 	/* Beat once per second. */
5678ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
5688ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
569b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error setting alarm.");
5708ba461d1SPeng Zhang 	}
5718ba461d1SPeng Zhang }
5728ba461d1SPeng Zhang 
5738ba461d1SPeng Zhang static int
5748ba461d1SPeng Zhang nfp_net_keepalive_init(struct nfp_cpp *cpp,
5758ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
5768ba461d1SPeng Zhang {
5778ba461d1SPeng Zhang 	uint8_t *base;
5788ba461d1SPeng Zhang 	uint64_t addr;
5798ba461d1SPeng Zhang 	uint32_t size;
5808ba461d1SPeng Zhang 	uint32_t cpp_id;
5818ba461d1SPeng Zhang 	struct nfp_resource *res;
5828ba461d1SPeng Zhang 
5838ba461d1SPeng Zhang 	res = nfp_resource_acquire(cpp, NFP_RESOURCE_KEEPALIVE);
5848ba461d1SPeng Zhang 	if (res == NULL)
5858ba461d1SPeng Zhang 		return -EIO;
5868ba461d1SPeng Zhang 
5878ba461d1SPeng Zhang 	cpp_id = nfp_resource_cpp_id(res);
5888ba461d1SPeng Zhang 	addr = nfp_resource_address(res);
5898ba461d1SPeng Zhang 	size = nfp_resource_size(res);
5908ba461d1SPeng Zhang 
5918ba461d1SPeng Zhang 	nfp_resource_release(res);
5928ba461d1SPeng Zhang 
5938ba461d1SPeng Zhang 	/* Allocate a fixed area for keepalive. */
5948ba461d1SPeng Zhang 	base = nfp_cpp_map_area(cpp, cpp_id, addr, size, &multi_pf->beat_area);
5958ba461d1SPeng Zhang 	if (base == NULL) {
5968ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Failed to map area for keepalive.");
5978ba461d1SPeng Zhang 		return -EIO;
5988ba461d1SPeng Zhang 	}
5998ba461d1SPeng Zhang 
6008ba461d1SPeng Zhang 	multi_pf->beat_addr = base;
6018ba461d1SPeng Zhang 
6028ba461d1SPeng Zhang 	return 0;
6038ba461d1SPeng Zhang }
6048ba461d1SPeng Zhang 
6058ba461d1SPeng Zhang static void
6068ba461d1SPeng Zhang nfp_net_keepalive_uninit(struct nfp_multi_pf *multi_pf)
6078ba461d1SPeng Zhang {
6088ba461d1SPeng Zhang 	nfp_cpp_area_release_free(multi_pf->beat_area);
6098ba461d1SPeng Zhang }
6108ba461d1SPeng Zhang 
6118ba461d1SPeng Zhang static int
6128ba461d1SPeng Zhang nfp_net_keepalive_start(struct nfp_multi_pf *multi_pf)
6138ba461d1SPeng Zhang {
6148ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
6158ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
616b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error setting alarm.");
6178ba461d1SPeng Zhang 		return -EIO;
6188ba461d1SPeng Zhang 	}
6198ba461d1SPeng Zhang 
6208ba461d1SPeng Zhang 	return 0;
6218ba461d1SPeng Zhang }
6228ba461d1SPeng Zhang 
6238ba461d1SPeng Zhang static void
624b67a7b40SPeng Zhang nfp_net_keepalive_clear(uint8_t *beat_addr,
625b67a7b40SPeng Zhang 		uint8_t function_id)
626b67a7b40SPeng Zhang {
627b67a7b40SPeng Zhang 	nn_writeq(0, beat_addr + NFP_BEAT_OFFSET(function_id));
628b67a7b40SPeng Zhang }
629b67a7b40SPeng Zhang 
630b67a7b40SPeng Zhang static void
631b67a7b40SPeng Zhang nfp_net_keepalive_clear_others(const struct nfp_dev_info *dev_info,
632b67a7b40SPeng Zhang 		struct nfp_multi_pf *multi_pf)
633b67a7b40SPeng Zhang {
634b67a7b40SPeng Zhang 	uint8_t port_num;
635b67a7b40SPeng Zhang 
636b67a7b40SPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
637b67a7b40SPeng Zhang 		if (port_num == multi_pf->function_id)
638b67a7b40SPeng Zhang 			continue;
639b67a7b40SPeng Zhang 
640b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(multi_pf->beat_addr, port_num);
641b67a7b40SPeng Zhang 	}
642b67a7b40SPeng Zhang }
643b67a7b40SPeng Zhang 
644b67a7b40SPeng Zhang static void
6458ba461d1SPeng Zhang nfp_net_keepalive_stop(struct nfp_multi_pf *multi_pf)
6468ba461d1SPeng Zhang {
6478ba461d1SPeng Zhang 	/* Cancel keepalive for multiple PF setup */
6488ba461d1SPeng Zhang 	rte_eal_alarm_cancel(nfp_net_beat_timer, (void *)multi_pf);
6498ba461d1SPeng Zhang }
6508ba461d1SPeng Zhang 
6516484c847SChaoyong He static int
6528b8f116bSChaoyong He nfp_net_uninit(struct rte_eth_dev *eth_dev)
6538b8f116bSChaoyong He {
6548b8f116bSChaoyong He 	struct nfp_net_hw *net_hw;
655ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
6568b8f116bSChaoyong He 
6578b8f116bSChaoyong He 	net_hw = eth_dev->data->dev_private;
658ff9f5a56SChaoyong He 	hw_priv = eth_dev->process_private;
6598153bc6fSChaoyong He 
6608153bc6fSChaoyong He 	if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
661ff9f5a56SChaoyong He 		nfp_net_flow_priv_uninit(hw_priv->pf_dev, net_hw->idx);
6628153bc6fSChaoyong He 
6638b8f116bSChaoyong He 	rte_free(net_hw->eth_xstats_base);
664ff9da649SLong Wu 	if ((net_hw->super.cap & NFP_NET_CFG_CTRL_TXRWB) != 0)
665ff9da649SLong Wu 		nfp_net_txrwb_free(eth_dev);
6668b8f116bSChaoyong He 	nfp_ipsec_uninit(eth_dev);
6676484c847SChaoyong He 
6686484c847SChaoyong He 	return 0;
6698b8f116bSChaoyong He }
6708b8f116bSChaoyong He 
67166d5f53dSChaoyong He static void
67266d5f53dSChaoyong He nfp_cleanup_port_app_fw_nic(struct nfp_pf_dev *pf_dev,
673a9fa1da7SChaoyong He 		uint8_t id,
674a9fa1da7SChaoyong He 		struct rte_eth_dev *eth_dev)
67566d5f53dSChaoyong He {
67666d5f53dSChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
67766d5f53dSChaoyong He 
67866d5f53dSChaoyong He 	app_fw_nic = pf_dev->app_fw_priv;
67966d5f53dSChaoyong He 	if (app_fw_nic->ports[id] != NULL) {
68066d5f53dSChaoyong He 		nfp_net_uninit(eth_dev);
68166d5f53dSChaoyong He 		app_fw_nic->ports[id] = NULL;
68266d5f53dSChaoyong He 	}
68366d5f53dSChaoyong He }
68466d5f53dSChaoyong He 
68566d5f53dSChaoyong He static void
68666d5f53dSChaoyong He nfp_uninit_app_fw_nic(struct nfp_pf_dev *pf_dev)
68766d5f53dSChaoyong He {
68866d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
68966d5f53dSChaoyong He 	rte_free(pf_dev->app_fw_priv);
69066d5f53dSChaoyong He }
69166d5f53dSChaoyong He 
69219542093SPeng Zhang static void
69319542093SPeng Zhang nfp_net_vf_config_uninit(struct nfp_pf_dev *pf_dev)
69419542093SPeng Zhang {
69519542093SPeng Zhang 	if (pf_dev->sriov_vf == 0)
69619542093SPeng Zhang 		return;
69719542093SPeng Zhang 
69819542093SPeng Zhang 	nfp_cpp_area_release_free(pf_dev->vf_cfg_tbl_area);
69919542093SPeng Zhang 	nfp_cpp_area_release_free(pf_dev->vf_area);
70019542093SPeng Zhang }
70119542093SPeng Zhang 
70266d5f53dSChaoyong He void
703ff9f5a56SChaoyong He nfp_pf_uninit(struct nfp_net_hw_priv *hw_priv)
70466d5f53dSChaoyong He {
705ff9f5a56SChaoyong He 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
706ff9f5a56SChaoyong He 
707c50bf4f0SLong Wu 	if (pf_dev->devargs.cpp_service_enable)
708929b0531SLong Wu 		nfp_disable_cpp_service(pf_dev);
70919542093SPeng Zhang 	nfp_net_vf_config_uninit(pf_dev);
710e54d68a0SChaoyong He 	nfp_cpp_area_release_free(pf_dev->mac_stats_area);
71166d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
71266d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
71366d5f53dSChaoyong He 	if (pf_dev->multi_pf.enabled) {
71466d5f53dSChaoyong He 		nfp_net_keepalive_stop(&pf_dev->multi_pf);
715b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
71666d5f53dSChaoyong He 		nfp_net_keepalive_uninit(&pf_dev->multi_pf);
71766d5f53dSChaoyong He 	}
71866d5f53dSChaoyong He 	free(pf_dev->nfp_eth_table);
71966d5f53dSChaoyong He 	free(pf_dev->hwinfo);
72066d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
7216b4273a0SLong Wu 	nfp_sync_free(pf_dev->sync);
72266d5f53dSChaoyong He 	rte_free(pf_dev);
723ff9f5a56SChaoyong He 	rte_free(hw_priv);
72466d5f53dSChaoyong He }
72566d5f53dSChaoyong He 
72666d5f53dSChaoyong He static int
727ff9f5a56SChaoyong He nfp_pf_secondary_uninit(struct nfp_net_hw_priv *hw_priv)
72866d5f53dSChaoyong He {
729ff9f5a56SChaoyong He 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
730ff9f5a56SChaoyong He 
73166d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
73266d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
7336b4273a0SLong Wu 	nfp_sync_free(pf_dev->sync);
73466d5f53dSChaoyong He 	rte_free(pf_dev);
735ff9f5a56SChaoyong He 	rte_free(hw_priv);
73666d5f53dSChaoyong He 
73766d5f53dSChaoyong He 	return 0;
73866d5f53dSChaoyong He }
73966d5f53dSChaoyong He 
740646ea79cSHeinrich Kuhn /* Reset and stop device. The device can not be restarted. */
741646ea79cSHeinrich Kuhn static int
742646ea79cSHeinrich Kuhn nfp_net_close(struct rte_eth_dev *dev)
743646ea79cSHeinrich Kuhn {
7448ceb85c3SChaoyong He 	uint8_t i;
7453b00109dSPeng Zhang 	uint8_t id;
74649952141SChaoyong He 	struct nfp_net_hw *hw;
74749952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
74849952141SChaoyong He 	struct rte_pci_device *pci_dev;
749ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
75049952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
751646ea79cSHeinrich Kuhn 
752ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
753ff9f5a56SChaoyong He 
75466d5f53dSChaoyong He 	/*
75566d5f53dSChaoyong He 	 * In secondary process, a released eth device can be found by its name
75666d5f53dSChaoyong He 	 * in shared memory.
75766d5f53dSChaoyong He 	 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the
75866d5f53dSChaoyong He 	 * eth device has been released.
75966d5f53dSChaoyong He 	 */
76066d5f53dSChaoyong He 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
76166d5f53dSChaoyong He 		if (dev->state == RTE_ETH_DEV_UNUSED)
762646ea79cSHeinrich Kuhn 			return 0;
763646ea79cSHeinrich Kuhn 
764ff9f5a56SChaoyong He 		nfp_pf_secondary_uninit(hw_priv);
76566d5f53dSChaoyong He 		return 0;
76666d5f53dSChaoyong He 	}
76766d5f53dSChaoyong He 
7689d723baaSChaoyong He 	hw = dev->data->dev_private;
769ff9f5a56SChaoyong He 	pf_dev = hw_priv->pf_dev;
770646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(dev);
771968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
772646ea79cSHeinrich Kuhn 
773646ea79cSHeinrich Kuhn 	/*
774646ea79cSHeinrich Kuhn 	 * We assume that the DPDK application is stopping all the
775646ea79cSHeinrich Kuhn 	 * threads/queues before calling the device close function.
776646ea79cSHeinrich Kuhn 	 */
777646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
778646ea79cSHeinrich Kuhn 
779646ea79cSHeinrich Kuhn 	/* Clear queues */
7801c8d02bbSJin Liu 	nfp_net_close_tx_queue(dev);
7811c8d02bbSJin Liu 	nfp_net_close_rx_queue(dev);
782646ea79cSHeinrich Kuhn 
783851f03e1SHeinrich Kuhn 	/* Cancel possible impending LSC work here before releasing the port */
784f4d24fe9SChaoyong He 	rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev);
785851f03e1SHeinrich Kuhn 
786646ea79cSHeinrich Kuhn 	/* Only free PF resources after all physical ports have been closed */
787646ea79cSHeinrich Kuhn 	/* Mark this port as unused and free device priv resources */
788f58bde00SChaoyong He 	nn_cfg_writeb(&hw->super, NFP_NET_CFG_LSC, 0xff);
78966d5f53dSChaoyong He 
79066d5f53dSChaoyong He 	if (pf_dev->app_fw_id != NFP_APP_FW_CORE_NIC)
79166d5f53dSChaoyong He 		return -EINVAL;
79266d5f53dSChaoyong He 
793a9fa1da7SChaoyong He 	nfp_cleanup_port_app_fw_nic(pf_dev, hw->idx, dev);
794646ea79cSHeinrich Kuhn 
7956408420cSPeng Zhang 	for (i = 0; i < pf_dev->total_phyports; i++) {
7963b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
7973b00109dSPeng Zhang 
798646ea79cSHeinrich Kuhn 		/* Check to see if ports are still in use */
7993b00109dSPeng Zhang 		if (app_fw_nic->ports[id] != NULL)
800646ea79cSHeinrich Kuhn 			return 0;
801646ea79cSHeinrich Kuhn 	}
802646ea79cSHeinrich Kuhn 
80366d5f53dSChaoyong He 	/* Enable in nfp_net_start() */
804d61138d4SHarman Kalra 	rte_intr_disable(pci_dev->intr_handle);
805646ea79cSHeinrich Kuhn 
80666d5f53dSChaoyong He 	/* Register in nfp_net_init() */
807d61138d4SHarman Kalra 	rte_intr_callback_unregister(pci_dev->intr_handle,
808a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)dev);
809646ea79cSHeinrich Kuhn 
81066d5f53dSChaoyong He 	nfp_uninit_app_fw_nic(pf_dev);
811ff9f5a56SChaoyong He 	nfp_pf_uninit(hw_priv);
81266d5f53dSChaoyong He 
813646ea79cSHeinrich Kuhn 	return 0;
814646ea79cSHeinrich Kuhn }
815646ea79cSHeinrich Kuhn 
816c55abf61SChaoyong He static int
817c55abf61SChaoyong He nfp_net_find_vxlan_idx(struct nfp_net_hw *hw,
818c55abf61SChaoyong He 		uint16_t port,
819c55abf61SChaoyong He 		uint32_t *idx)
820c55abf61SChaoyong He {
821c55abf61SChaoyong He 	uint32_t i;
822c55abf61SChaoyong He 	int free_idx = -1;
823c55abf61SChaoyong He 
824c55abf61SChaoyong He 	for (i = 0; i < NFP_NET_N_VXLAN_PORTS; i++) {
825c55abf61SChaoyong He 		if (hw->vxlan_ports[i] == port) {
826c55abf61SChaoyong He 			free_idx = i;
827c55abf61SChaoyong He 			break;
828c55abf61SChaoyong He 		}
829c55abf61SChaoyong He 
830c55abf61SChaoyong He 		if (hw->vxlan_usecnt[i] == 0) {
831c55abf61SChaoyong He 			free_idx = i;
832c55abf61SChaoyong He 			break;
833c55abf61SChaoyong He 		}
834c55abf61SChaoyong He 	}
835c55abf61SChaoyong He 
836c55abf61SChaoyong He 	if (free_idx == -1)
837c55abf61SChaoyong He 		return -EINVAL;
838c55abf61SChaoyong He 
839c55abf61SChaoyong He 	*idx = free_idx;
840c55abf61SChaoyong He 
841c55abf61SChaoyong He 	return 0;
842c55abf61SChaoyong He }
843c55abf61SChaoyong He 
844c55abf61SChaoyong He static int
845c55abf61SChaoyong He nfp_udp_tunnel_port_add(struct rte_eth_dev *dev,
846c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
847c55abf61SChaoyong He {
848c55abf61SChaoyong He 	int ret;
849c55abf61SChaoyong He 	uint32_t idx;
8505b81c1e2SLong Wu 	uint32_t ctrl;
8515b81c1e2SLong Wu 	struct nfp_hw *hw;
852c55abf61SChaoyong He 	uint16_t vxlan_port;
8535b81c1e2SLong Wu 	struct nfp_net_hw *net_hw;
854c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
855c55abf61SChaoyong He 
8565b81c1e2SLong Wu 	net_hw = dev->data->dev_private;
857c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
858c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
859c55abf61SChaoyong He 
860c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
861b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel.");
862c55abf61SChaoyong He 		return -ENOTSUP;
863c55abf61SChaoyong He 	}
864c55abf61SChaoyong He 
8655b81c1e2SLong Wu 	ret = nfp_net_find_vxlan_idx(net_hw, vxlan_port, &idx);
866c55abf61SChaoyong He 	if (ret != 0) {
867b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx.");
868c55abf61SChaoyong He 		return -EINVAL;
869c55abf61SChaoyong He 	}
870c55abf61SChaoyong He 
8715b81c1e2SLong Wu 	if (net_hw->vxlan_usecnt[idx] == 0) {
8725b81c1e2SLong Wu 		hw = &net_hw->super;
8735b81c1e2SLong Wu 		ctrl = hw->ctrl | NFP_NET_CFG_CTRL_VXLAN;
8745b81c1e2SLong Wu 
8755b81c1e2SLong Wu 		ret = nfp_net_set_vxlan_port(net_hw, idx, vxlan_port, ctrl);
876c55abf61SChaoyong He 		if (ret != 0) {
877b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Failed set vxlan port.");
878c55abf61SChaoyong He 			return -EINVAL;
879c55abf61SChaoyong He 		}
8805b81c1e2SLong Wu 
8815b81c1e2SLong Wu 		hw->ctrl = ctrl;
882c55abf61SChaoyong He 	}
883c55abf61SChaoyong He 
8845b81c1e2SLong Wu 	net_hw->vxlan_usecnt[idx]++;
885c55abf61SChaoyong He 
886c55abf61SChaoyong He 	return 0;
887c55abf61SChaoyong He }
888c55abf61SChaoyong He 
889c55abf61SChaoyong He static int
890c55abf61SChaoyong He nfp_udp_tunnel_port_del(struct rte_eth_dev *dev,
891c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
892c55abf61SChaoyong He {
893c55abf61SChaoyong He 	int ret;
894c55abf61SChaoyong He 	uint32_t idx;
8955b81c1e2SLong Wu 	uint32_t ctrl;
8965b81c1e2SLong Wu 	struct nfp_hw *hw;
897c55abf61SChaoyong He 	uint16_t vxlan_port;
8985b81c1e2SLong Wu 	struct nfp_net_hw *net_hw;
899c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
900c55abf61SChaoyong He 
9015b81c1e2SLong Wu 	net_hw = dev->data->dev_private;
902c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
903c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
904c55abf61SChaoyong He 
905c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
906b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel.");
907c55abf61SChaoyong He 		return -ENOTSUP;
908c55abf61SChaoyong He 	}
909c55abf61SChaoyong He 
9105b81c1e2SLong Wu 	ret = nfp_net_find_vxlan_idx(net_hw, vxlan_port, &idx);
9115b81c1e2SLong Wu 	if (ret != 0 || net_hw->vxlan_usecnt[idx] == 0) {
912b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx.");
913c55abf61SChaoyong He 		return -EINVAL;
914c55abf61SChaoyong He 	}
915c55abf61SChaoyong He 
9165b81c1e2SLong Wu 	net_hw->vxlan_usecnt[idx]--;
917c55abf61SChaoyong He 
9185b81c1e2SLong Wu 	if (net_hw->vxlan_usecnt[idx] == 0) {
9195b81c1e2SLong Wu 		hw = &net_hw->super;
9205b81c1e2SLong Wu 		ctrl = hw->ctrl & ~NFP_NET_CFG_CTRL_VXLAN;
9215b81c1e2SLong Wu 
9225b81c1e2SLong Wu 		ret = nfp_net_set_vxlan_port(net_hw, idx, 0, ctrl);
923c55abf61SChaoyong He 		if (ret != 0) {
924b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Failed set vxlan port.");
925c55abf61SChaoyong He 			return -EINVAL;
926c55abf61SChaoyong He 		}
9275b81c1e2SLong Wu 
9285b81c1e2SLong Wu 		hw->ctrl = ctrl;
929c55abf61SChaoyong He 	}
930c55abf61SChaoyong He 
931c55abf61SChaoyong He 	return 0;
932c55abf61SChaoyong He }
933c55abf61SChaoyong He 
934646ea79cSHeinrich Kuhn /* Initialise and register driver with DPDK Application */
9358d961320SJin Liu static const struct eth_dev_ops nfp_net_eth_dev_ops = {
936646ea79cSHeinrich Kuhn 	.dev_configure          = nfp_net_configure,
937646ea79cSHeinrich Kuhn 	.dev_start              = nfp_net_start,
938646ea79cSHeinrich Kuhn 	.dev_stop               = nfp_net_stop,
939646ea79cSHeinrich Kuhn 	.dev_set_link_up        = nfp_net_set_link_up,
940646ea79cSHeinrich Kuhn 	.dev_set_link_down      = nfp_net_set_link_down,
941646ea79cSHeinrich Kuhn 	.dev_close              = nfp_net_close,
942646ea79cSHeinrich Kuhn 	.promiscuous_enable     = nfp_net_promisc_enable,
943646ea79cSHeinrich Kuhn 	.promiscuous_disable    = nfp_net_promisc_disable,
9444a86c36bSQin Ke 	.allmulticast_enable    = nfp_net_allmulticast_enable,
9454a86c36bSQin Ke 	.allmulticast_disable   = nfp_net_allmulticast_disable,
946646ea79cSHeinrich Kuhn 	.link_update            = nfp_net_link_update,
947646ea79cSHeinrich Kuhn 	.stats_get              = nfp_net_stats_get,
948646ea79cSHeinrich Kuhn 	.stats_reset            = nfp_net_stats_reset,
949f26e8239SJames Hershaw 	.xstats_get             = nfp_net_xstats_get,
950f26e8239SJames Hershaw 	.xstats_reset           = nfp_net_xstats_reset,
951f26e8239SJames Hershaw 	.xstats_get_names       = nfp_net_xstats_get_names,
952f26e8239SJames Hershaw 	.xstats_get_by_id       = nfp_net_xstats_get_by_id,
953f26e8239SJames Hershaw 	.xstats_get_names_by_id = nfp_net_xstats_get_names_by_id,
954646ea79cSHeinrich Kuhn 	.dev_infos_get          = nfp_net_infos_get,
955646ea79cSHeinrich Kuhn 	.dev_supported_ptypes_get = nfp_net_supported_ptypes_get,
956a498019dSLong Wu 	.dev_ptypes_set         = nfp_net_ptypes_set,
957646ea79cSHeinrich Kuhn 	.mtu_set                = nfp_net_dev_mtu_set,
9580a94d6bcSJin Liu 	.mac_addr_set           = nfp_net_set_mac_addr,
959646ea79cSHeinrich Kuhn 	.vlan_offload_set       = nfp_net_vlan_offload_set,
960646ea79cSHeinrich Kuhn 	.reta_update            = nfp_net_reta_update,
961646ea79cSHeinrich Kuhn 	.reta_query             = nfp_net_reta_query,
962646ea79cSHeinrich Kuhn 	.rss_hash_update        = nfp_net_rss_hash_update,
963646ea79cSHeinrich Kuhn 	.rss_hash_conf_get      = nfp_net_rss_hash_conf_get,
964646ea79cSHeinrich Kuhn 	.rx_queue_setup         = nfp_net_rx_queue_setup,
965646ea79cSHeinrich Kuhn 	.rx_queue_release       = nfp_net_rx_queue_release,
96630198b3fSLong Wu 	.rxq_info_get           = nfp_net_rx_queue_info_get,
9678d961320SJin Liu 	.tx_queue_setup         = nfp_net_tx_queue_setup,
96852ddc4c2SJin Liu 	.tx_queue_release       = nfp_net_tx_queue_release,
969fbe2e2ecSLong Wu 	.txq_info_get           = nfp_net_tx_queue_info_get,
97052ddc4c2SJin Liu 	.rx_queue_intr_enable   = nfp_rx_queue_intr_enable,
97152ddc4c2SJin Liu 	.rx_queue_intr_disable  = nfp_rx_queue_intr_disable,
972c55abf61SChaoyong He 	.udp_tunnel_port_add    = nfp_udp_tunnel_port_add,
973c55abf61SChaoyong He 	.udp_tunnel_port_del    = nfp_udp_tunnel_port_del,
974128c8ad9SChaoyong He 	.fw_version_get         = nfp_net_firmware_version_get,
97551d15e82SZerun Fu 	.flow_ctrl_get          = nfp_net_flow_ctrl_get,
97668aa3537SZerun Fu 	.flow_ctrl_set          = nfp_net_flow_ctrl_set,
9770b9079d2SChaoyong He 	.flow_ops_get           = nfp_net_flow_ops_get,
9780786add9SZerun Fu 	.fec_get_capability     = nfp_net_fec_get_capability,
979c6835a32SZerun Fu 	.fec_get                = nfp_net_fec_get,
98037bd1b84SZerun Fu 	.fec_set                = nfp_net_fec_set,
9817f693813SChaoyong He 	.get_eeprom_length      = nfp_net_get_eeprom_len,
9827f693813SChaoyong He 	.get_eeprom             = nfp_net_get_eeprom,
9837f693813SChaoyong He 	.set_eeprom             = nfp_net_set_eeprom,
9847f693813SChaoyong He 	.get_module_info        = nfp_net_get_module_info,
9857f693813SChaoyong He 	.get_module_eeprom      = nfp_net_get_module_eeprom,
9868bd6f540SChaoyong He 	.dev_led_on             = nfp_net_led_on,
9878bd6f540SChaoyong He 	.dev_led_off            = nfp_net_led_off,
988*4dcbf32fSChaoyong He 	.rx_burst_mode_get      = nfp_net_rx_burst_mode_get,
989*4dcbf32fSChaoyong He 	.tx_burst_mode_get      = nfp_net_tx_burst_mode_get,
99052ddc4c2SJin Liu };
99152ddc4c2SJin Liu 
992ee8ca64eSChaoyong He static inline void
993000feb4cSChaoyong He nfp_net_ethdev_ops_mount(struct nfp_pf_dev *pf_dev,
994ee8ca64eSChaoyong He 		struct rte_eth_dev *eth_dev)
995266470b2SJin Liu {
996000feb4cSChaoyong He 	if (pf_dev->ver.extend == NFP_NET_CFG_VERSION_DP_NFD3)
997ee8ca64eSChaoyong He 		eth_dev->tx_pkt_burst = nfp_net_nfd3_xmit_pkts;
998ee8ca64eSChaoyong He 	else
999fb6befdfSLong Wu 		nfp_net_nfdk_xmit_pkts_set(eth_dev);
1000266470b2SJin Liu 
10018d961320SJin Liu 	eth_dev->dev_ops = &nfp_net_eth_dev_ops;
1002266470b2SJin Liu 	eth_dev->rx_queue_count = nfp_net_rx_queue_count;
1003b6755530SLong Wu 	nfp_net_recv_pkts_set(eth_dev);
1004266470b2SJin Liu }
1005266470b2SJin Liu 
1006646ea79cSHeinrich Kuhn static int
10076484c847SChaoyong He nfp_net_init(struct rte_eth_dev *eth_dev,
10086484c847SChaoyong He 		void *para)
1009646ea79cSHeinrich Kuhn {
101049952141SChaoyong He 	int err;
101149952141SChaoyong He 	uint16_t port;
10120314a8ffSChaoyong He 	uint64_t rx_base;
10130314a8ffSChaoyong He 	uint64_t tx_base;
10144a9bb682SChaoyong He 	struct nfp_hw *hw;
10154a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
101649952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
10176484c847SChaoyong He 	struct nfp_net_init *hw_init;
101849952141SChaoyong He 	struct rte_pci_device *pci_dev;
1019ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
102049952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
1021646ea79cSHeinrich Kuhn 
1022646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
102365f6915dSChaoyong He 	net_hw = eth_dev->data->dev_private;
1024646ea79cSHeinrich Kuhn 
10256484c847SChaoyong He 	hw_init = para;
10266484c847SChaoyong He 	net_hw->idx      = hw_init->idx;
10276484c847SChaoyong He 	net_hw->nfp_idx  = hw_init->nfp_idx;
10286484c847SChaoyong He 	eth_dev->process_private = hw_init->hw_priv;
10296484c847SChaoyong He 
1030646ea79cSHeinrich Kuhn 	/* Use backpointer here to the PF of this eth_dev */
1031ff9f5a56SChaoyong He 	hw_priv = eth_dev->process_private;
1032ff9f5a56SChaoyong He 	pf_dev = hw_priv->pf_dev;
1033646ea79cSHeinrich Kuhn 
1034968ec1c3SChaoyong He 	/* Use backpointer to the CoreNIC app struct */
1035968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
1036968ec1c3SChaoyong He 
10376484c847SChaoyong He 	/* Add this device to the PF's array of physical ports */
10386484c847SChaoyong He 	app_fw_nic->ports[net_hw->idx] = net_hw;
10396484c847SChaoyong He 
10406484c847SChaoyong He 	port = net_hw->idx;
10418ceb85c3SChaoyong He 	if (port > 7) {
1042b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Port value is wrong.");
1043646ea79cSHeinrich Kuhn 		return -ENODEV;
1044646ea79cSHeinrich Kuhn 	}
1045646ea79cSHeinrich Kuhn 
10464a9bb682SChaoyong He 	hw = &net_hw->super;
1047646ea79cSHeinrich Kuhn 
1048030b2b19SChaoyong He 	PMD_INIT_LOG(DEBUG, "Working with physical port number: %hu, "
1049b6de4353SZerun Fu 			"NFP internal port number: %d.", port, net_hw->nfp_idx);
1050646ea79cSHeinrich Kuhn 
1051646ea79cSHeinrich Kuhn 	rte_eth_copy_pci_info(eth_dev, pci_dev);
1052646ea79cSHeinrich Kuhn 
1053e54d68a0SChaoyong He 	if (pf_dev->multi_pf.enabled)
10544a9bb682SChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar;
1055e54d68a0SChaoyong He 	else
105619bd7cceSChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar + (port * pf_dev->ctrl_bar_size);
1057e54d68a0SChaoyong He 
1058e54d68a0SChaoyong He 	net_hw->mac_stats = pf_dev->mac_stats_bar +
10594a9bb682SChaoyong He 				(net_hw->nfp_idx * NFP_MAC_STATS_SIZE);
1060646ea79cSHeinrich Kuhn 
1061b6de4353SZerun Fu 	PMD_INIT_LOG(DEBUG, "Ctrl bar: %p.", hw->ctrl_bar);
1062b6de4353SZerun Fu 	PMD_INIT_LOG(DEBUG, "MAC stats: %p.", net_hw->mac_stats);
1063646ea79cSHeinrich Kuhn 
1064000feb4cSChaoyong He 	err = nfp_net_common_init(pf_dev, net_hw);
1065cd4397ebSPeng Zhang 	if (err != 0)
1066e54d68a0SChaoyong He 		return err;
1067fd392f84SPeng Zhang 
1068eecdfcc1SShihong Wang 	err = nfp_net_tlv_caps_parse(eth_dev);
1069eecdfcc1SShihong Wang 	if (err != 0) {
1070b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to parser TLV caps.");
1071e54d68a0SChaoyong He 		return err;
1072eecdfcc1SShihong Wang 	}
1073eecdfcc1SShihong Wang 
107454713740SChang Miao 	err = nfp_ipsec_init(eth_dev);
107554713740SChang Miao 	if (err != 0) {
1076b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to init IPsec module.");
1077e54d68a0SChaoyong He 		return err;
107854713740SChang Miao 	}
107954713740SChang Miao 
1080000feb4cSChaoyong He 	nfp_net_ethdev_ops_mount(pf_dev, eth_dev);
1081266470b2SJin Liu 
10824a9bb682SChaoyong He 	net_hw->eth_xstats_base = rte_malloc("rte_eth_xstat", sizeof(struct rte_eth_xstat) *
1083f26e8239SJames Hershaw 			nfp_net_xstats_size(eth_dev), 0);
10844a9bb682SChaoyong He 	if (net_hw->eth_xstats_base == NULL) {
1085f6272c7aSZerun Fu 		PMD_INIT_LOG(ERR, "No memory for xstats base values on device %s!",
1086f26e8239SJames Hershaw 				pci_dev->device.name);
108736994566SChaoyong He 		err = -ENOMEM;
108836994566SChaoyong He 		goto ipsec_exit;
1089f26e8239SJames Hershaw 	}
1090f26e8239SJames Hershaw 
1091646ea79cSHeinrich Kuhn 	/* Work out where in the BAR the queues start. */
10924a9bb682SChaoyong He 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
10934a9bb682SChaoyong He 	rx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_RXQ);
1094646ea79cSHeinrich Kuhn 
10954a9bb682SChaoyong He 	net_hw->tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
10964a9bb682SChaoyong He 	net_hw->rx_bar = pf_dev->qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ;
1097646ea79cSHeinrich Kuhn 
1098b6de4353SZerun Fu 	PMD_INIT_LOG(DEBUG, "The ctrl_bar: %p, tx_bar: %p, rx_bar: %p.",
10994a9bb682SChaoyong He 			hw->ctrl_bar, net_hw->tx_bar, net_hw->rx_bar);
1100646ea79cSHeinrich Kuhn 
11014a9bb682SChaoyong He 	nfp_net_cfg_queue_setup(net_hw);
11024a9bb682SChaoyong He 	net_hw->mtu = RTE_ETHER_MTU;
1103646ea79cSHeinrich Kuhn 
1104646ea79cSHeinrich Kuhn 	/* VLAN insertion is incompatible with LSOv2 */
11054a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LSO2) != 0)
11064a9bb682SChaoyong He 		hw->cap &= ~NFP_NET_CFG_CTRL_TXVLAN;
1107646ea79cSHeinrich Kuhn 
1108000feb4cSChaoyong He 	nfp_net_log_device_information(net_hw, pf_dev);
1109646ea79cSHeinrich Kuhn 
1110646ea79cSHeinrich Kuhn 	/* Initializing spinlock for reconfigs */
11114a9bb682SChaoyong He 	rte_spinlock_init(&hw->reconfig_lock);
1112646ea79cSHeinrich Kuhn 
111387abbaf9SPeng Zhang 	if ((port == 0 || pf_dev->multi_pf.enabled)) {
111487abbaf9SPeng Zhang 		err = nfp_net_vf_config_app_init(net_hw, pf_dev);
111587abbaf9SPeng Zhang 		if (err != 0) {
1116b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "Failed to init sriov module.");
111787abbaf9SPeng Zhang 			goto xstats_free;
111887abbaf9SPeng Zhang 		}
111987abbaf9SPeng Zhang 	}
112087abbaf9SPeng Zhang 
1121646ea79cSHeinrich Kuhn 	/* Allocating memory for mac addr */
1122f4d24fe9SChaoyong He 	eth_dev->data->mac_addrs = rte_zmalloc("mac_addr", RTE_ETHER_ADDR_LEN, 0);
1123646ea79cSHeinrich Kuhn 	if (eth_dev->data->mac_addrs == NULL) {
1124b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to space for MAC address.");
112536994566SChaoyong He 		err = -ENOMEM;
112636994566SChaoyong He 		goto xstats_free;
1127646ea79cSHeinrich Kuhn 	}
1128646ea79cSHeinrich Kuhn 
1129ff9da649SLong Wu 	if ((hw->cap & NFP_NET_CFG_CTRL_TXRWB) != 0) {
1130ff9da649SLong Wu 		err = nfp_net_txrwb_alloc(eth_dev);
1131ff9da649SLong Wu 		if (err != 0)
1132ff9da649SLong Wu 			goto xstats_free;
1133ff9da649SLong Wu 	}
1134ff9da649SLong Wu 
1135a9fa1da7SChaoyong He 	nfp_net_pf_read_mac(app_fw_nic, port, hw_priv);
1136503ac807SChaoyong He 	nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
1137646ea79cSHeinrich Kuhn 
11384a9bb682SChaoyong He 	if (rte_is_valid_assigned_ether_addr(&hw->mac_addr) == 0) {
1139b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Using random mac address for port %d.", port);
1140646ea79cSHeinrich Kuhn 		/* Using random mac addresses for VFs */
11414a9bb682SChaoyong He 		rte_eth_random_addr(&hw->mac_addr.addr_bytes[0]);
1142503ac807SChaoyong He 		nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
1143646ea79cSHeinrich Kuhn 	}
1144646ea79cSHeinrich Kuhn 
1145646ea79cSHeinrich Kuhn 	/* Copying mac address to DPDK eth_dev struct */
11464a9bb682SChaoyong He 	rte_ether_addr_copy(&hw->mac_addr, eth_dev->data->mac_addrs);
1147646ea79cSHeinrich Kuhn 
11484a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) == 0)
1149646ea79cSHeinrich Kuhn 		eth_dev->data->dev_flags |= RTE_ETH_DEV_NOLIVE_MAC_ADDR;
1150646ea79cSHeinrich Kuhn 
1151646ea79cSHeinrich Kuhn 	eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1152646ea79cSHeinrich Kuhn 
1153f6272c7aSZerun Fu 	PMD_INIT_LOG(INFO, "Port %d VendorID=%#x DeviceID=%#x "
1154c2c4f87bSAman Deep Singh 			"mac=" RTE_ETHER_ADDR_PRT_FMT,
1155646ea79cSHeinrich Kuhn 			eth_dev->data->port_id, pci_dev->id.vendor_id,
1156646ea79cSHeinrich Kuhn 			pci_dev->id.device_id,
11574a9bb682SChaoyong He 			RTE_ETHER_ADDR_BYTES(&hw->mac_addr));
1158646ea79cSHeinrich Kuhn 
1159646ea79cSHeinrich Kuhn 	/* Registering LSC interrupt handler */
1160d61138d4SHarman Kalra 	rte_intr_callback_register(pci_dev->intr_handle,
1161a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)eth_dev);
1162646ea79cSHeinrich Kuhn 	/* Telling the firmware about the LSC interrupt entry */
11634a9bb682SChaoyong He 	nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
116494d0631aSPeng Zhang 	/* Unmask the LSC interrupt */
116594d0631aSPeng Zhang 	nfp_net_irq_unmask(eth_dev);
1166646ea79cSHeinrich Kuhn 	/* Recording current stats counters values */
1167646ea79cSHeinrich Kuhn 	nfp_net_stats_reset(eth_dev);
1168646ea79cSHeinrich Kuhn 
11698153bc6fSChaoyong He 	if ((hw->cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) {
11708153bc6fSChaoyong He 		err = nfp_net_flow_priv_init(pf_dev, port);
11718153bc6fSChaoyong He 		if (err != 0) {
1172b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "Init net flow priv failed.");
1173ff9da649SLong Wu 			goto txrwb_free;
11748153bc6fSChaoyong He 		}
11758153bc6fSChaoyong He 	}
11768153bc6fSChaoyong He 
1177646ea79cSHeinrich Kuhn 	return 0;
117836994566SChaoyong He 
1179ff9da649SLong Wu txrwb_free:
1180ff9da649SLong Wu 	if ((hw->cap & NFP_NET_CFG_CTRL_TXRWB) != 0)
1181ff9da649SLong Wu 		nfp_net_txrwb_free(eth_dev);
118236994566SChaoyong He xstats_free:
118336994566SChaoyong He 	rte_free(net_hw->eth_xstats_base);
118436994566SChaoyong He ipsec_exit:
118536994566SChaoyong He 	nfp_ipsec_uninit(eth_dev);
118636994566SChaoyong He 
118736994566SChaoyong He 	return err;
1188646ea79cSHeinrich Kuhn }
1189646ea79cSHeinrich Kuhn 
119008461d7bSPeng Zhang static int
11916f708e52SChaoyong He nfp_net_device_activate(struct nfp_pf_dev *pf_dev)
119208461d7bSPeng Zhang {
119308461d7bSPeng Zhang 	int ret;
119408461d7bSPeng Zhang 	struct nfp_nsp *nsp;
11956f708e52SChaoyong He 	struct nfp_multi_pf *multi_pf;
119608461d7bSPeng Zhang 
11976f708e52SChaoyong He 	multi_pf = &pf_dev->multi_pf;
119808461d7bSPeng Zhang 	if (multi_pf->enabled && multi_pf->function_id != 0) {
11996f708e52SChaoyong He 		nsp = nfp_nsp_open(pf_dev->cpp);
120008461d7bSPeng Zhang 		if (nsp == NULL) {
1201b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle.");
120208461d7bSPeng Zhang 			return -EIO;
120308461d7bSPeng Zhang 		}
120408461d7bSPeng Zhang 
120508461d7bSPeng Zhang 		ret = nfp_nsp_device_activate(nsp);
120608461d7bSPeng Zhang 		nfp_nsp_close(nsp);
120708461d7bSPeng Zhang 		if (ret != 0 && ret != -EOPNOTSUPP)
120808461d7bSPeng Zhang 			return ret;
120908461d7bSPeng Zhang 	}
121008461d7bSPeng Zhang 
121108461d7bSPeng Zhang 	return 0;
121208461d7bSPeng Zhang }
121308461d7bSPeng Zhang 
1214646ea79cSHeinrich Kuhn #define DEFAULT_FW_PATH       "/lib/firmware/netronome"
1215646ea79cSHeinrich Kuhn 
1216646ea79cSHeinrich Kuhn static int
12176f708e52SChaoyong He nfp_fw_get_name(struct nfp_pf_dev *pf_dev,
1218ebfb540eSPeng Zhang 		char *fw_name,
1219ebfb540eSPeng Zhang 		size_t fw_size)
1220646ea79cSHeinrich Kuhn {
122149952141SChaoyong He 	char serial[40];
1222ff627b74SChaoyong He 	uint16_t interface;
122330f9f163SChaoyong He 	char card_desc[100];
1224ff627b74SChaoyong He 	uint32_t cpp_serial_len;
122530f9f163SChaoyong He 	const char *nfp_fw_model;
1226ff627b74SChaoyong He 	const uint8_t *cpp_serial;
1227ff627b74SChaoyong He 
12286f708e52SChaoyong He 	cpp_serial_len = nfp_cpp_serial(pf_dev->cpp, &cpp_serial);
1229ff627b74SChaoyong He 	if (cpp_serial_len != NFP_SERIAL_LEN)
1230ff627b74SChaoyong He 		return -ERANGE;
1231ff627b74SChaoyong He 
12326f708e52SChaoyong He 	interface = nfp_cpp_interface(pf_dev->cpp);
1233646ea79cSHeinrich Kuhn 
1234646ea79cSHeinrich Kuhn 	/* Looking for firmware file in order of priority */
1235646ea79cSHeinrich Kuhn 
1236646ea79cSHeinrich Kuhn 	/* First try to find a firmware image specific for this device */
1237646ea79cSHeinrich Kuhn 	snprintf(serial, sizeof(serial),
1238646ea79cSHeinrich Kuhn 			"serial-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
1239ff627b74SChaoyong He 			cpp_serial[0], cpp_serial[1], cpp_serial[2], cpp_serial[3],
1240ff627b74SChaoyong He 			cpp_serial[4], cpp_serial[5], interface >> 8, interface & 0xff);
1241ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/%s.nffw", DEFAULT_FW_PATH, serial);
1242646ea79cSHeinrich Kuhn 
1243b6de4353SZerun Fu 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s.", fw_name);
1244ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1245ebfb540eSPeng Zhang 		return 0;
1246b0c496abSChaoyong He 
1247646ea79cSHeinrich Kuhn 	/* Then try the PCI name */
1248ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/pci-%s.nffw", DEFAULT_FW_PATH,
12496f708e52SChaoyong He 			pf_dev->pci_dev->name);
1250646ea79cSHeinrich Kuhn 
1251b6de4353SZerun Fu 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s.", fw_name);
1252ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1253ebfb540eSPeng Zhang 		return 0;
1254646ea79cSHeinrich Kuhn 
12556f708e52SChaoyong He 	nfp_fw_model = nfp_hwinfo_lookup(pf_dev->hwinfo, "nffw.partno");
125630f9f163SChaoyong He 	if (nfp_fw_model == NULL) {
12576f708e52SChaoyong He 		nfp_fw_model = nfp_hwinfo_lookup(pf_dev->hwinfo, "assembly.partno");
125830f9f163SChaoyong He 		if (nfp_fw_model == NULL) {
1259b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Firmware model NOT found.");
126030f9f163SChaoyong He 			return -EIO;
126130f9f163SChaoyong He 		}
126230f9f163SChaoyong He 	}
126330f9f163SChaoyong He 
1264a2a0edc5SChaoyong He 	/* And then try the model name */
1265a2a0edc5SChaoyong He 	snprintf(card_desc, sizeof(card_desc), "%s.nffw", nfp_fw_model);
1266a2a0edc5SChaoyong He 	snprintf(fw_name, fw_size, "%s/%s", DEFAULT_FW_PATH, card_desc);
1267b6de4353SZerun Fu 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s.", fw_name);
1268a2a0edc5SChaoyong He 	if (access(fw_name, F_OK) == 0)
1269a2a0edc5SChaoyong He 		return 0;
1270a2a0edc5SChaoyong He 
1271646ea79cSHeinrich Kuhn 	/* Finally try the card type and media */
127230f9f163SChaoyong He 	snprintf(card_desc, sizeof(card_desc), "nic_%s_%dx%d.nffw",
12736f708e52SChaoyong He 			nfp_fw_model, pf_dev->nfp_eth_table->count,
12746f708e52SChaoyong He 			pf_dev->nfp_eth_table->ports[0].speed / 1000);
127530f9f163SChaoyong He 	snprintf(fw_name, fw_size, "%s/%s", DEFAULT_FW_PATH, card_desc);
1276b6de4353SZerun Fu 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s.", fw_name);
1277ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1278ebfb540eSPeng Zhang 		return 0;
1279c01e5c0cSChaoyong He 
1280646ea79cSHeinrich Kuhn 	return -ENOENT;
1281ebfb540eSPeng Zhang }
1282646ea79cSHeinrich Kuhn 
1283ebfb540eSPeng Zhang static int
1284ebfb540eSPeng Zhang nfp_fw_upload(struct nfp_nsp *nsp,
1285ebfb540eSPeng Zhang 		char *fw_name)
1286ebfb540eSPeng Zhang {
1287ebfb540eSPeng Zhang 	int err;
1288ebfb540eSPeng Zhang 	void *fw_buf;
1289ebfb540eSPeng Zhang 	size_t fsize;
1290ebfb540eSPeng Zhang 
1291ebfb540eSPeng Zhang 	err = rte_firmware_read(fw_name, &fw_buf, &fsize);
1292ebfb540eSPeng Zhang 	if (err != 0) {
1293f6272c7aSZerun Fu 		PMD_DRV_LOG(ERR, "Firmware %s not found!", fw_name);
1294ebfb540eSPeng Zhang 		return -ENOENT;
1295ebfb540eSPeng Zhang 	}
1296ebfb540eSPeng Zhang 
1297b6de4353SZerun Fu 	PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %zu.",
1298646ea79cSHeinrich Kuhn 			fw_name, fsize);
1299646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Uploading the firmware ...");
13002e634b03SPeng Zhang 	if (nfp_nsp_load_fw(nsp, fw_buf, fsize) < 0) {
13012e634b03SPeng Zhang 		free(fw_buf);
13022e634b03SPeng Zhang 		PMD_DRV_LOG(ERR, "Firmware load failed.");
13032e634b03SPeng Zhang 		return -EIO;
13042e634b03SPeng Zhang 	}
13052e634b03SPeng Zhang 
1306b6de4353SZerun Fu 	PMD_DRV_LOG(INFO, "Done.");
1307646ea79cSHeinrich Kuhn 
1308646ea79cSHeinrich Kuhn 	free(fw_buf);
1309646ea79cSHeinrich Kuhn 
1310646ea79cSHeinrich Kuhn 	return 0;
1311646ea79cSHeinrich Kuhn }
1312646ea79cSHeinrich Kuhn 
13133b00109dSPeng Zhang static void
13143b00109dSPeng Zhang nfp_fw_unload(struct nfp_cpp *cpp)
13153b00109dSPeng Zhang {
1316aa6b4a80SHuaxing Zhu 	int err;
13173b00109dSPeng Zhang 	struct nfp_nsp *nsp;
13183b00109dSPeng Zhang 
13193b00109dSPeng Zhang 	nsp = nfp_nsp_open(cpp);
13203b00109dSPeng Zhang 	if (nsp == NULL)
13213b00109dSPeng Zhang 		return;
13223b00109dSPeng Zhang 
1323aa6b4a80SHuaxing Zhu 	err = nfp_nsp_device_soft_reset(nsp);
1324aa6b4a80SHuaxing Zhu 	if (err != 0)
1325aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(WARNING, "Failed to do soft reset when nfp fw unload.");
1326aa6b4a80SHuaxing Zhu 
13273b00109dSPeng Zhang 	nfp_nsp_close(nsp);
13283b00109dSPeng Zhang }
13293b00109dSPeng Zhang 
1330646ea79cSHeinrich Kuhn static int
1331a2bc299dSPeng Zhang nfp_fw_check_change(struct nfp_cpp *cpp,
1332a2bc299dSPeng Zhang 		char *fw_name,
1333a2bc299dSPeng Zhang 		bool *fw_changed)
1334a2bc299dSPeng Zhang {
1335a2bc299dSPeng Zhang 	int ret;
1336a2bc299dSPeng Zhang 	uint32_t new_version = 0;
1337a2bc299dSPeng Zhang 	uint32_t old_version = 0;
1338a2bc299dSPeng Zhang 
1339a2bc299dSPeng Zhang 	ret = nfp_elf_get_fw_version(&new_version, fw_name);
1340a2bc299dSPeng Zhang 	if (ret != 0)
1341a2bc299dSPeng Zhang 		return ret;
1342a2bc299dSPeng Zhang 
1343b3c21344SChaoyong He 	nfp_net_get_fw_version(cpp, &old_version);
1344a2bc299dSPeng Zhang 
1345a2bc299dSPeng Zhang 	if (new_version != old_version) {
1346b6de4353SZerun Fu 		PMD_DRV_LOG(INFO, "FW version is changed, new %u, old %u.",
1347a2bc299dSPeng Zhang 				new_version, old_version);
1348a2bc299dSPeng Zhang 		*fw_changed = true;
1349a2bc299dSPeng Zhang 	} else {
1350b6de4353SZerun Fu 		PMD_DRV_LOG(INFO, "FW version is not changed and is %u.", new_version);
1351a2bc299dSPeng Zhang 		*fw_changed = false;
1352a2bc299dSPeng Zhang 	}
1353a2bc299dSPeng Zhang 
1354a2bc299dSPeng Zhang 	return 0;
1355a2bc299dSPeng Zhang }
1356a2bc299dSPeng Zhang 
1357c4ced2d5SHuaxing Zhu static void
1358c4ced2d5SHuaxing Zhu nfp_pcie_reg32_write_clear(struct rte_pci_device *pci_dev,
1359c4ced2d5SHuaxing Zhu 		int position)
1360c4ced2d5SHuaxing Zhu {
1361c4ced2d5SHuaxing Zhu 	int ret;
1362c4ced2d5SHuaxing Zhu 	uint32_t capability;
1363c4ced2d5SHuaxing Zhu 
1364c4ced2d5SHuaxing Zhu 	ret = rte_pci_read_config(pci_dev, &capability, 4, position);
1365c4ced2d5SHuaxing Zhu 	if (ret < 0)
1366c4ced2d5SHuaxing Zhu 		capability = 0xffffffff;
1367c4ced2d5SHuaxing Zhu 
1368c4ced2d5SHuaxing Zhu 	(void)rte_pci_write_config(pci_dev, &capability, 4, position);
1369c4ced2d5SHuaxing Zhu }
1370c4ced2d5SHuaxing Zhu 
1371c4ced2d5SHuaxing Zhu static void
1372c4ced2d5SHuaxing Zhu nfp_pcie_aer_clear(struct rte_pci_device *pci_dev)
1373c4ced2d5SHuaxing Zhu {
1374c4ced2d5SHuaxing Zhu 	int pos;
1375c4ced2d5SHuaxing Zhu 
1376c4ced2d5SHuaxing Zhu 	pos = rte_pci_find_ext_capability(pci_dev, RTE_PCI_EXT_CAP_ID_ERR);
1377c4ced2d5SHuaxing Zhu 	if (pos <= 0)
1378c4ced2d5SHuaxing Zhu 		return;
1379c4ced2d5SHuaxing Zhu 
1380c4ced2d5SHuaxing Zhu 	nfp_pcie_reg32_write_clear(pci_dev, pos + RTE_PCI_ERR_UNCOR_STATUS);
1381c4ced2d5SHuaxing Zhu 	nfp_pcie_reg32_write_clear(pci_dev, pos + RTE_PCI_ERR_COR_STATUS);
1382c4ced2d5SHuaxing Zhu }
1383c4ced2d5SHuaxing Zhu 
1384a2bc299dSPeng Zhang static int
1385ebfb540eSPeng Zhang nfp_fw_reload(struct nfp_nsp *nsp,
138608ea495dSChaoyong He 		char *fw_name,
1387c4ced2d5SHuaxing Zhu 		struct rte_pci_device *pci_dev,
138808ea495dSChaoyong He 		int reset)
13898ba461d1SPeng Zhang {
13908ba461d1SPeng Zhang 	int err;
139108ea495dSChaoyong He 	bool reset_flag;
13928ba461d1SPeng Zhang 
139308ea495dSChaoyong He 	reset_flag = (reset == NFP_NSP_DRV_RESET_ALWAYS) ||
139408ea495dSChaoyong He 			(reset == NFP_NSP_DRV_RESET_DISK);
13958ba461d1SPeng Zhang 
139608ea495dSChaoyong He 	if (reset_flag) {
139708ea495dSChaoyong He 		err = nfp_nsp_device_soft_reset(nsp);
139808ea495dSChaoyong He 		if (err != 0) {
1399b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NFP firmware soft reset failed.");
14008ba461d1SPeng Zhang 			return err;
14018ba461d1SPeng Zhang 		}
140208ea495dSChaoyong He 	}
140308ea495dSChaoyong He 
1404c4ced2d5SHuaxing Zhu 	/*
1405c4ced2d5SHuaxing Zhu 	 * Accessing device memory during soft reset may result in some
1406c4ced2d5SHuaxing Zhu 	 * errors being recorded in PCIE's AER register, which is normal.
1407c4ced2d5SHuaxing Zhu 	 * Therefore, after the soft reset is completed, these errors
1408c4ced2d5SHuaxing Zhu 	 * should be cleared.
1409c4ced2d5SHuaxing Zhu 	 */
1410c4ced2d5SHuaxing Zhu 	nfp_pcie_aer_clear(pci_dev);
1411c4ced2d5SHuaxing Zhu 
141208ea495dSChaoyong He 	err = nfp_fw_upload(nsp, fw_name);
141308ea495dSChaoyong He 	if (err != 0) {
1414b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFP firmware load failed.");
141508ea495dSChaoyong He 		return err;
141608ea495dSChaoyong He 	}
141708ea495dSChaoyong He 
141808ea495dSChaoyong He 	return 0;
141908ea495dSChaoyong He }
14208ba461d1SPeng Zhang 
1421a99ca614SPeng Zhang static bool
1422a99ca614SPeng Zhang nfp_fw_skip_load(const struct nfp_dev_info *dev_info,
1423b301fd73SPeng Zhang 		struct nfp_multi_pf *multi_pf,
1424b301fd73SPeng Zhang 		bool *reload_fw)
14258ba461d1SPeng Zhang {
142674397a7aSPeng Zhang 	uint8_t i;
142774397a7aSPeng Zhang 	uint64_t tmp_beat;
14288ba461d1SPeng Zhang 	uint32_t port_num;
14298b9a83eaSPeng Zhang 	uint8_t in_use = 0;
143074397a7aSPeng Zhang 	uint64_t beat[dev_info->pf_num_per_unit];
143174397a7aSPeng Zhang 	uint32_t offset[dev_info->pf_num_per_unit];
14328b9a83eaSPeng Zhang 	uint8_t abnormal = dev_info->pf_num_per_unit;
143374397a7aSPeng Zhang 
1434ab47cecfSPeng Zhang 	sleep(1);
143574397a7aSPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
1436ab47cecfSPeng Zhang 		if (port_num == multi_pf->function_id) {
1437ab47cecfSPeng Zhang 			abnormal--;
1438ab47cecfSPeng Zhang 			continue;
1439ab47cecfSPeng Zhang 		}
1440ab47cecfSPeng Zhang 
144174397a7aSPeng Zhang 		offset[port_num] = NFP_BEAT_OFFSET(port_num);
144274397a7aSPeng Zhang 		beat[port_num] = nn_readq(multi_pf->beat_addr + offset[port_num]);
14438b9a83eaSPeng Zhang 		if (beat[port_num] == 0)
14448b9a83eaSPeng Zhang 			abnormal--;
144574397a7aSPeng Zhang 	}
14468ba461d1SPeng Zhang 
14478b9a83eaSPeng Zhang 	if (abnormal == 0)
14488b9a83eaSPeng Zhang 		return true;
14498b9a83eaSPeng Zhang 
145074397a7aSPeng Zhang 	for (i = 0; i < 3; i++) {
145174397a7aSPeng Zhang 		sleep(1);
14528ba461d1SPeng Zhang 		for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
14538ba461d1SPeng Zhang 			if (port_num == multi_pf->function_id)
14548ba461d1SPeng Zhang 				continue;
14558ba461d1SPeng Zhang 
14568b9a83eaSPeng Zhang 			if (beat[port_num] == 0)
14578b9a83eaSPeng Zhang 				continue;
14588b9a83eaSPeng Zhang 
145974397a7aSPeng Zhang 			tmp_beat = nn_readq(multi_pf->beat_addr + offset[port_num]);
14608b9a83eaSPeng Zhang 			if (tmp_beat != beat[port_num]) {
14618b9a83eaSPeng Zhang 				in_use++;
14628b9a83eaSPeng Zhang 				abnormal--;
14638b9a83eaSPeng Zhang 				beat[port_num] = 0;
1464b301fd73SPeng Zhang 				if (*reload_fw) {
1465b301fd73SPeng Zhang 					*reload_fw = false;
1466b6de4353SZerun Fu 					PMD_DRV_LOG(ERR, "The param %s does not work.",
1467b301fd73SPeng Zhang 							NFP_PF_FORCE_RELOAD_FW);
1468b301fd73SPeng Zhang 				}
14698b9a83eaSPeng Zhang 			}
14708b9a83eaSPeng Zhang 		}
14718b9a83eaSPeng Zhang 
14728b9a83eaSPeng Zhang 		if (abnormal == 0)
1473a99ca614SPeng Zhang 			return true;
14748ba461d1SPeng Zhang 	}
14758b9a83eaSPeng Zhang 
14768b9a83eaSPeng Zhang 	if (in_use != 0) {
14778b9a83eaSPeng Zhang 		PMD_DRV_LOG(WARNING, "Abnormal %u != 0, the nic has port which is exit abnormally.",
14788b9a83eaSPeng Zhang 				abnormal);
14798b9a83eaSPeng Zhang 		return true;
14808ba461d1SPeng Zhang 	}
14818ba461d1SPeng Zhang 
1482a99ca614SPeng Zhang 	return false;
14838ba461d1SPeng Zhang }
148408ea495dSChaoyong He 
1485a2bc299dSPeng Zhang static int
148608ea495dSChaoyong He nfp_fw_reload_from_flash(struct nfp_nsp *nsp)
148708ea495dSChaoyong He {
148808ea495dSChaoyong He 	int ret;
148908ea495dSChaoyong He 
149008ea495dSChaoyong He 	ret = nfp_nsp_load_stored_fw(nsp);
149108ea495dSChaoyong He 	if (ret != 0) {
149208ea495dSChaoyong He 		PMD_DRV_LOG(ERR, "Load firmware from flash failed.");
149308ea495dSChaoyong He 		return -EACCES;
149408ea495dSChaoyong He 	}
149508ea495dSChaoyong He 
149608ea495dSChaoyong He 	return 0;
149708ea495dSChaoyong He }
149808ea495dSChaoyong He 
149908ea495dSChaoyong He static int
150008ea495dSChaoyong He nfp_fw_reload_for_single_pf_from_disk(struct nfp_nsp *nsp,
1501a2bc299dSPeng Zhang 		char *fw_name,
15026f708e52SChaoyong He 		struct nfp_pf_dev *pf_dev,
150308ea495dSChaoyong He 		int reset)
1504a2bc299dSPeng Zhang {
1505a2bc299dSPeng Zhang 	int ret;
1506a2bc299dSPeng Zhang 	bool fw_changed = true;
1507a2bc299dSPeng Zhang 
15086f708e52SChaoyong He 	if (nfp_nsp_has_fw_loaded(nsp) && nfp_nsp_fw_loaded(nsp) &&
15096f708e52SChaoyong He 			!pf_dev->devargs.force_reload_fw) {
15106f708e52SChaoyong He 		ret = nfp_fw_check_change(pf_dev->cpp, fw_name, &fw_changed);
1511a2bc299dSPeng Zhang 		if (ret != 0)
1512a2bc299dSPeng Zhang 			return ret;
1513a2bc299dSPeng Zhang 	}
1514a2bc299dSPeng Zhang 
1515a2bc299dSPeng Zhang 	if (!fw_changed)
1516a2bc299dSPeng Zhang 		return 0;
1517a2bc299dSPeng Zhang 
1518c4ced2d5SHuaxing Zhu 	ret = nfp_fw_reload(nsp, fw_name, pf_dev->pci_dev, reset);
1519a2bc299dSPeng Zhang 	if (ret != 0)
1520a2bc299dSPeng Zhang 		return ret;
1521a2bc299dSPeng Zhang 
1522a2bc299dSPeng Zhang 	return 0;
1523a2bc299dSPeng Zhang }
15248ba461d1SPeng Zhang 
15258ba461d1SPeng Zhang static int
152608ea495dSChaoyong He nfp_fw_reload_for_single_pf(struct nfp_nsp *nsp,
152708ea495dSChaoyong He 		char *fw_name,
15286f708e52SChaoyong He 		struct nfp_pf_dev *pf_dev,
152908ea495dSChaoyong He 		int reset,
153008ea495dSChaoyong He 		int policy)
153108ea495dSChaoyong He {
153208ea495dSChaoyong He 	int ret;
153308ea495dSChaoyong He 
153408ea495dSChaoyong He 	if (policy == NFP_NSP_APP_FW_LOAD_FLASH && nfp_nsp_has_stored_fw_load(nsp)) {
153508ea495dSChaoyong He 		ret = nfp_fw_reload_from_flash(nsp);
153608ea495dSChaoyong He 		if (ret != 0) {
153708ea495dSChaoyong He 			PMD_DRV_LOG(ERR, "Load single PF firmware from flash failed.");
153808ea495dSChaoyong He 			return ret;
153908ea495dSChaoyong He 		}
154008ea495dSChaoyong He 	} else if (fw_name[0] != 0) {
15416f708e52SChaoyong He 		ret = nfp_fw_reload_for_single_pf_from_disk(nsp, fw_name, pf_dev, reset);
154208ea495dSChaoyong He 		if (ret != 0) {
154308ea495dSChaoyong He 			PMD_DRV_LOG(ERR, "Load single PF firmware from disk failed.");
154408ea495dSChaoyong He 			return ret;
154508ea495dSChaoyong He 		}
154608ea495dSChaoyong He 	} else {
154708ea495dSChaoyong He 		PMD_DRV_LOG(ERR, "Not load firmware, please update flash or recofigure card.");
154808ea495dSChaoyong He 		return -ENODATA;
154908ea495dSChaoyong He 	}
155008ea495dSChaoyong He 
155108ea495dSChaoyong He 	return 0;
155208ea495dSChaoyong He }
155308ea495dSChaoyong He 
155408ea495dSChaoyong He static int
155508ea495dSChaoyong He nfp_fw_reload_for_multi_pf_from_disk(struct nfp_nsp *nsp,
155608ea495dSChaoyong He 		char *fw_name,
155708ea495dSChaoyong He 		const struct nfp_dev_info *dev_info,
15586f708e52SChaoyong He 		struct nfp_pf_dev *pf_dev,
155908ea495dSChaoyong He 		int reset)
156008ea495dSChaoyong He {
156108ea495dSChaoyong He 	int err;
156208ea495dSChaoyong He 	bool fw_changed = true;
156308ea495dSChaoyong He 	bool skip_load_fw = false;
15646f708e52SChaoyong He 	bool reload_fw = pf_dev->devargs.force_reload_fw;
156508ea495dSChaoyong He 
156608ea495dSChaoyong He 	if (nfp_nsp_has_fw_loaded(nsp) && nfp_nsp_fw_loaded(nsp) && !reload_fw) {
15676f708e52SChaoyong He 		err = nfp_fw_check_change(pf_dev->cpp, fw_name, &fw_changed);
156808ea495dSChaoyong He 		if (err != 0)
156908ea495dSChaoyong He 			return err;
157008ea495dSChaoyong He 	}
157108ea495dSChaoyong He 
157208ea495dSChaoyong He 	if (!fw_changed || reload_fw)
15736f708e52SChaoyong He 		skip_load_fw = nfp_fw_skip_load(dev_info, &pf_dev->multi_pf, &reload_fw);
157408ea495dSChaoyong He 
157508ea495dSChaoyong He 	if (skip_load_fw && !reload_fw)
157608ea495dSChaoyong He 		return 0;
157708ea495dSChaoyong He 
1578c4ced2d5SHuaxing Zhu 	err = nfp_fw_reload(nsp, fw_name, pf_dev->pci_dev, reset);
157908ea495dSChaoyong He 	if (err != 0)
158008ea495dSChaoyong He 		return err;
158108ea495dSChaoyong He 
158208ea495dSChaoyong He 	return 0;
158308ea495dSChaoyong He }
158408ea495dSChaoyong He 
158508ea495dSChaoyong He static int
1586a2bc299dSPeng Zhang nfp_fw_reload_for_multi_pf(struct nfp_nsp *nsp,
1587ebfb540eSPeng Zhang 		char *fw_name,
15888ba461d1SPeng Zhang 		const struct nfp_dev_info *dev_info,
15896f708e52SChaoyong He 		struct nfp_pf_dev *pf_dev,
159008ea495dSChaoyong He 		int reset,
159108ea495dSChaoyong He 		int policy)
15928ba461d1SPeng Zhang {
15938ba461d1SPeng Zhang 	int err;
15946f708e52SChaoyong He 	struct nfp_multi_pf *multi_pf;
15958ba461d1SPeng Zhang 
15966f708e52SChaoyong He 	multi_pf = &pf_dev->multi_pf;
15976f708e52SChaoyong He 
15986f708e52SChaoyong He 	err = nfp_net_keepalive_init(pf_dev->cpp, multi_pf);
15998ba461d1SPeng Zhang 	if (err != 0) {
1600b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFP init beat failed.");
16018ba461d1SPeng Zhang 		return err;
16028ba461d1SPeng Zhang 	}
16038ba461d1SPeng Zhang 
16048ba461d1SPeng Zhang 	err = nfp_net_keepalive_start(multi_pf);
16058ba461d1SPeng Zhang 	if (err != 0) {
1606b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFP write beat failed.");
1607a2bc299dSPeng Zhang 		goto keepalive_uninit;
16088ba461d1SPeng Zhang 	}
16098ba461d1SPeng Zhang 
161008ea495dSChaoyong He 	if (policy == NFP_NSP_APP_FW_LOAD_FLASH && nfp_nsp_has_stored_fw_load(nsp)) {
161108ea495dSChaoyong He 		err = nfp_fw_reload_from_flash(nsp);
161208ea495dSChaoyong He 		if (err != 0) {
161308ea495dSChaoyong He 			PMD_DRV_LOG(ERR, "Load multi PF firmware from flash failed.");
1614a2bc299dSPeng Zhang 			goto keepalive_stop;
1615a2bc299dSPeng Zhang 		}
161608ea495dSChaoyong He 	} else if (fw_name[0] != 0) {
16176f708e52SChaoyong He 		err = nfp_fw_reload_for_multi_pf_from_disk(nsp, fw_name, dev_info,
16186f708e52SChaoyong He 				pf_dev, reset);
161908ea495dSChaoyong He 		if (err != 0) {
162008ea495dSChaoyong He 			PMD_DRV_LOG(ERR, "Load multi PF firmware from disk failed.");
1621a2bc299dSPeng Zhang 			goto keepalive_stop;
162208ea495dSChaoyong He 		}
162308ea495dSChaoyong He 	} else {
162408ea495dSChaoyong He 		PMD_DRV_LOG(ERR, "Not load firmware, please update flash or recofigure card.");
162508ea495dSChaoyong He 		err = -ENODATA;
162608ea495dSChaoyong He 		goto keepalive_stop;
162708ea495dSChaoyong He 	}
16288ba461d1SPeng Zhang 
1629b67a7b40SPeng Zhang 	nfp_net_keepalive_clear_others(dev_info, multi_pf);
1630b67a7b40SPeng Zhang 
1631a99ca614SPeng Zhang 	return 0;
1632a2bc299dSPeng Zhang 
1633a2bc299dSPeng Zhang keepalive_stop:
1634a2bc299dSPeng Zhang 	nfp_net_keepalive_stop(multi_pf);
1635a2bc299dSPeng Zhang keepalive_uninit:
1636a2bc299dSPeng Zhang 	nfp_net_keepalive_uninit(multi_pf);
1637a2bc299dSPeng Zhang 
1638a2bc299dSPeng Zhang 	return err;
1639a99ca614SPeng Zhang }
1640a99ca614SPeng Zhang 
16418ba461d1SPeng Zhang static int
164208ea495dSChaoyong He nfp_strtol(const char *buf,
164308ea495dSChaoyong He 		int base,
164408ea495dSChaoyong He 		long *value)
164508ea495dSChaoyong He {
164608ea495dSChaoyong He 	long val;
164708ea495dSChaoyong He 	char *tmp;
164808ea495dSChaoyong He 
164908ea495dSChaoyong He 	if (value == NULL)
165008ea495dSChaoyong He 		return -EINVAL;
165108ea495dSChaoyong He 
165208ea495dSChaoyong He 	val = strtol(buf, &tmp, base);
165308ea495dSChaoyong He 	if (tmp == NULL || *tmp != 0)
165408ea495dSChaoyong He 		return -EINVAL;
165508ea495dSChaoyong He 
165608ea495dSChaoyong He 	*value = val;
165708ea495dSChaoyong He 
165808ea495dSChaoyong He 	return 0;
165908ea495dSChaoyong He }
166008ea495dSChaoyong He 
166108ea495dSChaoyong He static int
166208ea495dSChaoyong He nfp_fw_policy_value_get(struct nfp_nsp *nsp,
166308ea495dSChaoyong He 		const char *key,
166408ea495dSChaoyong He 		const char *default_val,
166508ea495dSChaoyong He 		int max_val,
166608ea495dSChaoyong He 		int *value)
166708ea495dSChaoyong He {
166808ea495dSChaoyong He 	int ret;
166908ea495dSChaoyong He 	int64_t val;
167008ea495dSChaoyong He 	char buf[64];
167108ea495dSChaoyong He 
167208ea495dSChaoyong He 	snprintf(buf, sizeof(buf), "%s", key);
167308ea495dSChaoyong He 	ret = nfp_nsp_hwinfo_lookup_optional(nsp, buf, sizeof(buf), default_val);
167408ea495dSChaoyong He 	if (ret != 0)
167508ea495dSChaoyong He 		return ret;
167608ea495dSChaoyong He 
167708ea495dSChaoyong He 	ret = nfp_strtol(buf, 0, &val);
167808ea495dSChaoyong He 	if (ret != 0 || val < 0 || val > max_val) {
1679b6de4353SZerun Fu 		PMD_DRV_LOG(WARNING, "Invalid value '%s' from '%s', ignoring.",
168008ea495dSChaoyong He 				buf, key);
168108ea495dSChaoyong He 		/* Fall back to the default value */
168208ea495dSChaoyong He 		ret = nfp_strtol(default_val, 0, &val);
168308ea495dSChaoyong He 		if (ret != 0)
168408ea495dSChaoyong He 			return ret;
168508ea495dSChaoyong He 	}
168608ea495dSChaoyong He 
168708ea495dSChaoyong He 	*value = val;
168808ea495dSChaoyong He 
168908ea495dSChaoyong He 	return 0;
169008ea495dSChaoyong He }
169108ea495dSChaoyong He 
169208ea495dSChaoyong He static int
16936f708e52SChaoyong He nfp_fw_setup(struct nfp_pf_dev *pf_dev,
16946f708e52SChaoyong He 		const struct nfp_dev_info *dev_info)
1695646ea79cSHeinrich Kuhn {
169649952141SChaoyong He 	int err;
169708ea495dSChaoyong He 	int reset;
169808ea495dSChaoyong He 	int policy;
1699ebfb540eSPeng Zhang 	char fw_name[125];
1700646ea79cSHeinrich Kuhn 	struct nfp_nsp *nsp;
1701646ea79cSHeinrich Kuhn 
17026f708e52SChaoyong He 	nsp = nfp_nsp_open(pf_dev->cpp);
1703a6189a67SJin Liu 	if (nsp == NULL) {
1704b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle.");
1705646ea79cSHeinrich Kuhn 		return -EIO;
1706646ea79cSHeinrich Kuhn 	}
1707646ea79cSHeinrich Kuhn 
170808ea495dSChaoyong He 	err = nfp_fw_policy_value_get(nsp, "abi_drv_reset",
170908ea495dSChaoyong He 			NFP_NSP_DRV_RESET_DEFAULT, NFP_NSP_DRV_RESET_NEVER,
171008ea495dSChaoyong He 			&reset);
171108ea495dSChaoyong He 	if (err != 0) {
171208ea495dSChaoyong He 		PMD_DRV_LOG(ERR, "Get 'abi_drv_reset' from HWinfo failed.");
171308ea495dSChaoyong He 		goto close_nsp;
171408ea495dSChaoyong He 	}
1715646ea79cSHeinrich Kuhn 
171608ea495dSChaoyong He 	err = nfp_fw_policy_value_get(nsp, "app_fw_from_flash",
171708ea495dSChaoyong He 			NFP_NSP_APP_FW_LOAD_DEFAULT, NFP_NSP_APP_FW_LOAD_PREF,
171808ea495dSChaoyong He 			&policy);
171908ea495dSChaoyong He 	if (err != 0) {
172008ea495dSChaoyong He 		PMD_DRV_LOG(ERR, "Get 'app_fw_from_flash' from HWinfo failed.");
172108ea495dSChaoyong He 		goto close_nsp;
172208ea495dSChaoyong He 	}
172308ea495dSChaoyong He 
172408ea495dSChaoyong He 	fw_name[0] = 0;
172508ea495dSChaoyong He 	if (policy != NFP_NSP_APP_FW_LOAD_FLASH) {
17266f708e52SChaoyong He 		err = nfp_fw_get_name(pf_dev, fw_name, sizeof(fw_name));
172708ea495dSChaoyong He 		if (err != 0) {
1728fb86136dSZerun Fu 			PMD_DRV_LOG(ERR, "Can not find suitable firmware.");
172908ea495dSChaoyong He 			goto close_nsp;
173008ea495dSChaoyong He 		}
173108ea495dSChaoyong He 	}
173208ea495dSChaoyong He 
17336f708e52SChaoyong He 	if (pf_dev->multi_pf.enabled)
17346f708e52SChaoyong He 		err = nfp_fw_reload_for_multi_pf(nsp, fw_name, dev_info,
17356f708e52SChaoyong He 				pf_dev, reset, policy);
173608ea495dSChaoyong He 	else
17376f708e52SChaoyong He 		err = nfp_fw_reload_for_single_pf(nsp, fw_name, pf_dev,
17386f708e52SChaoyong He 				reset, policy);
173908ea495dSChaoyong He 
174008ea495dSChaoyong He close_nsp:
1741646ea79cSHeinrich Kuhn 	nfp_nsp_close(nsp);
1742646ea79cSHeinrich Kuhn 	return err;
1743646ea79cSHeinrich Kuhn }
1744646ea79cSHeinrich Kuhn 
17458ad2cc8fSPeng Zhang static inline bool
1746a508fa23SPeng Zhang nfp_check_multi_pf_from_fw(uint32_t total_vnics)
1747a508fa23SPeng Zhang {
1748a508fa23SPeng Zhang 	if (total_vnics == 1)
1749a508fa23SPeng Zhang 		return true;
1750a508fa23SPeng Zhang 
1751a508fa23SPeng Zhang 	return false;
1752a508fa23SPeng Zhang }
1753a508fa23SPeng Zhang 
1754a508fa23SPeng Zhang static inline bool
17558ad2cc8fSPeng Zhang nfp_check_multi_pf_from_nsp(struct rte_pci_device *pci_dev,
17568ad2cc8fSPeng Zhang 		struct nfp_cpp *cpp)
17578ad2cc8fSPeng Zhang {
17588ad2cc8fSPeng Zhang 	bool flag;
17598ad2cc8fSPeng Zhang 	struct nfp_nsp *nsp;
17608ad2cc8fSPeng Zhang 
17618ad2cc8fSPeng Zhang 	nsp = nfp_nsp_open(cpp);
17628ad2cc8fSPeng Zhang 	if (nsp == NULL) {
1763b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle.");
17648ad2cc8fSPeng Zhang 		return false;
17658ad2cc8fSPeng Zhang 	}
17668ad2cc8fSPeng Zhang 
17678ad2cc8fSPeng Zhang 	flag = (nfp_nsp_get_abi_ver_major(nsp) > 0) &&
17688ad2cc8fSPeng Zhang 			(pci_dev->id.device_id == PCI_DEVICE_ID_NFP3800_PF_NIC);
17698ad2cc8fSPeng Zhang 
17708ad2cc8fSPeng Zhang 	nfp_nsp_close(nsp);
17718ad2cc8fSPeng Zhang 	return flag;
17728ad2cc8fSPeng Zhang }
17738ad2cc8fSPeng Zhang 
1774a6189a67SJin Liu static int
177595f978efSPeng Zhang nfp_enable_multi_pf(struct nfp_pf_dev *pf_dev)
177695f978efSPeng Zhang {
177795f978efSPeng Zhang 	int err = 0;
177895f978efSPeng Zhang 	uint64_t tx_base;
177995f978efSPeng Zhang 	uint8_t *ctrl_bar;
178095f978efSPeng Zhang 	struct nfp_hw *hw;
178195f978efSPeng Zhang 	uint32_t cap_extend;
178295f978efSPeng Zhang 	struct nfp_net_hw net_hw;
178395f978efSPeng Zhang 	struct nfp_cpp_area *area;
178495f978efSPeng Zhang 	char name[RTE_ETH_NAME_MAX_LEN];
178595f978efSPeng Zhang 
178695f978efSPeng Zhang 	memset(&net_hw, 0, sizeof(struct nfp_net_hw));
178795f978efSPeng Zhang 
178895f978efSPeng Zhang 	/* Map the symbol table */
178919bd7cceSChaoyong He 	pf_dev->ctrl_bar_size = NFP_NET_CFG_BAR_SZ_MIN;
179095f978efSPeng Zhang 	snprintf(name, sizeof(name), "_pf%u_net_bar0",
179195f978efSPeng Zhang 			pf_dev->multi_pf.function_id);
179219bd7cceSChaoyong He 	ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, name, pf_dev->ctrl_bar_size,
179395f978efSPeng Zhang 			&area);
179495f978efSPeng Zhang 	if (ctrl_bar == NULL) {
1795b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to find data vNIC memory symbol.");
179695f978efSPeng Zhang 		return -ENODEV;
179795f978efSPeng Zhang 	}
179895f978efSPeng Zhang 
179995f978efSPeng Zhang 	hw = &net_hw.super;
180095f978efSPeng Zhang 	hw->ctrl_bar = ctrl_bar;
180195f978efSPeng Zhang 
1802000feb4cSChaoyong He 	/* Check the version from firmware */
1803000feb4cSChaoyong He 	if (!nfp_net_version_check(hw, pf_dev)) {
1804000feb4cSChaoyong He 		PMD_INIT_LOG(ERR, "Not the valid version.");
1805000feb4cSChaoyong He 		err = -EINVAL;
1806000feb4cSChaoyong He 		goto end;
1807000feb4cSChaoyong He 	}
1808000feb4cSChaoyong He 
180919bd7cceSChaoyong He 	/* Set the ctrl bar size */
181019bd7cceSChaoyong He 	nfp_net_ctrl_bar_size_set(pf_dev);
181119bd7cceSChaoyong He 
1812000feb4cSChaoyong He 	if (!pf_dev->multi_pf.enabled)
1813000feb4cSChaoyong He 		goto end;
1814000feb4cSChaoyong He 
181595f978efSPeng Zhang 	cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
181695f978efSPeng Zhang 	if ((cap_extend & NFP_NET_CFG_CTRL_MULTI_PF) == 0) {
1817b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Loaded firmware does not support multiple PF.");
181895f978efSPeng Zhang 		err = -EINVAL;
181995f978efSPeng Zhang 		goto end;
182095f978efSPeng Zhang 	}
182195f978efSPeng Zhang 
182295f978efSPeng Zhang 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
182395f978efSPeng Zhang 	net_hw.tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
182495f978efSPeng Zhang 	nfp_net_cfg_queue_setup(&net_hw);
182595f978efSPeng Zhang 	rte_spinlock_init(&hw->reconfig_lock);
18268c1d15f1SChaoyong He 	err = nfp_ext_reconfig(&net_hw.super, NFP_NET_CFG_CTRL_MULTI_PF,
18278c1d15f1SChaoyong He 			NFP_NET_CFG_UPDATE_GEN);
18288c1d15f1SChaoyong He 	if (err != 0) {
18298c1d15f1SChaoyong He 		PMD_INIT_LOG(ERR, "Configure multiple PF failed.");
18308c1d15f1SChaoyong He 		goto end;
18318c1d15f1SChaoyong He 	}
18328c1d15f1SChaoyong He 
183395f978efSPeng Zhang end:
183495f978efSPeng Zhang 	nfp_cpp_area_release_free(area);
183595f978efSPeng Zhang 	return err;
183695f978efSPeng Zhang }
183795f978efSPeng Zhang 
18386408420cSPeng Zhang static bool
18396408420cSPeng Zhang nfp_app_fw_nic_total_phyports_check(struct nfp_pf_dev *pf_dev)
18406408420cSPeng Zhang {
18416408420cSPeng Zhang 	uint8_t total_phyports;
18426408420cSPeng Zhang 
1843eac7eda4SChaoyong He 	total_phyports = nfp_net_get_phyports_from_fw(pf_dev);
18446408420cSPeng Zhang 
18456408420cSPeng Zhang 	if (pf_dev->multi_pf.enabled) {
18466408420cSPeng Zhang 		if (!nfp_check_multi_pf_from_fw(total_phyports)) {
1847b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "NSP report multipf, but FW report not multipf.");
18486408420cSPeng Zhang 			return false;
18496408420cSPeng Zhang 		}
18506408420cSPeng Zhang 	} else {
18516408420cSPeng Zhang 		/*
18526408420cSPeng Zhang 		 * For single PF the number of vNICs exposed should be the same as the
18536408420cSPeng Zhang 		 * number of physical ports.
18546408420cSPeng Zhang 		 */
18556408420cSPeng Zhang 		if (total_phyports != pf_dev->nfp_eth_table->count) {
1856b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "Total physical ports do not match number of vNICs.");
18576408420cSPeng Zhang 			return false;
18586408420cSPeng Zhang 		}
18596408420cSPeng Zhang 	}
18606408420cSPeng Zhang 
18616408420cSPeng Zhang 	return true;
18626408420cSPeng Zhang }
18636408420cSPeng Zhang 
1864eac7eda4SChaoyong He static void
1865eac7eda4SChaoyong He nfp_port_name_generate(char *port_name,
1866eac7eda4SChaoyong He 		size_t length,
1867eac7eda4SChaoyong He 		int port_id,
1868eac7eda4SChaoyong He 		struct nfp_pf_dev *pf_dev)
1869eac7eda4SChaoyong He {
1870eac7eda4SChaoyong He 	const char *name = pf_dev->pci_dev->device.name;
1871eac7eda4SChaoyong He 
1872eac7eda4SChaoyong He 	if (pf_dev->multi_pf.enabled)
1873eac7eda4SChaoyong He 		snprintf(port_name, length, "%s", name);
1874eac7eda4SChaoyong He 	else
1875eac7eda4SChaoyong He 		snprintf(port_name, length, "%s_port%u", name, port_id);
1876eac7eda4SChaoyong He }
1877eac7eda4SChaoyong He 
187895f978efSPeng Zhang static int
1879d81e2b51SChaoyong He nfp_init_app_fw_nic(struct nfp_net_hw_priv *hw_priv)
1880646ea79cSHeinrich Kuhn {
18818ceb85c3SChaoyong He 	uint8_t i;
18823b00109dSPeng Zhang 	uint8_t id;
1883e7978635SChaoyong He 	int ret = 0;
1884968ec1c3SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
1885a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
18863b00109dSPeng Zhang 	char bar_name[RTE_ETH_NAME_MAX_LEN];
1887646ea79cSHeinrich Kuhn 	char port_name[RTE_ETH_NAME_MAX_LEN];
1888ff9f5a56SChaoyong He 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
18896484c847SChaoyong He 	struct nfp_net_init hw_init = {
18906484c847SChaoyong He 		.hw_priv = hw_priv,
18916484c847SChaoyong He 	};
1892646ea79cSHeinrich Kuhn 
1893968ec1c3SChaoyong He 	nfp_eth_table = pf_dev->nfp_eth_table;
1894b6de4353SZerun Fu 	PMD_INIT_LOG(INFO, "Total physical ports: %d.", nfp_eth_table->count);
18953b00109dSPeng Zhang 	id = nfp_function_id_get(pf_dev, 0);
1896968ec1c3SChaoyong He 
1897968ec1c3SChaoyong He 	/* Allocate memory for the CoreNIC app */
1898968ec1c3SChaoyong He 	app_fw_nic = rte_zmalloc("nfp_app_fw_nic", sizeof(*app_fw_nic), 0);
1899968ec1c3SChaoyong He 	if (app_fw_nic == NULL)
1900968ec1c3SChaoyong He 		return -ENOMEM;
1901968ec1c3SChaoyong He 
1902968ec1c3SChaoyong He 	/* Point the app_fw_priv pointer in the PF to the coreNIC app */
1903968ec1c3SChaoyong He 	pf_dev->app_fw_priv = app_fw_nic;
1904968ec1c3SChaoyong He 
19056408420cSPeng Zhang 	/* Check the number of vNIC's created for the PF */
19066408420cSPeng Zhang 	if (!nfp_app_fw_nic_total_phyports_check(pf_dev)) {
1907968ec1c3SChaoyong He 		ret = -ENODEV;
1908968ec1c3SChaoyong He 		goto app_cleanup;
1909968ec1c3SChaoyong He 	}
1910968ec1c3SChaoyong He 
1911968ec1c3SChaoyong He 	/* Populate coreNIC app properties */
19126408420cSPeng Zhang 	if (pf_dev->total_phyports > 1)
1913968ec1c3SChaoyong He 		app_fw_nic->multiport = true;
1914968ec1c3SChaoyong He 
1915968ec1c3SChaoyong He 	/* Map the symbol table */
19163b00109dSPeng Zhang 	snprintf(bar_name, sizeof(bar_name), "_pf%u_net_bar0", id);
19173b00109dSPeng Zhang 	pf_dev->ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, bar_name,
191819bd7cceSChaoyong He 			pf_dev->total_phyports * pf_dev->ctrl_bar_size,
1919d5e9fc86SChaoyong He 			&pf_dev->ctrl_area);
1920968ec1c3SChaoyong He 	if (pf_dev->ctrl_bar == NULL) {
1921b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "The nfp_rtsym_map fails for %s.", bar_name);
1922968ec1c3SChaoyong He 		ret = -EIO;
1923968ec1c3SChaoyong He 		goto app_cleanup;
1924968ec1c3SChaoyong He 	}
1925968ec1c3SChaoyong He 
1926b6de4353SZerun Fu 	PMD_INIT_LOG(DEBUG, "Ctrl bar: %p.", pf_dev->ctrl_bar);
1927968ec1c3SChaoyong He 
1928968ec1c3SChaoyong He 	/* Loop through all physical ports on PF */
19296408420cSPeng Zhang 	for (i = 0; i < pf_dev->total_phyports; i++) {
1930eac7eda4SChaoyong He 		nfp_port_name_generate(port_name, sizeof(port_name), i, pf_dev);
1931646ea79cSHeinrich Kuhn 
1932c92c83d4SPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
19336484c847SChaoyong He 		hw_init.idx = id;
19346484c847SChaoyong He 		hw_init.nfp_idx = nfp_eth_table->ports[id].index;
19356484c847SChaoyong He 		ret = rte_eth_dev_create(&pf_dev->pci_dev->device, port_name,
19366484c847SChaoyong He 				sizeof(struct nfp_net_hw), NULL, NULL,
19376484c847SChaoyong He 				nfp_net_init, &hw_init);
19386484c847SChaoyong He 		if (ret != 0)
1939646ea79cSHeinrich Kuhn 			goto port_cleanup;
1940646ea79cSHeinrich Kuhn 
1941646ea79cSHeinrich Kuhn 	} /* End loop, all ports on this PF */
1942968ec1c3SChaoyong He 
1943968ec1c3SChaoyong He 	return 0;
1944646ea79cSHeinrich Kuhn 
1945646ea79cSHeinrich Kuhn port_cleanup:
1946eac7eda4SChaoyong He 	for (uint32_t j = 0; j < i; j++) {
1947a9fa1da7SChaoyong He 		struct rte_eth_dev *eth_dev;
19483b00109dSPeng Zhang 
1949eac7eda4SChaoyong He 		nfp_port_name_generate(port_name, sizeof(port_name), j, pf_dev);
1950a9fa1da7SChaoyong He 		eth_dev = rte_eth_dev_get_by_name(port_name);
19516484c847SChaoyong He 		if (eth_dev != NULL)
19526484c847SChaoyong He 			rte_eth_dev_destroy(eth_dev, nfp_net_uninit);
1953646ea79cSHeinrich Kuhn 	}
19548b8f116bSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
1955968ec1c3SChaoyong He app_cleanup:
1956968ec1c3SChaoyong He 	rte_free(app_fw_nic);
1957a6189a67SJin Liu 
1958646ea79cSHeinrich Kuhn 	return ret;
1959646ea79cSHeinrich Kuhn }
1960646ea79cSHeinrich Kuhn 
1961a6189a67SJin Liu static int
1962c7a6970fSZerun Fu nfp_net_hwinfo_set(uint8_t function_id,
1963c7a6970fSZerun Fu 		struct nfp_rtsym_table *sym_tbl,
1964103134d2SZerun Fu 		struct nfp_cpp *cpp,
1965103134d2SZerun Fu 		enum nfp_app_fw_id app_fw_id)
1966c7a6970fSZerun Fu {
1967c7a6970fSZerun Fu 	int ret = 0;
1968c7a6970fSZerun Fu 	uint64_t app_cap;
1969c7a6970fSZerun Fu 	struct nfp_nsp *nsp;
1970103134d2SZerun Fu 	uint8_t sp_indiff = 1;
1971c7a6970fSZerun Fu 	char hw_info[RTE_ETH_NAME_MAX_LEN];
1972c7a6970fSZerun Fu 	char app_cap_name[RTE_ETH_NAME_MAX_LEN];
1973c7a6970fSZerun Fu 
1974103134d2SZerun Fu 	if (app_fw_id != NFP_APP_FW_FLOWER_NIC) {
1975c7a6970fSZerun Fu 		/* Read the app capabilities of the firmware loaded */
1976c7a6970fSZerun Fu 		snprintf(app_cap_name, sizeof(app_cap_name), "_pf%u_net_app_cap", function_id);
1977c7a6970fSZerun Fu 		app_cap = nfp_rtsym_read_le(sym_tbl, app_cap_name, &ret);
1978c7a6970fSZerun Fu 		if (ret != 0) {
1979103134d2SZerun Fu 			PMD_INIT_LOG(ERR, "Could not read app_fw_cap from firmware.");
1980c7a6970fSZerun Fu 			return ret;
1981c7a6970fSZerun Fu 		}
1982c7a6970fSZerun Fu 
1983c7a6970fSZerun Fu 		/* Calculate the value of sp_indiff and write to hw_info */
1984c7a6970fSZerun Fu 		sp_indiff = app_cap & NFP_NET_APP_CAP_SP_INDIFF;
1985103134d2SZerun Fu 	}
1986103134d2SZerun Fu 
1987c7a6970fSZerun Fu 	snprintf(hw_info, sizeof(hw_info), "sp_indiff=%u", sp_indiff);
1988c7a6970fSZerun Fu 
1989c7a6970fSZerun Fu 	nsp = nfp_nsp_open(cpp);
1990c7a6970fSZerun Fu 	if (nsp == NULL) {
1991103134d2SZerun Fu 		PMD_INIT_LOG(ERR, "Could not get NSP.");
1992c7a6970fSZerun Fu 		return -EIO;
1993c7a6970fSZerun Fu 	}
1994c7a6970fSZerun Fu 
1995c7a6970fSZerun Fu 	ret = nfp_nsp_hwinfo_set(nsp, hw_info, sizeof(hw_info));
1996c7a6970fSZerun Fu 	nfp_nsp_close(nsp);
1997c7a6970fSZerun Fu 	if (ret != 0) {
1998c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set parameter to hwinfo.");
1999c7a6970fSZerun Fu 		return ret;
2000c7a6970fSZerun Fu 	}
2001c7a6970fSZerun Fu 
2002c7a6970fSZerun Fu 	return 0;
2003c7a6970fSZerun Fu }
2004c7a6970fSZerun Fu 
20053110ab73SZerun Fu const uint32_t nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
20063110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M]     = RTE_ETH_LINK_SPEED_10M,
20073110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M_HD]  = RTE_ETH_LINK_SPEED_10M_HD,
20083110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M]    = RTE_ETH_LINK_SPEED_100M,
20093110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M_HD] = RTE_ETH_LINK_SPEED_100M_HD,
20103110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_1G]      = RTE_ETH_LINK_SPEED_1G,
20113110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_2P5G]    = RTE_ETH_LINK_SPEED_2_5G,
20123110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_5G]      = RTE_ETH_LINK_SPEED_5G,
20133110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10G]     = RTE_ETH_LINK_SPEED_10G,
20143110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_CX]     = RTE_ETH_LINK_SPEED_1G,
20153110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_KX]     = RTE_ETH_LINK_SPEED_1G,
20163110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KX4]     = RTE_ETH_LINK_SPEED_10G,
20173110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KR]      = RTE_ETH_LINK_SPEED_10G,
20183110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CX4]     = RTE_ETH_LINK_SPEED_10G,
20193110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CR]      = RTE_ETH_LINK_SPEED_10G,
20203110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_SR]      = RTE_ETH_LINK_SPEED_10G,
20213110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_ER]      = RTE_ETH_LINK_SPEED_10G,
20223110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR]      = RTE_ETH_LINK_SPEED_25G,
20233110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR_S]    = RTE_ETH_LINK_SPEED_25G,
20243110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR]      = RTE_ETH_LINK_SPEED_25G,
20253110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR_S]    = RTE_ETH_LINK_SPEED_25G,
20263110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_SR]      = RTE_ETH_LINK_SPEED_25G,
20273110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_CR4]     = RTE_ETH_LINK_SPEED_40G,
20283110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_KR4]     = RTE_ETH_LINK_SPEED_40G,
20293110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_SR4]     = RTE_ETH_LINK_SPEED_40G,
20303110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_LR4]     = RTE_ETH_LINK_SPEED_40G,
20313110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_KR]      = RTE_ETH_LINK_SPEED_50G,
20323110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_SR]      = RTE_ETH_LINK_SPEED_50G,
20333110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_CR]      = RTE_ETH_LINK_SPEED_50G,
20343110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_LR]      = RTE_ETH_LINK_SPEED_50G,
20353110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_ER]      = RTE_ETH_LINK_SPEED_50G,
20363110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_FR]      = RTE_ETH_LINK_SPEED_50G,
20373110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KR4]    = RTE_ETH_LINK_SPEED_100G,
20383110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_SR4]    = RTE_ETH_LINK_SPEED_100G,
20393110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR4]    = RTE_ETH_LINK_SPEED_100G,
20403110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KP4]    = RTE_ETH_LINK_SPEED_100G,
20413110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR10]   = RTE_ETH_LINK_SPEED_100G,
20423110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_LR]      = RTE_ETH_LINK_SPEED_10G,
20433110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_LR]      = RTE_ETH_LINK_SPEED_25G,
20443110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_ER]      = RTE_ETH_LINK_SPEED_25G
20453110ab73SZerun Fu };
20463110ab73SZerun Fu 
20473110ab73SZerun Fu static int
20483110ab73SZerun Fu nfp_net_speed_capa_get_real(struct nfp_eth_media_buf *media_buf,
20493110ab73SZerun Fu 		struct nfp_pf_dev *pf_dev)
20503110ab73SZerun Fu {
20513110ab73SZerun Fu 	uint32_t i;
20523110ab73SZerun Fu 	uint32_t j;
20533110ab73SZerun Fu 	uint32_t offset;
20543110ab73SZerun Fu 	uint32_t speed_capa = 0;
20553110ab73SZerun Fu 	uint64_t supported_modes;
20563110ab73SZerun Fu 
20573110ab73SZerun Fu 	for (i = 0; i < RTE_DIM(media_buf->supported_modes); i++) {
20583110ab73SZerun Fu 		supported_modes = media_buf->supported_modes[i];
20593110ab73SZerun Fu 		offset = i * UINT64_BIT;
20603110ab73SZerun Fu 		for (j = 0; j < UINT64_BIT; j++) {
20613110ab73SZerun Fu 			if (supported_modes == 0)
20623110ab73SZerun Fu 				break;
20633110ab73SZerun Fu 
20643110ab73SZerun Fu 			if ((supported_modes & 1) != 0) {
20653110ab73SZerun Fu 				if ((j + offset) >= NFP_MEDIA_LINK_MODES_NUMBER) {
20663110ab73SZerun Fu 					PMD_DRV_LOG(ERR, "Invalid offset of media table.");
20673110ab73SZerun Fu 					return -EINVAL;
20683110ab73SZerun Fu 				}
20693110ab73SZerun Fu 
20703110ab73SZerun Fu 				speed_capa |= nfp_eth_media_table[j + offset];
20713110ab73SZerun Fu 			}
20723110ab73SZerun Fu 
20733110ab73SZerun Fu 			supported_modes = supported_modes >> 1;
20743110ab73SZerun Fu 		}
20753110ab73SZerun Fu 	}
20763110ab73SZerun Fu 
20773110ab73SZerun Fu 	pf_dev->speed_capa = speed_capa;
20783110ab73SZerun Fu 
20793110ab73SZerun Fu 	return pf_dev->speed_capa == 0 ? -EINVAL : 0;
20803110ab73SZerun Fu }
20813110ab73SZerun Fu 
20823110ab73SZerun Fu static int
20835b46a539SPeng Zhang nfp_net_speed_cap_get_one(struct nfp_pf_dev *pf_dev,
20843110ab73SZerun Fu 		uint32_t port_id)
20853110ab73SZerun Fu {
20863110ab73SZerun Fu 	int ret;
20873110ab73SZerun Fu 	struct nfp_nsp *nsp;
20883110ab73SZerun Fu 	struct nfp_eth_media_buf media_buf;
20893110ab73SZerun Fu 
20903110ab73SZerun Fu 	media_buf.eth_index = pf_dev->nfp_eth_table->ports[port_id].eth_index;
20913110ab73SZerun Fu 	pf_dev->speed_capa = 0;
20923110ab73SZerun Fu 
20933110ab73SZerun Fu 	nsp = nfp_nsp_open(pf_dev->cpp);
20943110ab73SZerun Fu 	if (nsp == NULL) {
2095fb86136dSZerun Fu 		PMD_DRV_LOG(ERR, "Could not get NSP.");
20963110ab73SZerun Fu 		return -EIO;
20973110ab73SZerun Fu 	}
20983110ab73SZerun Fu 
20993110ab73SZerun Fu 	ret = nfp_nsp_read_media(nsp, &media_buf, sizeof(media_buf));
21003110ab73SZerun Fu 	nfp_nsp_close(nsp);
21013110ab73SZerun Fu 	if (ret != 0) {
21023110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to read media.");
21033110ab73SZerun Fu 		return ret;
21043110ab73SZerun Fu 	}
21053110ab73SZerun Fu 
21063110ab73SZerun Fu 	ret = nfp_net_speed_capa_get_real(&media_buf, pf_dev);
21073110ab73SZerun Fu 	if (ret < 0) {
21083110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Speed capability is invalid.");
21093110ab73SZerun Fu 		return ret;
21103110ab73SZerun Fu 	}
21113110ab73SZerun Fu 
21123110ab73SZerun Fu 	return 0;
21133110ab73SZerun Fu }
21143110ab73SZerun Fu 
21155b46a539SPeng Zhang static int
21165b46a539SPeng Zhang nfp_net_speed_cap_get(struct nfp_pf_dev *pf_dev)
21175b46a539SPeng Zhang {
21185b46a539SPeng Zhang 	int ret;
21195b46a539SPeng Zhang 	uint32_t i;
21205b46a539SPeng Zhang 	uint32_t id;
21215b46a539SPeng Zhang 	uint32_t count;
21225b46a539SPeng Zhang 
21236f708e52SChaoyong He 	count = pf_dev->total_phyports;
21245b46a539SPeng Zhang 	for (i = 0; i < count; i++) {
21255b46a539SPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
21265b46a539SPeng Zhang 		ret = nfp_net_speed_cap_get_one(pf_dev, id);
21275b46a539SPeng Zhang 		if (ret != 0) {
21285b46a539SPeng Zhang 			PMD_INIT_LOG(ERR, "Failed to get port %d speed capability.", id);
21295b46a539SPeng Zhang 			return ret;
21305b46a539SPeng Zhang 		}
21315b46a539SPeng Zhang 	}
21325b46a539SPeng Zhang 
21335b46a539SPeng Zhang 	return 0;
21345b46a539SPeng Zhang }
21355b46a539SPeng Zhang 
2136bd4969abSPeng Zhang /* Force the physical port down to clear the possible DMA error */
2137bd4969abSPeng Zhang static int
21386f708e52SChaoyong He nfp_net_force_port_down(struct nfp_pf_dev *pf_dev)
2139bd4969abSPeng Zhang {
2140bd4969abSPeng Zhang 	int ret;
2141bd4969abSPeng Zhang 	uint32_t i;
2142bd4969abSPeng Zhang 	uint32_t id;
2143bd4969abSPeng Zhang 	uint32_t index;
2144bd4969abSPeng Zhang 	uint32_t count;
2145bd4969abSPeng Zhang 
21466f708e52SChaoyong He 	count = pf_dev->total_phyports;
2147bd4969abSPeng Zhang 	for (i = 0; i < count; i++) {
2148bd4969abSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
21496f708e52SChaoyong He 		index = pf_dev->nfp_eth_table->ports[id].index;
21506f708e52SChaoyong He 		ret = nfp_eth_set_configured(pf_dev->cpp, index, 0);
2151bd4969abSPeng Zhang 		if (ret < 0)
2152bd4969abSPeng Zhang 			return ret;
2153bd4969abSPeng Zhang 	}
2154bd4969abSPeng Zhang 
2155bd4969abSPeng Zhang 	return 0;
2156bd4969abSPeng Zhang }
2157bd4969abSPeng Zhang 
2158c7a6970fSZerun Fu static int
2159e51160adSPeng Zhang nfp_fw_app_primary_init(struct nfp_net_hw_priv *hw_priv)
2160e51160adSPeng Zhang {
2161e51160adSPeng Zhang 	int ret;
2162e51160adSPeng Zhang 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
2163e51160adSPeng Zhang 
2164e51160adSPeng Zhang 	switch (pf_dev->app_fw_id) {
2165e51160adSPeng Zhang 	case NFP_APP_FW_CORE_NIC:
2166b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Initializing coreNIC.");
2167e51160adSPeng Zhang 		ret = nfp_init_app_fw_nic(hw_priv);
2168e51160adSPeng Zhang 		if (ret != 0) {
2169e51160adSPeng Zhang 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
2170e51160adSPeng Zhang 			return ret;
2171e51160adSPeng Zhang 		}
2172e51160adSPeng Zhang 		break;
2173e51160adSPeng Zhang 	case NFP_APP_FW_FLOWER_NIC:
2174b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Initializing Flower.");
2175e51160adSPeng Zhang 		ret = nfp_init_app_fw_flower(hw_priv);
2176e51160adSPeng Zhang 		if (ret != 0) {
2177e51160adSPeng Zhang 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
2178e51160adSPeng Zhang 			return ret;
2179e51160adSPeng Zhang 		}
2180e51160adSPeng Zhang 		break;
2181e51160adSPeng Zhang 	default:
2182b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded.");
2183e51160adSPeng Zhang 		ret = -EINVAL;
2184e51160adSPeng Zhang 		return ret;
2185e51160adSPeng Zhang 	}
2186e51160adSPeng Zhang 
2187e51160adSPeng Zhang 	return 0;
2188e51160adSPeng Zhang }
2189e51160adSPeng Zhang 
2190e51160adSPeng Zhang static int
219120086cb8SPeng Zhang nfp_pf_get_max_vf(struct nfp_pf_dev *pf_dev)
219220086cb8SPeng Zhang {
219320086cb8SPeng Zhang 	int ret;
219420086cb8SPeng Zhang 	uint32_t max_vfs;
219520086cb8SPeng Zhang 
219620086cb8SPeng Zhang 	max_vfs = nfp_rtsym_read_le(pf_dev->sym_tbl, "nfd_vf_cfg_max_vfs", &ret);
219720086cb8SPeng Zhang 	if (ret != 0)
219820086cb8SPeng Zhang 		return ret;
219920086cb8SPeng Zhang 
220020086cb8SPeng Zhang 	pf_dev->max_vfs = max_vfs;
220120086cb8SPeng Zhang 
220220086cb8SPeng Zhang 	return 0;
220320086cb8SPeng Zhang }
220420086cb8SPeng Zhang 
220520086cb8SPeng Zhang static int
220620086cb8SPeng Zhang nfp_pf_get_sriov_vf(struct nfp_pf_dev *pf_dev,
220720086cb8SPeng Zhang 		const struct nfp_dev_info *dev_info)
220820086cb8SPeng Zhang {
220920086cb8SPeng Zhang 	int ret;
221020086cb8SPeng Zhang 	off_t pos;
221120086cb8SPeng Zhang 	uint16_t offset;
221220086cb8SPeng Zhang 	uint16_t sriov_vf;
221320086cb8SPeng Zhang 
221420086cb8SPeng Zhang 	/* For 3800 single-PF and 4000 card */
221520086cb8SPeng Zhang 	if (!pf_dev->multi_pf.enabled) {
221620086cb8SPeng Zhang 		pf_dev->sriov_vf = pf_dev->max_vfs;
221720086cb8SPeng Zhang 		return 0;
221820086cb8SPeng Zhang 	}
221920086cb8SPeng Zhang 
222020086cb8SPeng Zhang 	pos = rte_pci_find_ext_capability(pf_dev->pci_dev, RTE_PCI_EXT_CAP_ID_SRIOV);
222120086cb8SPeng Zhang 	if (pos == 0) {
2222b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not get the pci sriov cap.");
222320086cb8SPeng Zhang 		return -EIO;
222420086cb8SPeng Zhang 	}
222520086cb8SPeng Zhang 
222620086cb8SPeng Zhang 	/*
222720086cb8SPeng Zhang 	 * Management firmware ensures that sriov capability registers
222820086cb8SPeng Zhang 	 * are initialized correctly.
222920086cb8SPeng Zhang 	 */
223020086cb8SPeng Zhang 	ret = rte_pci_read_config(pf_dev->pci_dev, &sriov_vf, sizeof(sriov_vf),
223120086cb8SPeng Zhang 			pos + RTE_PCI_SRIOV_TOTAL_VF);
223220086cb8SPeng Zhang 	if (ret < 0) {
2233b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not read the sriov toatl VF.");
223420086cb8SPeng Zhang 		return -EIO;
223520086cb8SPeng Zhang 	}
223620086cb8SPeng Zhang 
223720086cb8SPeng Zhang 	/* Offset of first VF is relative to its PF. */
223820086cb8SPeng Zhang 	ret = rte_pci_read_config(pf_dev->pci_dev, &offset, sizeof(offset),
223920086cb8SPeng Zhang 			pos + RTE_PCI_SRIOV_VF_OFFSET);
224020086cb8SPeng Zhang 	if (ret < 0) {
2241b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not get the VF offset.");
224220086cb8SPeng Zhang 		return -EIO;
224320086cb8SPeng Zhang 	}
224420086cb8SPeng Zhang 
224520086cb8SPeng Zhang 	offset += pf_dev->multi_pf.function_id;
224620086cb8SPeng Zhang 	if (offset < dev_info->pf_num_per_unit)
224720086cb8SPeng Zhang 		return -ERANGE;
224820086cb8SPeng Zhang 
224920086cb8SPeng Zhang 	offset -= dev_info->pf_num_per_unit;
225020086cb8SPeng Zhang 	if (offset >= pf_dev->max_vfs || offset + sriov_vf > pf_dev->max_vfs) {
2251b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "The pci allocate VF is more than the MAX VF.");
225220086cb8SPeng Zhang 		return -ERANGE;
225320086cb8SPeng Zhang 	}
225420086cb8SPeng Zhang 
2255d4e160acSPeng Zhang 	pf_dev->vf_base_id = offset;
225620086cb8SPeng Zhang 	pf_dev->sriov_vf = sriov_vf;
225720086cb8SPeng Zhang 
225820086cb8SPeng Zhang 	return 0;
225920086cb8SPeng Zhang }
226020086cb8SPeng Zhang 
226120086cb8SPeng Zhang static int
226220086cb8SPeng Zhang nfp_net_get_vf_info(struct nfp_pf_dev *pf_dev,
226320086cb8SPeng Zhang 		const struct nfp_dev_info *dev_info)
226420086cb8SPeng Zhang {
226520086cb8SPeng Zhang 	int ret;
226620086cb8SPeng Zhang 
226720086cb8SPeng Zhang 	ret = nfp_pf_get_max_vf(pf_dev);
226820086cb8SPeng Zhang 	if (ret != 0) {
226920086cb8SPeng Zhang 		if (ret != -ENOENT) {
2270b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "Read max VFs failed.");
227120086cb8SPeng Zhang 			return ret;
227220086cb8SPeng Zhang 		}
227320086cb8SPeng Zhang 
2274b6de4353SZerun Fu 		PMD_INIT_LOG(WARNING, "The firmware can not support read max VFs.");
227520086cb8SPeng Zhang 		return 0;
227620086cb8SPeng Zhang 	}
227720086cb8SPeng Zhang 
227820086cb8SPeng Zhang 	if (pf_dev->max_vfs == 0)
227920086cb8SPeng Zhang 		return 0;
228020086cb8SPeng Zhang 
228120086cb8SPeng Zhang 	ret = nfp_pf_get_sriov_vf(pf_dev, dev_info);
228220086cb8SPeng Zhang 	if (ret < 0)
228320086cb8SPeng Zhang 		return ret;
228420086cb8SPeng Zhang 
2285bb24eb38SPeng Zhang 	pf_dev->queue_per_vf = NFP_QUEUE_PER_VF;
2286bb24eb38SPeng Zhang 
228720086cb8SPeng Zhang 	return 0;
228820086cb8SPeng Zhang }
228920086cb8SPeng Zhang 
229020086cb8SPeng Zhang static int
229119542093SPeng Zhang nfp_net_vf_config_init(struct nfp_pf_dev *pf_dev)
229219542093SPeng Zhang {
229319542093SPeng Zhang 	int ret = 0;
229419542093SPeng Zhang 	uint32_t min_size;
229519542093SPeng Zhang 	char vf_bar_name[RTE_ETH_NAME_MAX_LEN];
229619542093SPeng Zhang 	char vf_cfg_name[RTE_ETH_NAME_MAX_LEN];
229719542093SPeng Zhang 
229819542093SPeng Zhang 	if (pf_dev->sriov_vf == 0)
229919542093SPeng Zhang 		return 0;
230019542093SPeng Zhang 
230119bd7cceSChaoyong He 	min_size = pf_dev->ctrl_bar_size * pf_dev->sriov_vf;
230219542093SPeng Zhang 	snprintf(vf_bar_name, sizeof(vf_bar_name), "_pf%d_net_vf_bar",
230319542093SPeng Zhang 			pf_dev->multi_pf.function_id);
230419542093SPeng Zhang 	pf_dev->vf_bar = nfp_rtsym_map_offset(pf_dev->sym_tbl, vf_bar_name,
230519bd7cceSChaoyong He 			pf_dev->ctrl_bar_size * pf_dev->vf_base_id,
230619542093SPeng Zhang 			min_size, &pf_dev->vf_area);
230719542093SPeng Zhang 	if (pf_dev->vf_bar == NULL) {
230819542093SPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to get vf cfg.");
230919542093SPeng Zhang 		return -EIO;
231019542093SPeng Zhang 	}
231119542093SPeng Zhang 
231219542093SPeng Zhang 	min_size = NFP_NET_VF_CFG_SZ * pf_dev->sriov_vf + NFP_NET_VF_CFG_MB_SZ;
231319542093SPeng Zhang 	snprintf(vf_cfg_name, sizeof(vf_cfg_name), "_pf%d_net_vf_cfg2",
231419542093SPeng Zhang 			pf_dev->multi_pf.function_id);
231519542093SPeng Zhang 	pf_dev->vf_cfg_tbl_bar = nfp_rtsym_map(pf_dev->sym_tbl, vf_cfg_name,
231619542093SPeng Zhang 			min_size, &pf_dev->vf_cfg_tbl_area);
231719542093SPeng Zhang 	if (pf_dev->vf_cfg_tbl_bar == NULL) {
231819542093SPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to get vf configure table.");
231919542093SPeng Zhang 		ret = -EIO;
232019542093SPeng Zhang 		goto vf_bar_cleanup;
232119542093SPeng Zhang 	}
232219542093SPeng Zhang 
232319542093SPeng Zhang 	return 0;
232419542093SPeng Zhang 
232519542093SPeng Zhang vf_bar_cleanup:
232619542093SPeng Zhang 	nfp_cpp_area_release_free(pf_dev->vf_area);
232719542093SPeng Zhang 
232819542093SPeng Zhang 	return ret;
232919542093SPeng Zhang }
233019542093SPeng Zhang 
233119542093SPeng Zhang static int
2332a6189a67SJin Liu nfp_pf_init(struct rte_pci_device *pci_dev)
2333646ea79cSHeinrich Kuhn {
23346b4273a0SLong Wu 	void *sync;
2335e7978635SChaoyong He 	int ret = 0;
23365c464d6aSJin Liu 	uint64_t addr;
2337925c27ecSChaoyong He 	uint32_t cpp_id;
23383b00109dSPeng Zhang 	uint8_t function_id;
2339a6189a67SJin Liu 	struct nfp_cpp *cpp;
2340a6189a67SJin Liu 	struct nfp_pf_dev *pf_dev;
2341a6189a67SJin Liu 	struct nfp_hwinfo *hwinfo;
234249952141SChaoyong He 	enum nfp_app_fw_id app_fw_id;
2343a6189a67SJin Liu 	char name[RTE_ETH_NAME_MAX_LEN];
2344a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
2345ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
23463b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
2347a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
23480314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
2349646ea79cSHeinrich Kuhn 
2350a6189a67SJin Liu 	if (pci_dev == NULL)
2351a6189a67SJin Liu 		return -ENODEV;
2352646ea79cSHeinrich Kuhn 
235384aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
235484aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
235584aaba5aSChaoyong He 		return -ENODEV;
235684aaba5aSChaoyong He 	}
235784aaba5aSChaoyong He 
23580314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
23590314a8ffSChaoyong He 	if (dev_info == NULL) {
2360b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Not supported device ID.");
23610314a8ffSChaoyong He 		return -ENODEV;
23620314a8ffSChaoyong He 	}
23630314a8ffSChaoyong He 
2364ff9f5a56SChaoyong He 	hw_priv = rte_zmalloc(NULL, sizeof(*hw_priv), 0);
2365ff9f5a56SChaoyong He 	if (hw_priv == NULL) {
2366b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not alloc memory for hw priv data.");
2367ff9f5a56SChaoyong He 		return -ENOMEM;
2368ff9f5a56SChaoyong He 	}
2369ff9f5a56SChaoyong He 
23708ad2cc8fSPeng Zhang 	/* Allocate memory for the PF "device" */
23713b00109dSPeng Zhang 	function_id = (pci_dev->addr.function) & 0x07;
23723b00109dSPeng Zhang 	snprintf(name, sizeof(name), "nfp_pf%u", function_id);
23738ad2cc8fSPeng Zhang 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
23748ad2cc8fSPeng Zhang 	if (pf_dev == NULL) {
2375b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not allocate memory for the PF device.");
2376ff9f5a56SChaoyong He 		ret = -ENOMEM;
2377ff9f5a56SChaoyong He 		goto hw_priv_free;
23788ad2cc8fSPeng Zhang 	}
23798ad2cc8fSPeng Zhang 
23806f708e52SChaoyong He 	hw_priv->dev_info = dev_info;
23816f708e52SChaoyong He 	hw_priv->pf_dev = pf_dev;
23826f708e52SChaoyong He 
23836b4273a0SLong Wu 	sync = nfp_sync_alloc();
23846b4273a0SLong Wu 	if (sync == NULL) {
23856b4273a0SLong Wu 		PMD_INIT_LOG(ERR, "Failed to alloc sync zone.");
23866b4273a0SLong Wu 		ret = -ENOMEM;
23876b4273a0SLong Wu 		goto pf_cleanup;
23886b4273a0SLong Wu 	}
23896b4273a0SLong Wu 
23906f708e52SChaoyong He 	pf_dev->sync = sync;
23916f708e52SChaoyong He 
2392646ea79cSHeinrich Kuhn 	/*
2393646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
2394646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
2395646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
2396646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
2397646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
2398646ea79cSHeinrich Kuhn 	 */
2399646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
24001fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
2401646ea79cSHeinrich Kuhn 	else
24021fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
2403646ea79cSHeinrich Kuhn 
2404a6189a67SJin Liu 	if (cpp == NULL) {
2405b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained.");
24068ad2cc8fSPeng Zhang 		ret = -EIO;
24076b4273a0SLong Wu 		goto sync_free;
2408646ea79cSHeinrich Kuhn 	}
2409646ea79cSHeinrich Kuhn 
24106f708e52SChaoyong He 	pf_dev->cpp = cpp;
24116f708e52SChaoyong He 	pf_dev->pci_dev = pci_dev;
24126f708e52SChaoyong He 
2413646ea79cSHeinrich Kuhn 	hwinfo = nfp_hwinfo_read(cpp);
2414a6189a67SJin Liu 	if (hwinfo == NULL) {
2415b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Error reading hwinfo table.");
2416646ea79cSHeinrich Kuhn 		ret = -EIO;
2417968ec1c3SChaoyong He 		goto cpp_cleanup;
2418646ea79cSHeinrich Kuhn 	}
2419646ea79cSHeinrich Kuhn 
24206f708e52SChaoyong He 	pf_dev->hwinfo = hwinfo;
24216f708e52SChaoyong He 
2422968ec1c3SChaoyong He 	/* Read the number of physical ports from hardware */
2423646ea79cSHeinrich Kuhn 	nfp_eth_table = nfp_eth_read_ports(cpp);
2424a6189a67SJin Liu 	if (nfp_eth_table == NULL) {
2425b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Error reading NFP ethernet table.");
2426646ea79cSHeinrich Kuhn 		ret = -EIO;
2427646ea79cSHeinrich Kuhn 		goto hwinfo_cleanup;
2428646ea79cSHeinrich Kuhn 	}
2429646ea79cSHeinrich Kuhn 
243030f9f163SChaoyong He 	if (nfp_eth_table->count == 0 || nfp_eth_table->count > 8) {
2431b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "NFP ethernet table reports wrong ports: %u.",
243230f9f163SChaoyong He 				nfp_eth_table->count);
243330f9f163SChaoyong He 		ret = -EIO;
243430f9f163SChaoyong He 		goto eth_table_cleanup;
243530f9f163SChaoyong He 	}
243630f9f163SChaoyong He 
24376f708e52SChaoyong He 	pf_dev->nfp_eth_table = nfp_eth_table;
24388ad2cc8fSPeng Zhang 	pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_nsp(pci_dev, cpp);
24393b00109dSPeng Zhang 	pf_dev->multi_pf.function_id = function_id;
2440eac7eda4SChaoyong He 	pf_dev->total_phyports = nfp_net_get_phyports_from_nsp(pf_dev);
24418ad2cc8fSPeng Zhang 
24426f708e52SChaoyong He 	ret = nfp_net_force_port_down(pf_dev);
2443bd4969abSPeng Zhang 	if (ret != 0) {
2444b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to force port down.");
2445bd4969abSPeng Zhang 		ret = -EIO;
2446bd4969abSPeng Zhang 		goto eth_table_cleanup;
24473b00109dSPeng Zhang 	}
24489e442599SShihong Wang 
24491a114cd0SLong Wu 	ret = nfp_devargs_parse(&pf_dev->devargs, pci_dev->device.devargs);
24501a114cd0SLong Wu 	if (ret != 0) {
2451b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Error when parsing device args.");
24521a114cd0SLong Wu 		ret = -EINVAL;
24531a114cd0SLong Wu 		goto eth_table_cleanup;
24541a114cd0SLong Wu 	}
2455b301fd73SPeng Zhang 
24566f708e52SChaoyong He 	ret = nfp_net_device_activate(pf_dev);
245708461d7bSPeng Zhang 	if (ret != 0) {
2458b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to activate the NFP device.");
245908461d7bSPeng Zhang 		ret = -EIO;
246008461d7bSPeng Zhang 		goto eth_table_cleanup;
246108461d7bSPeng Zhang 	}
246208461d7bSPeng Zhang 
24636f708e52SChaoyong He 	ret = nfp_fw_setup(pf_dev, dev_info);
24646f708e52SChaoyong He 	if (ret != 0) {
2465b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Error when uploading firmware.");
2466646ea79cSHeinrich Kuhn 		ret = -EIO;
2467646ea79cSHeinrich Kuhn 		goto eth_table_cleanup;
2468646ea79cSHeinrich Kuhn 	}
2469646ea79cSHeinrich Kuhn 
2470646ea79cSHeinrich Kuhn 	/* Now the symbol table should be there */
2471646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
2472a6189a67SJin Liu 	if (sym_tbl == NULL) {
2473b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table.");
2474646ea79cSHeinrich Kuhn 		ret = -EIO;
24753b00109dSPeng Zhang 		goto fw_cleanup;
2476646ea79cSHeinrich Kuhn 	}
2477646ea79cSHeinrich Kuhn 
24786f708e52SChaoyong He 	pf_dev->sym_tbl = sym_tbl;
24796f708e52SChaoyong He 
2480968ec1c3SChaoyong He 	/* Read the app ID of the firmware loaded */
24813b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
24823b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
2483e7978635SChaoyong He 	if (ret != 0) {
2484b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Could not read %s from firmware.", app_name);
2485646ea79cSHeinrich Kuhn 		ret = -EIO;
2486646ea79cSHeinrich Kuhn 		goto sym_tbl_cleanup;
2487646ea79cSHeinrich Kuhn 	}
2488646ea79cSHeinrich Kuhn 
24896f708e52SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
24906f708e52SChaoyong He 
2491c7a6970fSZerun Fu 	/* Write sp_indiff to hw_info */
2492103134d2SZerun Fu 	ret = nfp_net_hwinfo_set(function_id, sym_tbl, cpp, app_fw_id);
2493c7a6970fSZerun Fu 	if (ret != 0) {
2494c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set hwinfo.");
2495c7a6970fSZerun Fu 		ret = -EIO;
2496c7a6970fSZerun Fu 		goto sym_tbl_cleanup;
2497c7a6970fSZerun Fu 	}
2498c7a6970fSZerun Fu 
24995b46a539SPeng Zhang 	ret = nfp_net_speed_cap_get(pf_dev);
25003110ab73SZerun Fu 	if (ret != 0) {
25013110ab73SZerun Fu 		PMD_INIT_LOG(ERR, "Failed to get speed capability.");
25023110ab73SZerun Fu 		ret = -EIO;
25033110ab73SZerun Fu 		goto sym_tbl_cleanup;
25043110ab73SZerun Fu 	}
25053110ab73SZerun Fu 
250620086cb8SPeng Zhang 	/* Get the VF info */
250720086cb8SPeng Zhang 	ret = nfp_net_get_vf_info(pf_dev, dev_info);
250820086cb8SPeng Zhang 	if (ret != 0) {
250920086cb8SPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to get VF info.");
251020086cb8SPeng Zhang 		ret = -EIO;
251120086cb8SPeng Zhang 		goto sym_tbl_cleanup;
251220086cb8SPeng Zhang 	}
251320086cb8SPeng Zhang 
251440688372SChaoyong He 	/* Configure access to tx/rx vNIC BARs */
25150314a8ffSChaoyong He 	addr = nfp_qcp_queue_offset(dev_info, 0);
2516925c27ecSChaoyong He 	cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0);
25170314a8ffSChaoyong He 
2518711e4559SChaoyong He 	pf_dev->qc_bar = nfp_cpp_map_area(pf_dev->cpp, cpp_id,
25190314a8ffSChaoyong He 			addr, dev_info->qc_area_sz, &pf_dev->qc_area);
2520711e4559SChaoyong He 	if (pf_dev->qc_bar == NULL) {
2521b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "The nfp_rtsym_map fails for net.qc.");
2522646ea79cSHeinrich Kuhn 		ret = -EIO;
25238ad2cc8fSPeng Zhang 		goto sym_tbl_cleanup;
2524646ea79cSHeinrich Kuhn 	}
2525646ea79cSHeinrich Kuhn 
2526b6de4353SZerun Fu 	PMD_INIT_LOG(DEBUG, "The qc_bar address: %p.", pf_dev->qc_bar);
2527646ea79cSHeinrich Kuhn 
2528e54d68a0SChaoyong He 	pf_dev->mac_stats_bar = nfp_rtsym_map(sym_tbl, "_mac_stats",
2529e54d68a0SChaoyong He 			NFP_MAC_STATS_SIZE * nfp_eth_table->max_index,
2530e54d68a0SChaoyong He 			&pf_dev->mac_stats_area);
2531e54d68a0SChaoyong He 	if (pf_dev->mac_stats_bar == NULL) {
2532b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "The nfp_rtsym_map fails for _mac_stats.");
2533e54d68a0SChaoyong He 		goto hwqueues_cleanup;
2534e54d68a0SChaoyong He 	}
2535e54d68a0SChaoyong He 
253619bd7cceSChaoyong He 	ret = nfp_enable_multi_pf(pf_dev);
253719bd7cceSChaoyong He 	if (ret != 0)
253819bd7cceSChaoyong He 		goto mac_stats_cleanup;
253919bd7cceSChaoyong He 
254019542093SPeng Zhang 	ret = nfp_net_vf_config_init(pf_dev);
254119542093SPeng Zhang 	if (ret != 0) {
254219542093SPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to init VF config.");
25431dd83476SPeng Zhang 		goto vf_cfg_tbl_cleanup;
254419bd7cceSChaoyong He 	}
25451dd83476SPeng Zhang 
2546c2b4f0d5SChaoyong He 	hw_priv->is_pf = true;
2547ff9f5a56SChaoyong He 
2548636e133eSPeng Zhang 	if (!nfp_net_recv_pkt_meta_check_register(hw_priv)) {
2549636e133eSPeng Zhang 		PMD_INIT_LOG(ERR, "PF register meta check function failed.");
2550636e133eSPeng Zhang 		ret = -EIO;
2551636e133eSPeng Zhang 		goto hw_priv_free;
2552636e133eSPeng Zhang 	}
2553636e133eSPeng Zhang 
2554a6189a67SJin Liu 	/*
2555968ec1c3SChaoyong He 	 * PF initialization has been done at this point. Call app specific
255640688372SChaoyong He 	 * init code now.
2557646ea79cSHeinrich Kuhn 	 */
2558e51160adSPeng Zhang 	ret = nfp_fw_app_primary_init(hw_priv);
2559968ec1c3SChaoyong He 	if (ret != 0) {
2560e51160adSPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to init hw app primary.");
256119542093SPeng Zhang 		goto vf_cfg_tbl_cleanup;
2562646ea79cSHeinrich Kuhn 	}
2563646ea79cSHeinrich Kuhn 
256440688372SChaoyong He 	/* Register the CPP bridge service here for primary use */
2565c50bf4f0SLong Wu 	if (pf_dev->devargs.cpp_service_enable) {
2566bab0e6f4SChaoyong He 		ret = nfp_enable_cpp_service(pf_dev);
25676d0ee64aSLong Wu 		if (ret != 0) {
25686d0ee64aSLong Wu 			PMD_INIT_LOG(ERR, "Enable CPP service failed.");
256919542093SPeng Zhang 			goto vf_cfg_tbl_cleanup;
25706d0ee64aSLong Wu 		}
2571c50bf4f0SLong Wu 	}
2572646ea79cSHeinrich Kuhn 
2573646ea79cSHeinrich Kuhn 	return 0;
2574646ea79cSHeinrich Kuhn 
257519542093SPeng Zhang vf_cfg_tbl_cleanup:
257619542093SPeng Zhang 	nfp_net_vf_config_uninit(pf_dev);
2577e54d68a0SChaoyong He mac_stats_cleanup:
2578e54d68a0SChaoyong He 	nfp_cpp_area_release_free(pf_dev->mac_stats_area);
2579646ea79cSHeinrich Kuhn hwqueues_cleanup:
2580528812a6SChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
2581646ea79cSHeinrich Kuhn sym_tbl_cleanup:
2582646ea79cSHeinrich Kuhn 	free(sym_tbl);
25833b00109dSPeng Zhang fw_cleanup:
25843b00109dSPeng Zhang 	nfp_fw_unload(cpp);
25853a64e190SChaoyong He 	if (pf_dev->multi_pf.enabled) {
25868ba461d1SPeng Zhang 		nfp_net_keepalive_stop(&pf_dev->multi_pf);
2587b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
2588528812a6SChaoyong He 		nfp_net_keepalive_uninit(&pf_dev->multi_pf);
25893a64e190SChaoyong He 	}
2590646ea79cSHeinrich Kuhn eth_table_cleanup:
2591646ea79cSHeinrich Kuhn 	free(nfp_eth_table);
2592646ea79cSHeinrich Kuhn hwinfo_cleanup:
2593646ea79cSHeinrich Kuhn 	free(hwinfo);
2594968ec1c3SChaoyong He cpp_cleanup:
2595968ec1c3SChaoyong He 	nfp_cpp_free(cpp);
25966b4273a0SLong Wu sync_free:
25976b4273a0SLong Wu 	nfp_sync_free(sync);
25988ad2cc8fSPeng Zhang pf_cleanup:
25998ad2cc8fSPeng Zhang 	rte_free(pf_dev);
2600ff9f5a56SChaoyong He hw_priv_free:
2601ff9f5a56SChaoyong He 	rte_free(hw_priv);
26027feb8909SChaoyong He 
2603646ea79cSHeinrich Kuhn 	return ret;
2604646ea79cSHeinrich Kuhn }
2605646ea79cSHeinrich Kuhn 
2606d5f39e07SChaoyong He static int
26076484c847SChaoyong He nfp_secondary_net_init(struct rte_eth_dev *eth_dev,
26086484c847SChaoyong He 		void *para)
26096484c847SChaoyong He {
2610000feb4cSChaoyong He 	struct nfp_net_hw_priv *hw_priv;
26116484c847SChaoyong He 
2612000feb4cSChaoyong He 	hw_priv = para;
2613000feb4cSChaoyong He 	nfp_net_ethdev_ops_mount(hw_priv->pf_dev, eth_dev);
26146484c847SChaoyong He 
26156484c847SChaoyong He 	eth_dev->process_private = para;
26166484c847SChaoyong He 
26176484c847SChaoyong He 	return 0;
26186484c847SChaoyong He }
26196484c847SChaoyong He 
26206484c847SChaoyong He static int
2621ff9f5a56SChaoyong He nfp_secondary_init_app_fw_nic(struct nfp_net_hw_priv *hw_priv)
2622d5f39e07SChaoyong He {
26238ceb85c3SChaoyong He 	uint32_t i;
2624d5f39e07SChaoyong He 	int ret = 0;
26258ceb85c3SChaoyong He 	uint32_t total_vnics;
2626eac7eda4SChaoyong He 	char port_name[RTE_ETH_NAME_MAX_LEN];
2627ff9f5a56SChaoyong He 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
2628d5f39e07SChaoyong He 
2629eac7eda4SChaoyong He 	total_vnics = nfp_net_get_phyports_from_fw(pf_dev);
2630d5f39e07SChaoyong He 
2631d5f39e07SChaoyong He 	for (i = 0; i < total_vnics; i++) {
2632eac7eda4SChaoyong He 		nfp_port_name_generate(port_name, sizeof(port_name), i, pf_dev);
2633d5f39e07SChaoyong He 
2634b6de4353SZerun Fu 		PMD_INIT_LOG(DEBUG, "Secondary attaching to port %s.", port_name);
26356484c847SChaoyong He 		ret = rte_eth_dev_create(&pf_dev->pci_dev->device, port_name, 0,
26366484c847SChaoyong He 				NULL, NULL, nfp_secondary_net_init, hw_priv);
26376484c847SChaoyong He 		if (ret != 0) {
2638b6de4353SZerun Fu 			PMD_INIT_LOG(ERR, "Secondary process attach to port %s failed.", port_name);
2639eac7eda4SChaoyong He 			goto port_cleanup;
2640d5f39e07SChaoyong He 		}
2641d5f39e07SChaoyong He 	}
2642d5f39e07SChaoyong He 
2643eac7eda4SChaoyong He 	return 0;
2644eac7eda4SChaoyong He 
2645eac7eda4SChaoyong He port_cleanup:
2646eac7eda4SChaoyong He 	for (uint32_t j = 0; j < i; j++) {
2647eac7eda4SChaoyong He 		struct rte_eth_dev *eth_dev;
2648eac7eda4SChaoyong He 
2649eac7eda4SChaoyong He 		nfp_port_name_generate(port_name, sizeof(port_name), j, pf_dev);
2650eac7eda4SChaoyong He 		eth_dev = rte_eth_dev_get_by_name(port_name);
2651eac7eda4SChaoyong He 		if (eth_dev != NULL)
2652eac7eda4SChaoyong He 			rte_eth_dev_destroy(eth_dev, NULL);
2653eac7eda4SChaoyong He 	}
2654eac7eda4SChaoyong He 
2655d5f39e07SChaoyong He 	return ret;
2656d5f39e07SChaoyong He }
2657d5f39e07SChaoyong He 
2658e51160adSPeng Zhang static int
2659e51160adSPeng Zhang nfp_fw_app_secondary_init(struct nfp_net_hw_priv *hw_priv)
2660e51160adSPeng Zhang {
2661e51160adSPeng Zhang 	int ret;
2662e51160adSPeng Zhang 	struct nfp_pf_dev *pf_dev = hw_priv->pf_dev;
2663e51160adSPeng Zhang 
2664e51160adSPeng Zhang 	switch (pf_dev->app_fw_id) {
2665e51160adSPeng Zhang 	case NFP_APP_FW_CORE_NIC:
2666b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Initializing coreNIC.");
2667e51160adSPeng Zhang 		ret = nfp_secondary_init_app_fw_nic(hw_priv);
2668e51160adSPeng Zhang 		if (ret != 0) {
2669e51160adSPeng Zhang 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
2670e51160adSPeng Zhang 			return ret;
2671e51160adSPeng Zhang 		}
2672e51160adSPeng Zhang 		break;
2673e51160adSPeng Zhang 	case NFP_APP_FW_FLOWER_NIC:
2674b6de4353SZerun Fu 		PMD_INIT_LOG(INFO, "Initializing Flower.");
2675e51160adSPeng Zhang 		ret = nfp_secondary_init_app_fw_flower(hw_priv);
2676e51160adSPeng Zhang 		if (ret != 0) {
2677e51160adSPeng Zhang 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
2678e51160adSPeng Zhang 			return ret;
2679e51160adSPeng Zhang 		}
2680e51160adSPeng Zhang 		break;
2681e51160adSPeng Zhang 	default:
2682b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded.");
2683e51160adSPeng Zhang 		ret = -EINVAL;
2684e51160adSPeng Zhang 		return ret;
2685e51160adSPeng Zhang 	}
2686e51160adSPeng Zhang 
2687e51160adSPeng Zhang 	return 0;
2688e51160adSPeng Zhang }
2689e51160adSPeng Zhang 
2690646ea79cSHeinrich Kuhn /*
2691646ea79cSHeinrich Kuhn  * When attaching to the NFP4000/6000 PF on a secondary process there
2692646ea79cSHeinrich Kuhn  * is no need to initialise the PF again. Only minimal work is required
269340688372SChaoyong He  * here.
2694646ea79cSHeinrich Kuhn  */
2695a6189a67SJin Liu static int
2696a6189a67SJin Liu nfp_pf_secondary_init(struct rte_pci_device *pci_dev)
2697646ea79cSHeinrich Kuhn {
26986b4273a0SLong Wu 	void *sync;
2699968ec1c3SChaoyong He 	int ret = 0;
2700a6189a67SJin Liu 	struct nfp_cpp *cpp;
27013b00109dSPeng Zhang 	uint8_t function_id;
2702016141b1SChaoyong He 	struct nfp_pf_dev *pf_dev;
2703d5f39e07SChaoyong He 	enum nfp_app_fw_id app_fw_id;
2704016141b1SChaoyong He 	char name[RTE_ETH_NAME_MAX_LEN];
2705a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
2706ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
27070314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
27083b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
2709646ea79cSHeinrich Kuhn 
2710a6189a67SJin Liu 	if (pci_dev == NULL)
2711646ea79cSHeinrich Kuhn 		return -ENODEV;
2712646ea79cSHeinrich Kuhn 
271384aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
271484aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
271584aaba5aSChaoyong He 		return -ENODEV;
271684aaba5aSChaoyong He 	}
271784aaba5aSChaoyong He 
27180314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
27190314a8ffSChaoyong He 	if (dev_info == NULL) {
2720b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Not supported device ID.");
27210314a8ffSChaoyong He 		return -ENODEV;
27220314a8ffSChaoyong He 	}
27230314a8ffSChaoyong He 
2724ff9f5a56SChaoyong He 	hw_priv = rte_zmalloc(NULL, sizeof(*hw_priv), 0);
2725ff9f5a56SChaoyong He 	if (hw_priv == NULL) {
2726b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not alloc memory for hw priv data.");
2727ff9f5a56SChaoyong He 		return -ENOMEM;
2728ff9f5a56SChaoyong He 	}
2729ff9f5a56SChaoyong He 
2730016141b1SChaoyong He 	/* Allocate memory for the PF "device" */
2731eac7eda4SChaoyong He 	function_id = pci_dev->addr.function & 0x7;
2732016141b1SChaoyong He 	snprintf(name, sizeof(name), "nfp_pf%d", 0);
2733016141b1SChaoyong He 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
2734016141b1SChaoyong He 	if (pf_dev == NULL) {
2735b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Can not allocate memory for the PF device.");
2736ff9f5a56SChaoyong He 		ret = -ENOMEM;
2737ff9f5a56SChaoyong He 		goto hw_priv_free;
2738016141b1SChaoyong He 	}
2739016141b1SChaoyong He 
27406f708e52SChaoyong He 	hw_priv->pf_dev = pf_dev;
27416f708e52SChaoyong He 	hw_priv->dev_info = dev_info;
27426f708e52SChaoyong He 
27436b4273a0SLong Wu 	sync = nfp_sync_alloc();
27446b4273a0SLong Wu 	if (sync == NULL) {
27456b4273a0SLong Wu 		PMD_INIT_LOG(ERR, "Failed to alloc sync zone.");
27466b4273a0SLong Wu 		ret = -ENOMEM;
27476b4273a0SLong Wu 		goto pf_cleanup;
27486b4273a0SLong Wu 	}
27496b4273a0SLong Wu 
27506f708e52SChaoyong He 	pf_dev->sync = sync;
27516f708e52SChaoyong He 
2752646ea79cSHeinrich Kuhn 	/*
2753646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
2754646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
2755646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
2756646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
2757646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
2758646ea79cSHeinrich Kuhn 	 */
2759646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
27601fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
2761646ea79cSHeinrich Kuhn 	else
27621fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
2763646ea79cSHeinrich Kuhn 
2764a6189a67SJin Liu 	if (cpp == NULL) {
2765b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained.");
2766016141b1SChaoyong He 		ret = -EIO;
27676b4273a0SLong Wu 		goto sync_free;
2768646ea79cSHeinrich Kuhn 	}
2769646ea79cSHeinrich Kuhn 
27706f708e52SChaoyong He 	pf_dev->cpp = cpp;
27716f708e52SChaoyong He 	pf_dev->pci_dev = pci_dev;
27726f708e52SChaoyong He 
2773646ea79cSHeinrich Kuhn 	/*
2774646ea79cSHeinrich Kuhn 	 * We don't have access to the PF created in the primary process
277540688372SChaoyong He 	 * here so we have to read the number of ports from firmware.
2776646ea79cSHeinrich Kuhn 	 */
2777646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
2778a6189a67SJin Liu 	if (sym_tbl == NULL) {
2779b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table.");
2780016141b1SChaoyong He 		ret = -EIO;
2781db8150deSChaoyong He 		goto cpp_cleanup;
2782646ea79cSHeinrich Kuhn 	}
2783646ea79cSHeinrich Kuhn 
27846f708e52SChaoyong He 	pf_dev->sym_tbl = sym_tbl;
27856f708e52SChaoyong He 
2786eac7eda4SChaoyong He 	/* Read the number of physical ports from firmware */
2787eac7eda4SChaoyong He 	pf_dev->multi_pf.function_id = function_id;
2788eac7eda4SChaoyong He 	pf_dev->total_phyports = nfp_net_get_phyports_from_fw(pf_dev);
2789eac7eda4SChaoyong He 	pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_fw(pf_dev->total_phyports);
2790eac7eda4SChaoyong He 
2791d5f39e07SChaoyong He 	/* Read the app ID of the firmware loaded */
27923b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
27933b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
2794e7978635SChaoyong He 	if (ret != 0) {
2795b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Could not read %s from fw.", app_name);
2796016141b1SChaoyong He 		ret = -EIO;
2797968ec1c3SChaoyong He 		goto sym_tbl_cleanup;
2798968ec1c3SChaoyong He 	}
2799646ea79cSHeinrich Kuhn 
2800016141b1SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
2801016141b1SChaoyong He 
2802c2b4f0d5SChaoyong He 	hw_priv->is_pf = true;
2803ff9f5a56SChaoyong He 
2804016141b1SChaoyong He 	/* Call app specific init code now */
2805e51160adSPeng Zhang 	ret = nfp_fw_app_secondary_init(hw_priv);
2806d5f39e07SChaoyong He 	if (ret != 0) {
2807e51160adSPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to init hw app primary.");
2808d5f39e07SChaoyong He 		goto sym_tbl_cleanup;
2809646ea79cSHeinrich Kuhn 	}
2810646ea79cSHeinrich Kuhn 
2811016141b1SChaoyong He 	return 0;
2812016141b1SChaoyong He 
2813968ec1c3SChaoyong He sym_tbl_cleanup:
2814968ec1c3SChaoyong He 	free(sym_tbl);
2815db8150deSChaoyong He cpp_cleanup:
2816db8150deSChaoyong He 	nfp_cpp_free(cpp);
28176b4273a0SLong Wu sync_free:
28186b4273a0SLong Wu 	nfp_sync_free(sync);
2819016141b1SChaoyong He pf_cleanup:
2820016141b1SChaoyong He 	rte_free(pf_dev);
2821ff9f5a56SChaoyong He hw_priv_free:
2822ff9f5a56SChaoyong He 	rte_free(hw_priv);
2823968ec1c3SChaoyong He 
2824968ec1c3SChaoyong He 	return ret;
2825646ea79cSHeinrich Kuhn }
2826646ea79cSHeinrich Kuhn 
2827a6189a67SJin Liu static int
2828a6189a67SJin Liu nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
2829646ea79cSHeinrich Kuhn 		struct rte_pci_device *dev)
2830646ea79cSHeinrich Kuhn {
2831646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
2832646ea79cSHeinrich Kuhn 		return nfp_pf_init(dev);
2833646ea79cSHeinrich Kuhn 	else
2834646ea79cSHeinrich Kuhn 		return nfp_pf_secondary_init(dev);
2835646ea79cSHeinrich Kuhn }
2836646ea79cSHeinrich Kuhn 
2837646ea79cSHeinrich Kuhn static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
2838646ea79cSHeinrich Kuhn 	{
2839646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
28405c464d6aSJin Liu 				PCI_DEVICE_ID_NFP3800_PF_NIC)
28415c464d6aSJin Liu 	},
28425c464d6aSJin Liu 	{
28435c464d6aSJin Liu 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2844646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP4000_PF_NIC)
2845646ea79cSHeinrich Kuhn 	},
2846646ea79cSHeinrich Kuhn 	{
2847646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2848646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP6000_PF_NIC)
2849646ea79cSHeinrich Kuhn 	},
2850646ea79cSHeinrich Kuhn 	{
28515aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
28525aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP3800_PF_NIC)
28535aedd4c3SJames Hershaw 	},
28545aedd4c3SJames Hershaw 	{
28555aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
28565aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP4000_PF_NIC)
28575aedd4c3SJames Hershaw 	},
28585aedd4c3SJames Hershaw 	{
28595aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
28605aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP6000_PF_NIC)
28615aedd4c3SJames Hershaw 	},
28625aedd4c3SJames Hershaw 	{
2863646ea79cSHeinrich Kuhn 		.vendor_id = 0,
2864646ea79cSHeinrich Kuhn 	},
2865646ea79cSHeinrich Kuhn };
2866646ea79cSHeinrich Kuhn 
2867a6189a67SJin Liu static int
2868a6189a67SJin Liu nfp_pci_uninit(struct rte_eth_dev *eth_dev)
2869646ea79cSHeinrich Kuhn {
2870646ea79cSHeinrich Kuhn 	uint16_t port_id;
287149952141SChaoyong He 	struct rte_pci_device *pci_dev;
2872646ea79cSHeinrich Kuhn 
2873646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
2874646ea79cSHeinrich Kuhn 
2875646ea79cSHeinrich Kuhn 	/* Free up all physical ports under PF */
2876646ea79cSHeinrich Kuhn 	RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device)
2877646ea79cSHeinrich Kuhn 		rte_eth_dev_close(port_id);
2878646ea79cSHeinrich Kuhn 	/*
2879646ea79cSHeinrich Kuhn 	 * Ports can be closed and freed but hotplugging is not
288040688372SChaoyong He 	 * currently supported.
2881646ea79cSHeinrich Kuhn 	 */
2882646ea79cSHeinrich Kuhn 	return -ENOTSUP;
2883646ea79cSHeinrich Kuhn }
2884646ea79cSHeinrich Kuhn 
2885a6189a67SJin Liu static int
2886a6189a67SJin Liu eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
2887646ea79cSHeinrich Kuhn {
2888646ea79cSHeinrich Kuhn 	return rte_eth_dev_pci_generic_remove(pci_dev, nfp_pci_uninit);
2889646ea79cSHeinrich Kuhn }
2890646ea79cSHeinrich Kuhn 
2891646ea79cSHeinrich Kuhn static struct rte_pci_driver rte_nfp_net_pf_pmd = {
2892646ea79cSHeinrich Kuhn 	.id_table = pci_id_nfp_pf_net_map,
2893646ea79cSHeinrich Kuhn 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
2894646ea79cSHeinrich Kuhn 	.probe = nfp_pf_pci_probe,
2895646ea79cSHeinrich Kuhn 	.remove = eth_nfp_pci_remove,
2896646ea79cSHeinrich Kuhn };
2897646ea79cSHeinrich Kuhn 
2898d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI(NFP_PF_DRIVER_NAME, rte_nfp_net_pf_pmd);
2899d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI_TABLE(NFP_PF_DRIVER_NAME, pci_id_nfp_pf_net_map);
2900d505ee1dSChaoyong He RTE_PMD_REGISTER_KMOD_DEP(NFP_PF_DRIVER_NAME, "* igb_uio | uio_pci_generic | vfio");
2901c50bf4f0SLong Wu RTE_PMD_REGISTER_PARAM_STRING(NFP_PF_DRIVER_NAME,
2902c50bf4f0SLong Wu 		NFP_PF_FORCE_RELOAD_FW "=<0|1>"
2903c50bf4f0SLong Wu 		NFP_CPP_SERVICE_ENABLE "=<0|1>");
2904