xref: /dpdk/drivers/net/nfp/nfp_ethdev.c (revision a2bc299d46e0da1facc4be179ff7d961bfe708cc)
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>
12646ea79cSHeinrich Kuhn 
135a95b024SChaoyong He #include "flower/nfp_flower.h"
145a95b024SChaoyong He #include "nfd3/nfp_nfd3.h"
155a95b024SChaoyong He #include "nfdk/nfp_nfdk.h"
16646ea79cSHeinrich Kuhn #include "nfpcore/nfp_cpp.h"
17*a2bc299dSPeng Zhang #include "nfpcore/nfp_elf.h"
18646ea79cSHeinrich Kuhn #include "nfpcore/nfp_hwinfo.h"
19646ea79cSHeinrich Kuhn #include "nfpcore/nfp_rtsym.h"
20646ea79cSHeinrich Kuhn #include "nfpcore/nfp_nsp.h"
21796f1aecSChaoyong He #include "nfpcore/nfp6000_pcie.h"
228ba461d1SPeng Zhang #include "nfpcore/nfp_resource.h"
236b4273a0SLong Wu #include "nfpcore/nfp_sync.h"
24646ea79cSHeinrich Kuhn 
25646ea79cSHeinrich Kuhn #include "nfp_cpp_bridge.h"
2654713740SChang Miao #include "nfp_ipsec.h"
275a95b024SChaoyong He #include "nfp_logs.h"
288153bc6fSChaoyong He #include "nfp_net_flow.h"
29b1880421SChaoyong He 
30c7a6970fSZerun Fu /* 64-bit per app capabilities */
31c7a6970fSZerun Fu #define NFP_NET_APP_CAP_SP_INDIFF       RTE_BIT64(0) /* Indifferent to port speed */
32c7a6970fSZerun Fu 
33d505ee1dSChaoyong He #define NFP_PF_DRIVER_NAME net_nfp_pf
34d505ee1dSChaoyong He 
35a243128bSChaoyong He static void
36f4d24fe9SChaoyong He nfp_net_pf_read_mac(struct nfp_app_fw_nic *app_fw_nic,
378ceb85c3SChaoyong He 		uint16_t port)
38646ea79cSHeinrich Kuhn {
3949952141SChaoyong He 	struct nfp_net_hw *hw;
40646ea79cSHeinrich Kuhn 	struct nfp_eth_table *nfp_eth_table;
41646ea79cSHeinrich Kuhn 
42646ea79cSHeinrich Kuhn 	/* Grab a pointer to the correct physical port */
43968ec1c3SChaoyong He 	hw = app_fw_nic->ports[port];
44646ea79cSHeinrich Kuhn 
45a243128bSChaoyong He 	nfp_eth_table = app_fw_nic->pf_dev->nfp_eth_table;
46646ea79cSHeinrich Kuhn 
47ef759759SChaoyong He 	rte_ether_addr_copy(&nfp_eth_table->ports[port].mac_addr, &hw->super.mac_addr);
48646ea79cSHeinrich Kuhn }
49646ea79cSHeinrich Kuhn 
50009f43d5SZerun Fu static uint32_t
51009f43d5SZerun Fu nfp_net_speed_bitmap2speed(uint32_t speeds_bitmap)
52009f43d5SZerun Fu {
53009f43d5SZerun Fu 	switch (speeds_bitmap) {
54009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M_HD:
55009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
56009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M:
57009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
58009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M_HD:
59009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
60009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M:
61009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
62009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_1G:
63009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_1G;
64009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_2_5G:
65009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_2_5G;
66009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_5G:
67009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_5G;
68009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10G:
69009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10G;
70009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_20G:
71009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_20G;
72009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_25G:
73009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_25G;
74009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_40G:
75009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_40G;
76009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_50G:
77009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_50G;
78009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_56G:
79009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_56G;
80009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100G:
81009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100G;
82009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_200G:
83009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_200G;
84009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_400G:
85009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_400G;
86009f43d5SZerun Fu 	default:
87009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_NONE;
88009f43d5SZerun Fu 	}
89009f43d5SZerun Fu }
90009f43d5SZerun Fu 
91009f43d5SZerun Fu static int
92009f43d5SZerun Fu nfp_net_nfp4000_speed_configure_check(uint16_t port_id,
93009f43d5SZerun Fu 		uint32_t configure_speed,
94009f43d5SZerun Fu 		struct nfp_eth_table *nfp_eth_table)
95009f43d5SZerun Fu {
96009f43d5SZerun Fu 	switch (port_id) {
97009f43d5SZerun Fu 	case 0:
98009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_25G &&
99009f43d5SZerun Fu 				nfp_eth_table->ports[1].speed == RTE_ETH_SPEED_NUM_10G) {
100009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
101009f43d5SZerun Fu 			return -ENOTSUP;
102009f43d5SZerun Fu 		}
103009f43d5SZerun Fu 		break;
104009f43d5SZerun Fu 	case 1:
105009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_10G &&
106009f43d5SZerun Fu 				nfp_eth_table->ports[0].speed == RTE_ETH_SPEED_NUM_25G) {
107009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
108009f43d5SZerun Fu 			return -ENOTSUP;
109009f43d5SZerun Fu 		}
110009f43d5SZerun Fu 		break;
111009f43d5SZerun Fu 	default:
112009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "The port id is invalid.");
113009f43d5SZerun Fu 		return -EINVAL;
114009f43d5SZerun Fu 	}
115009f43d5SZerun Fu 
116009f43d5SZerun Fu 	return 0;
117009f43d5SZerun Fu }
118009f43d5SZerun Fu 
119009f43d5SZerun Fu static int
120009f43d5SZerun Fu nfp_net_speed_configure(struct rte_eth_dev *dev,
121009f43d5SZerun Fu 		struct nfp_net_hw *net_hw)
122009f43d5SZerun Fu {
123009f43d5SZerun Fu 	int ret;
124009f43d5SZerun Fu 	uint32_t speed_capa;
125009f43d5SZerun Fu 	struct nfp_nsp *nsp;
126009f43d5SZerun Fu 	uint32_t link_speeds;
127009f43d5SZerun Fu 	uint32_t configure_speed;
128009f43d5SZerun Fu 	struct nfp_eth_table_port *eth_port;
129009f43d5SZerun Fu 	struct nfp_eth_table *nfp_eth_table;
130009f43d5SZerun Fu 
131009f43d5SZerun Fu 	nfp_eth_table = net_hw->pf_dev->nfp_eth_table;
132009f43d5SZerun Fu 	eth_port = &nfp_eth_table->ports[net_hw->idx];
133009f43d5SZerun Fu 
134009f43d5SZerun Fu 	speed_capa = net_hw->pf_dev->speed_capa;
135009f43d5SZerun Fu 	if (speed_capa == 0) {
136009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Speed_capa is invalid.");
137009f43d5SZerun Fu 		return -EINVAL;
138009f43d5SZerun Fu 	}
139009f43d5SZerun Fu 
140009f43d5SZerun Fu 	link_speeds = dev->data->dev_conf.link_speeds;
141009f43d5SZerun Fu 	configure_speed = nfp_net_speed_bitmap2speed(speed_capa & link_speeds);
142009f43d5SZerun Fu 	if (configure_speed == RTE_ETH_SPEED_NUM_NONE &&
143009f43d5SZerun Fu 			link_speeds != RTE_ETH_LINK_SPEED_AUTONEG) {
144009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Configured speed is invalid.");
145009f43d5SZerun Fu 		return -EINVAL;
146009f43d5SZerun Fu 	}
147009f43d5SZerun Fu 
148009f43d5SZerun Fu 	/* NFP4000 does not allow the port 0 25Gbps and port 1 10Gbps at the same time. */
149009f43d5SZerun Fu 	if (net_hw->device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) {
150009f43d5SZerun Fu 		ret = nfp_net_nfp4000_speed_configure_check(net_hw->idx,
151009f43d5SZerun Fu 				configure_speed, nfp_eth_table);
152009f43d5SZerun Fu 		if (ret != 0) {
153009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to configure speed for NFP4000.");
154009f43d5SZerun Fu 			return ret;
155009f43d5SZerun Fu 		}
156009f43d5SZerun Fu 	}
157009f43d5SZerun Fu 
158009f43d5SZerun Fu 	nsp = nfp_eth_config_start(net_hw->cpp, eth_port->index);
159009f43d5SZerun Fu 	if (nsp == NULL) {
160009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Couldn't get NSP.");
161009f43d5SZerun Fu 		return -EIO;
162009f43d5SZerun Fu 	}
163009f43d5SZerun Fu 
164009f43d5SZerun Fu 	if (link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
165009f43d5SZerun Fu 		if (eth_port->supp_aneg) {
166009f43d5SZerun Fu 			ret = nfp_eth_set_aneg(nsp, NFP_ANEG_AUTO);
167009f43d5SZerun Fu 			if (ret != 0) {
168009f43d5SZerun Fu 				PMD_DRV_LOG(ERR, "Failed to set ANEG enable.");
169009f43d5SZerun Fu 				goto config_cleanup;
170009f43d5SZerun Fu 			}
171009f43d5SZerun Fu 		}
172009f43d5SZerun Fu 	} else {
173009f43d5SZerun Fu 		ret = nfp_eth_set_aneg(nsp, NFP_ANEG_DISABLED);
174009f43d5SZerun Fu 		if (ret != 0) {
175009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set ANEG disable.");
176009f43d5SZerun Fu 			goto config_cleanup;
177009f43d5SZerun Fu 		}
178009f43d5SZerun Fu 
179009f43d5SZerun Fu 		ret = nfp_eth_set_speed(nsp, configure_speed);
180009f43d5SZerun Fu 		if (ret != 0) {
181009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set speed.");
182009f43d5SZerun Fu 			goto config_cleanup;
183009f43d5SZerun Fu 		}
184009f43d5SZerun Fu 	}
185009f43d5SZerun Fu 
186009f43d5SZerun Fu 	return nfp_eth_config_commit_end(nsp);
187009f43d5SZerun Fu 
188009f43d5SZerun Fu config_cleanup:
189009f43d5SZerun Fu 	nfp_eth_config_cleanup_end(nsp);
190009f43d5SZerun Fu 
191009f43d5SZerun Fu 	return ret;
192009f43d5SZerun Fu }
193009f43d5SZerun Fu 
194646ea79cSHeinrich Kuhn static int
195646ea79cSHeinrich Kuhn nfp_net_start(struct rte_eth_dev *dev)
196646ea79cSHeinrich Kuhn {
19749952141SChaoyong He 	int ret;
19849952141SChaoyong He 	uint16_t i;
19972d1dea6SChaoyong He 	struct nfp_hw *hw;
20049952141SChaoyong He 	uint32_t new_ctrl;
201acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
20249952141SChaoyong He 	uint32_t update = 0;
2032e7c3612SQin Ke 	uint32_t cap_extend;
20449952141SChaoyong He 	uint32_t intr_vector;
20549952141SChaoyong He 	uint32_t ctrl_extend = 0;
20672d1dea6SChaoyong He 	struct nfp_net_hw *net_hw;
207646ea79cSHeinrich Kuhn 	struct nfp_pf_dev *pf_dev;
208646ea79cSHeinrich Kuhn 	struct rte_eth_rxmode *rxmode;
20949952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
21049952141SChaoyong He 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
21149952141SChaoyong He 	struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
212646ea79cSHeinrich Kuhn 
2139d723baaSChaoyong He 	net_hw = dev->data->dev_private;
21465f6915dSChaoyong He 	pf_dev = net_hw->pf_dev;
215968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
21672d1dea6SChaoyong He 	hw = &net_hw->super;
217646ea79cSHeinrich Kuhn 
218646ea79cSHeinrich Kuhn 	/* Disabling queues just in case... */
219646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
220646ea79cSHeinrich Kuhn 
221646ea79cSHeinrich Kuhn 	/* Enabling the required queues in the device */
222646ea79cSHeinrich Kuhn 	nfp_net_enable_queues(dev);
223646ea79cSHeinrich Kuhn 
224009f43d5SZerun Fu 	/* Configure the port speed and the auto-negotiation mode. */
225009f43d5SZerun Fu 	ret = nfp_net_speed_configure(dev, net_hw);
226009f43d5SZerun Fu 	if (ret < 0) {
227009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set the speed and auto-negotiation mode.");
228009f43d5SZerun Fu 		return ret;
229009f43d5SZerun Fu 	}
230009f43d5SZerun Fu 
23140688372SChaoyong He 	/* Check and configure queue intr-vector mapping */
232646ea79cSHeinrich Kuhn 	if (dev->data->dev_conf.intr_conf.rxq != 0) {
233968ec1c3SChaoyong He 		if (app_fw_nic->multiport) {
234646ea79cSHeinrich Kuhn 			PMD_INIT_LOG(ERR, "PMD rx interrupt is not supported "
235646ea79cSHeinrich Kuhn 					"with NFP multiport PF");
236646ea79cSHeinrich Kuhn 				return -EINVAL;
237646ea79cSHeinrich Kuhn 		}
238b0c496abSChaoyong He 
239f4d24fe9SChaoyong He 		if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_UIO) {
240646ea79cSHeinrich Kuhn 			/*
241646ea79cSHeinrich Kuhn 			 * Better not to share LSC with RX interrupts.
24240688372SChaoyong He 			 * Unregistering LSC interrupt handler.
243646ea79cSHeinrich Kuhn 			 */
244e7978635SChaoyong He 			rte_intr_callback_unregister(intr_handle,
245646ea79cSHeinrich Kuhn 					nfp_net_dev_interrupt_handler, (void *)dev);
246646ea79cSHeinrich Kuhn 
247646ea79cSHeinrich Kuhn 			if (dev->data->nb_rx_queues > 1) {
248646ea79cSHeinrich Kuhn 				PMD_INIT_LOG(ERR, "PMD rx interrupt only "
249646ea79cSHeinrich Kuhn 						"supports 1 queue with UIO");
250646ea79cSHeinrich Kuhn 				return -EIO;
251646ea79cSHeinrich Kuhn 			}
252646ea79cSHeinrich Kuhn 		}
253b0c496abSChaoyong He 
254646ea79cSHeinrich Kuhn 		intr_vector = dev->data->nb_rx_queues;
255c01e5c0cSChaoyong He 		if (rte_intr_efd_enable(intr_handle, intr_vector) != 0)
256646ea79cSHeinrich Kuhn 			return -1;
257646ea79cSHeinrich Kuhn 
258646ea79cSHeinrich Kuhn 		nfp_configure_rx_interrupt(dev, intr_handle);
259646ea79cSHeinrich Kuhn 		update = NFP_NET_CFG_UPDATE_MSIX;
260646ea79cSHeinrich Kuhn 	}
261646ea79cSHeinrich Kuhn 
262dbad6f64SPeng Zhang 	/* Checking MTU set */
26372d1dea6SChaoyong He 	if (dev->data->mtu > net_hw->flbufsz) {
264dbad6f64SPeng Zhang 		PMD_INIT_LOG(ERR, "MTU (%u) can't be larger than the current NFP_FRAME_SIZE (%u)",
26572d1dea6SChaoyong He 				dev->data->mtu, net_hw->flbufsz);
266dbad6f64SPeng Zhang 		return -ERANGE;
267dbad6f64SPeng Zhang 	}
268dbad6f64SPeng Zhang 
269646ea79cSHeinrich Kuhn 	rte_intr_enable(intr_handle);
270646ea79cSHeinrich Kuhn 
271646ea79cSHeinrich Kuhn 	new_ctrl = nfp_check_offloads(dev);
272646ea79cSHeinrich Kuhn 
273646ea79cSHeinrich Kuhn 	/* Writing configuration parameters in the device */
27472d1dea6SChaoyong He 	nfp_net_params_setup(net_hw);
275646ea79cSHeinrich Kuhn 
276c4de52ecSChaoyong He 	rxmode = &dev->data->dev_conf.rxmode;
277c01e5c0cSChaoyong He 	if ((rxmode->mq_mode & RTE_ETH_MQ_RX_RSS) != 0) {
278646ea79cSHeinrich Kuhn 		nfp_net_rss_config_default(dev);
279646ea79cSHeinrich Kuhn 		update |= NFP_NET_CFG_UPDATE_RSS;
28072d1dea6SChaoyong He 		new_ctrl |= nfp_net_cfg_ctrl_rss(hw->cap);
281646ea79cSHeinrich Kuhn 	}
282646ea79cSHeinrich Kuhn 
283646ea79cSHeinrich Kuhn 	/* Enable device */
284646ea79cSHeinrich Kuhn 	new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
285646ea79cSHeinrich Kuhn 
286646ea79cSHeinrich Kuhn 	update |= NFP_NET_CFG_UPDATE_GEN | NFP_NET_CFG_UPDATE_RING;
287646ea79cSHeinrich Kuhn 
288c55abf61SChaoyong He 	/* Enable vxlan */
28972d1dea6SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_VXLAN) != 0) {
290c55abf61SChaoyong He 		new_ctrl |= NFP_NET_CFG_CTRL_VXLAN;
291c55abf61SChaoyong He 		update |= NFP_NET_CFG_UPDATE_VXLAN;
292c925a157SFei Qin 	}
293c55abf61SChaoyong He 
29472d1dea6SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_RINGCFG) != 0)
295646ea79cSHeinrich Kuhn 		new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG;
296646ea79cSHeinrich Kuhn 
29772d1dea6SChaoyong He 	if (nfp_reconfig(hw, new_ctrl, update) != 0)
298646ea79cSHeinrich Kuhn 		return -EIO;
299646ea79cSHeinrich Kuhn 
3001e80c074SChaoyong He 	hw->ctrl = new_ctrl;
3011e80c074SChaoyong He 
3022e7c3612SQin Ke 	/* Enable packet type offload by extend ctrl word1. */
30372d1dea6SChaoyong He 	cap_extend = hw->cap_ext;
3042e7c3612SQin Ke 	if ((cap_extend & NFP_NET_CFG_CTRL_PKT_TYPE) != 0)
3052e7c3612SQin Ke 		ctrl_extend = NFP_NET_CFG_CTRL_PKT_TYPE;
3062e7c3612SQin Ke 
30754713740SChang Miao 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0)
3089177c800SChaoyong He 		ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC |
3099177c800SChaoyong He 				NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP |
3109177c800SChaoyong He 				NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP;
31154713740SChang Miao 
3128153bc6fSChaoyong He 	/* Enable flow steer by extend ctrl word1. */
3138153bc6fSChaoyong He 	if ((cap_extend & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
3148153bc6fSChaoyong He 		ctrl_extend |= NFP_NET_CFG_CTRL_FLOW_STEER;
3158153bc6fSChaoyong He 
3162e7c3612SQin Ke 	update = NFP_NET_CFG_UPDATE_GEN;
31772d1dea6SChaoyong He 	if (nfp_ext_reconfig(hw, ctrl_extend, update) != 0)
3182e7c3612SQin Ke 		return -EIO;
3192e7c3612SQin Ke 
32072d1dea6SChaoyong He 	hw->ctrl_ext = ctrl_extend;
321b4b6988aSChaoyong He 
322646ea79cSHeinrich Kuhn 	/*
323646ea79cSHeinrich Kuhn 	 * Allocating rte mbufs for configured rx queues.
32440688372SChaoyong He 	 * This requires queues being enabled before.
325646ea79cSHeinrich Kuhn 	 */
326c01e5c0cSChaoyong He 	if (nfp_net_rx_freelist_setup(dev) != 0) {
327646ea79cSHeinrich Kuhn 		ret = -ENOMEM;
328646ea79cSHeinrich Kuhn 		goto error;
329646ea79cSHeinrich Kuhn 	}
330646ea79cSHeinrich Kuhn 
331646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
332acb6bebfSChaoyong He 		cpp = net_hw->cpp;
333646ea79cSHeinrich Kuhn 	else
334acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
335acb6bebfSChaoyong He 
336acb6bebfSChaoyong He 	/* Configure the physical port up */
337acb6bebfSChaoyong He 	nfp_eth_set_configured(cpp, net_hw->nfp_idx, 1);
338646ea79cSHeinrich Kuhn 
339c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_rx_queues; i++)
340c46216e7SJie Hai 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
341c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_tx_queues; i++)
342c46216e7SJie Hai 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
343c46216e7SJie Hai 
344646ea79cSHeinrich Kuhn 	return 0;
345646ea79cSHeinrich Kuhn 
346646ea79cSHeinrich Kuhn error:
347646ea79cSHeinrich Kuhn 	/*
348646ea79cSHeinrich Kuhn 	 * An error returned by this function should mean the app
349646ea79cSHeinrich Kuhn 	 * exiting and then the system releasing all the memory
350646ea79cSHeinrich Kuhn 	 * allocated even memory coming from hugepages.
351646ea79cSHeinrich Kuhn 	 *
352646ea79cSHeinrich Kuhn 	 * The device could be enabled at this point with some queues
353646ea79cSHeinrich Kuhn 	 * ready for getting packets. This is true if the call to
354646ea79cSHeinrich Kuhn 	 * nfp_net_rx_freelist_setup() succeeds for some queues but
355646ea79cSHeinrich Kuhn 	 * fails for subsequent queues.
356646ea79cSHeinrich Kuhn 	 *
357646ea79cSHeinrich Kuhn 	 * This should make the app exiting but better if we tell the
358646ea79cSHeinrich Kuhn 	 * device first.
359646ea79cSHeinrich Kuhn 	 */
360646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
361646ea79cSHeinrich Kuhn 
362646ea79cSHeinrich Kuhn 	return ret;
363646ea79cSHeinrich Kuhn }
364646ea79cSHeinrich Kuhn 
365646ea79cSHeinrich Kuhn /* Set the link up. */
366646ea79cSHeinrich Kuhn static int
367646ea79cSHeinrich Kuhn nfp_net_set_link_up(struct rte_eth_dev *dev)
368646ea79cSHeinrich Kuhn {
369acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
370646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
371646ea79cSHeinrich Kuhn 
3729d723baaSChaoyong He 	hw = dev->data->dev_private;
373646ea79cSHeinrich Kuhn 
374646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
375acb6bebfSChaoyong He 		cpp = hw->cpp;
376646ea79cSHeinrich Kuhn 	else
377acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
378acb6bebfSChaoyong He 
379acb6bebfSChaoyong He 	return nfp_eth_set_configured(cpp, hw->nfp_idx, 1);
380646ea79cSHeinrich Kuhn }
381646ea79cSHeinrich Kuhn 
382646ea79cSHeinrich Kuhn /* Set the link down. */
383646ea79cSHeinrich Kuhn static int
384646ea79cSHeinrich Kuhn nfp_net_set_link_down(struct rte_eth_dev *dev)
385646ea79cSHeinrich Kuhn {
386acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
387646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
388646ea79cSHeinrich Kuhn 
3899d723baaSChaoyong He 	hw = dev->data->dev_private;
390646ea79cSHeinrich Kuhn 
391646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
392acb6bebfSChaoyong He 		cpp = hw->cpp;
393646ea79cSHeinrich Kuhn 	else
394acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
395acb6bebfSChaoyong He 
396acb6bebfSChaoyong He 	return nfp_eth_set_configured(cpp, hw->nfp_idx, 0);
397646ea79cSHeinrich Kuhn }
398646ea79cSHeinrich Kuhn 
3993b00109dSPeng Zhang static uint8_t
4003b00109dSPeng Zhang nfp_function_id_get(const struct nfp_pf_dev *pf_dev,
4013b00109dSPeng Zhang 		uint8_t phy_port)
4023b00109dSPeng Zhang {
4033b00109dSPeng Zhang 	if (pf_dev->multi_pf.enabled)
4043b00109dSPeng Zhang 		return pf_dev->multi_pf.function_id;
4053b00109dSPeng Zhang 
4063b00109dSPeng Zhang 	return phy_port;
4073b00109dSPeng Zhang }
4083b00109dSPeng Zhang 
4098ba461d1SPeng Zhang static void
4108ba461d1SPeng Zhang nfp_net_beat_timer(void *arg)
4118ba461d1SPeng Zhang {
4128ba461d1SPeng Zhang 	uint64_t cur_sec;
4138ba461d1SPeng Zhang 	struct nfp_multi_pf *multi_pf = arg;
4148ba461d1SPeng Zhang 
4158ba461d1SPeng Zhang 	cur_sec = rte_rdtsc();
4168ba461d1SPeng Zhang 	nn_writeq(cur_sec, multi_pf->beat_addr + NFP_BEAT_OFFSET(multi_pf->function_id));
4178ba461d1SPeng Zhang 
4188ba461d1SPeng Zhang 	/* Beat once per second. */
4198ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
4208ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
4218ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Error setting alarm");
4228ba461d1SPeng Zhang 	}
4238ba461d1SPeng Zhang }
4248ba461d1SPeng Zhang 
4258ba461d1SPeng Zhang static int
4268ba461d1SPeng Zhang nfp_net_keepalive_init(struct nfp_cpp *cpp,
4278ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
4288ba461d1SPeng Zhang {
4298ba461d1SPeng Zhang 	uint8_t *base;
4308ba461d1SPeng Zhang 	uint64_t addr;
4318ba461d1SPeng Zhang 	uint32_t size;
4328ba461d1SPeng Zhang 	uint32_t cpp_id;
4338ba461d1SPeng Zhang 	struct nfp_resource *res;
4348ba461d1SPeng Zhang 
4358ba461d1SPeng Zhang 	res = nfp_resource_acquire(cpp, NFP_RESOURCE_KEEPALIVE);
4368ba461d1SPeng Zhang 	if (res == NULL)
4378ba461d1SPeng Zhang 		return -EIO;
4388ba461d1SPeng Zhang 
4398ba461d1SPeng Zhang 	cpp_id = nfp_resource_cpp_id(res);
4408ba461d1SPeng Zhang 	addr = nfp_resource_address(res);
4418ba461d1SPeng Zhang 	size = nfp_resource_size(res);
4428ba461d1SPeng Zhang 
4438ba461d1SPeng Zhang 	nfp_resource_release(res);
4448ba461d1SPeng Zhang 
4458ba461d1SPeng Zhang 	/* Allocate a fixed area for keepalive. */
4468ba461d1SPeng Zhang 	base = nfp_cpp_map_area(cpp, cpp_id, addr, size, &multi_pf->beat_area);
4478ba461d1SPeng Zhang 	if (base == NULL) {
4488ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Failed to map area for keepalive.");
4498ba461d1SPeng Zhang 		return -EIO;
4508ba461d1SPeng Zhang 	}
4518ba461d1SPeng Zhang 
4528ba461d1SPeng Zhang 	multi_pf->beat_addr = base;
4538ba461d1SPeng Zhang 
4548ba461d1SPeng Zhang 	return 0;
4558ba461d1SPeng Zhang }
4568ba461d1SPeng Zhang 
4578ba461d1SPeng Zhang static void
4588ba461d1SPeng Zhang nfp_net_keepalive_uninit(struct nfp_multi_pf *multi_pf)
4598ba461d1SPeng Zhang {
4608ba461d1SPeng Zhang 	nfp_cpp_area_release_free(multi_pf->beat_area);
4618ba461d1SPeng Zhang }
4628ba461d1SPeng Zhang 
4638ba461d1SPeng Zhang static int
4648ba461d1SPeng Zhang nfp_net_keepalive_start(struct nfp_multi_pf *multi_pf)
4658ba461d1SPeng Zhang {
4668ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
4678ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
4688ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Error setting alarm");
4698ba461d1SPeng Zhang 		return -EIO;
4708ba461d1SPeng Zhang 	}
4718ba461d1SPeng Zhang 
4728ba461d1SPeng Zhang 	return 0;
4738ba461d1SPeng Zhang }
4748ba461d1SPeng Zhang 
4758ba461d1SPeng Zhang static void
476b67a7b40SPeng Zhang nfp_net_keepalive_clear(uint8_t *beat_addr,
477b67a7b40SPeng Zhang 		uint8_t function_id)
478b67a7b40SPeng Zhang {
479b67a7b40SPeng Zhang 	nn_writeq(0, beat_addr + NFP_BEAT_OFFSET(function_id));
480b67a7b40SPeng Zhang }
481b67a7b40SPeng Zhang 
482b67a7b40SPeng Zhang static void
483b67a7b40SPeng Zhang nfp_net_keepalive_clear_others(const struct nfp_dev_info *dev_info,
484b67a7b40SPeng Zhang 		struct nfp_multi_pf *multi_pf)
485b67a7b40SPeng Zhang {
486b67a7b40SPeng Zhang 	uint8_t port_num;
487b67a7b40SPeng Zhang 
488b67a7b40SPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
489b67a7b40SPeng Zhang 		if (port_num == multi_pf->function_id)
490b67a7b40SPeng Zhang 			continue;
491b67a7b40SPeng Zhang 
492b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(multi_pf->beat_addr, port_num);
493b67a7b40SPeng Zhang 	}
494b67a7b40SPeng Zhang }
495b67a7b40SPeng Zhang 
496b67a7b40SPeng Zhang static void
4978ba461d1SPeng Zhang nfp_net_keepalive_stop(struct nfp_multi_pf *multi_pf)
4988ba461d1SPeng Zhang {
4998ba461d1SPeng Zhang 	/* Cancel keepalive for multiple PF setup */
5008ba461d1SPeng Zhang 	rte_eal_alarm_cancel(nfp_net_beat_timer, (void *)multi_pf);
5018ba461d1SPeng Zhang }
5028ba461d1SPeng Zhang 
5038b8f116bSChaoyong He static void
5048b8f116bSChaoyong He nfp_net_uninit(struct rte_eth_dev *eth_dev)
5058b8f116bSChaoyong He {
5068b8f116bSChaoyong He 	struct nfp_net_hw *net_hw;
5078b8f116bSChaoyong He 
5088b8f116bSChaoyong He 	net_hw = eth_dev->data->dev_private;
5098153bc6fSChaoyong He 
5108153bc6fSChaoyong He 	if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
5118153bc6fSChaoyong He 		nfp_net_flow_priv_uninit(net_hw->pf_dev, net_hw->idx);
5128153bc6fSChaoyong He 
5138b8f116bSChaoyong He 	rte_free(net_hw->eth_xstats_base);
5148b8f116bSChaoyong He 	nfp_ipsec_uninit(eth_dev);
5158b8f116bSChaoyong He 	if (net_hw->mac_stats_area != NULL)
5168b8f116bSChaoyong He 		nfp_cpp_area_release_free(net_hw->mac_stats_area);
5178b8f116bSChaoyong He }
5188b8f116bSChaoyong He 
51966d5f53dSChaoyong He static void
52066d5f53dSChaoyong He nfp_cleanup_port_app_fw_nic(struct nfp_pf_dev *pf_dev,
52166d5f53dSChaoyong He 		uint8_t id)
52266d5f53dSChaoyong He {
52366d5f53dSChaoyong He 	struct rte_eth_dev *eth_dev;
52466d5f53dSChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
52566d5f53dSChaoyong He 
52666d5f53dSChaoyong He 	app_fw_nic = pf_dev->app_fw_priv;
52766d5f53dSChaoyong He 	if (app_fw_nic->ports[id] != NULL) {
52866d5f53dSChaoyong He 		eth_dev = app_fw_nic->ports[id]->eth_dev;
52966d5f53dSChaoyong He 		if (eth_dev != NULL)
53066d5f53dSChaoyong He 			nfp_net_uninit(eth_dev);
53166d5f53dSChaoyong He 
53266d5f53dSChaoyong He 		app_fw_nic->ports[id] = NULL;
53366d5f53dSChaoyong He 	}
53466d5f53dSChaoyong He }
53566d5f53dSChaoyong He 
53666d5f53dSChaoyong He static void
53766d5f53dSChaoyong He nfp_uninit_app_fw_nic(struct nfp_pf_dev *pf_dev)
53866d5f53dSChaoyong He {
53966d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
54066d5f53dSChaoyong He 	rte_free(pf_dev->app_fw_priv);
54166d5f53dSChaoyong He }
54266d5f53dSChaoyong He 
54366d5f53dSChaoyong He void
54466d5f53dSChaoyong He nfp_pf_uninit(struct nfp_pf_dev *pf_dev)
54566d5f53dSChaoyong He {
54666d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
54766d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
54866d5f53dSChaoyong He 	if (pf_dev->multi_pf.enabled) {
54966d5f53dSChaoyong He 		nfp_net_keepalive_stop(&pf_dev->multi_pf);
550b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
55166d5f53dSChaoyong He 		nfp_net_keepalive_uninit(&pf_dev->multi_pf);
55266d5f53dSChaoyong He 	}
55366d5f53dSChaoyong He 	free(pf_dev->nfp_eth_table);
55466d5f53dSChaoyong He 	free(pf_dev->hwinfo);
55566d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
5566b4273a0SLong Wu 	nfp_sync_free(pf_dev->sync);
55766d5f53dSChaoyong He 	rte_free(pf_dev);
55866d5f53dSChaoyong He }
55966d5f53dSChaoyong He 
56066d5f53dSChaoyong He static int
56166d5f53dSChaoyong He nfp_pf_secondary_uninit(struct nfp_pf_dev *pf_dev)
56266d5f53dSChaoyong He {
56366d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
56466d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
5656b4273a0SLong Wu 	nfp_sync_free(pf_dev->sync);
56666d5f53dSChaoyong He 	rte_free(pf_dev);
56766d5f53dSChaoyong He 
56866d5f53dSChaoyong He 	return 0;
56966d5f53dSChaoyong He }
57066d5f53dSChaoyong He 
571646ea79cSHeinrich Kuhn /* Reset and stop device. The device can not be restarted. */
572646ea79cSHeinrich Kuhn static int
573646ea79cSHeinrich Kuhn nfp_net_close(struct rte_eth_dev *dev)
574646ea79cSHeinrich Kuhn {
5758ceb85c3SChaoyong He 	uint8_t i;
5763b00109dSPeng Zhang 	uint8_t id;
57749952141SChaoyong He 	struct nfp_net_hw *hw;
57849952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
57949952141SChaoyong He 	struct rte_pci_device *pci_dev;
58049952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
581646ea79cSHeinrich Kuhn 
58266d5f53dSChaoyong He 	/*
58366d5f53dSChaoyong He 	 * In secondary process, a released eth device can be found by its name
58466d5f53dSChaoyong He 	 * in shared memory.
58566d5f53dSChaoyong He 	 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the
58666d5f53dSChaoyong He 	 * eth device has been released.
58766d5f53dSChaoyong He 	 */
58866d5f53dSChaoyong He 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
58966d5f53dSChaoyong He 		if (dev->state == RTE_ETH_DEV_UNUSED)
590646ea79cSHeinrich Kuhn 			return 0;
591646ea79cSHeinrich Kuhn 
59266d5f53dSChaoyong He 		nfp_pf_secondary_uninit(dev->process_private);
59366d5f53dSChaoyong He 		return 0;
59466d5f53dSChaoyong He 	}
59566d5f53dSChaoyong He 
5969d723baaSChaoyong He 	hw = dev->data->dev_private;
59765f6915dSChaoyong He 	pf_dev = hw->pf_dev;
598646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(dev);
599968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
600646ea79cSHeinrich Kuhn 
601646ea79cSHeinrich Kuhn 	/*
602646ea79cSHeinrich Kuhn 	 * We assume that the DPDK application is stopping all the
603646ea79cSHeinrich Kuhn 	 * threads/queues before calling the device close function.
604646ea79cSHeinrich Kuhn 	 */
605646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
606646ea79cSHeinrich Kuhn 
607646ea79cSHeinrich Kuhn 	/* Clear queues */
6081c8d02bbSJin Liu 	nfp_net_close_tx_queue(dev);
6091c8d02bbSJin Liu 	nfp_net_close_rx_queue(dev);
610646ea79cSHeinrich Kuhn 
611851f03e1SHeinrich Kuhn 	/* Cancel possible impending LSC work here before releasing the port */
612f4d24fe9SChaoyong He 	rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev);
613851f03e1SHeinrich Kuhn 
614646ea79cSHeinrich Kuhn 	/* Only free PF resources after all physical ports have been closed */
615646ea79cSHeinrich Kuhn 	/* Mark this port as unused and free device priv resources */
616f58bde00SChaoyong He 	nn_cfg_writeb(&hw->super, NFP_NET_CFG_LSC, 0xff);
61766d5f53dSChaoyong He 
61866d5f53dSChaoyong He 	if (pf_dev->app_fw_id != NFP_APP_FW_CORE_NIC)
61966d5f53dSChaoyong He 		return -EINVAL;
62066d5f53dSChaoyong He 
62166d5f53dSChaoyong He 	nfp_cleanup_port_app_fw_nic(pf_dev, hw->idx);
622646ea79cSHeinrich Kuhn 
623968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
6243b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
6253b00109dSPeng Zhang 
626646ea79cSHeinrich Kuhn 		/* Check to see if ports are still in use */
6273b00109dSPeng Zhang 		if (app_fw_nic->ports[id] != NULL)
628646ea79cSHeinrich Kuhn 			return 0;
629646ea79cSHeinrich Kuhn 	}
630646ea79cSHeinrich Kuhn 
63166d5f53dSChaoyong He 	/* Enable in nfp_net_start() */
632d61138d4SHarman Kalra 	rte_intr_disable(pci_dev->intr_handle);
633646ea79cSHeinrich Kuhn 
63466d5f53dSChaoyong He 	/* Register in nfp_net_init() */
635d61138d4SHarman Kalra 	rte_intr_callback_unregister(pci_dev->intr_handle,
636a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)dev);
637646ea79cSHeinrich Kuhn 
63866d5f53dSChaoyong He 	nfp_uninit_app_fw_nic(pf_dev);
63966d5f53dSChaoyong He 	nfp_pf_uninit(pf_dev);
64066d5f53dSChaoyong He 
641646ea79cSHeinrich Kuhn 	return 0;
642646ea79cSHeinrich Kuhn }
643646ea79cSHeinrich Kuhn 
644c55abf61SChaoyong He static int
645c55abf61SChaoyong He nfp_net_find_vxlan_idx(struct nfp_net_hw *hw,
646c55abf61SChaoyong He 		uint16_t port,
647c55abf61SChaoyong He 		uint32_t *idx)
648c55abf61SChaoyong He {
649c55abf61SChaoyong He 	uint32_t i;
650c55abf61SChaoyong He 	int free_idx = -1;
651c55abf61SChaoyong He 
652c55abf61SChaoyong He 	for (i = 0; i < NFP_NET_N_VXLAN_PORTS; i++) {
653c55abf61SChaoyong He 		if (hw->vxlan_ports[i] == port) {
654c55abf61SChaoyong He 			free_idx = i;
655c55abf61SChaoyong He 			break;
656c55abf61SChaoyong He 		}
657c55abf61SChaoyong He 
658c55abf61SChaoyong He 		if (hw->vxlan_usecnt[i] == 0) {
659c55abf61SChaoyong He 			free_idx = i;
660c55abf61SChaoyong He 			break;
661c55abf61SChaoyong He 		}
662c55abf61SChaoyong He 	}
663c55abf61SChaoyong He 
664c55abf61SChaoyong He 	if (free_idx == -1)
665c55abf61SChaoyong He 		return -EINVAL;
666c55abf61SChaoyong He 
667c55abf61SChaoyong He 	*idx = free_idx;
668c55abf61SChaoyong He 
669c55abf61SChaoyong He 	return 0;
670c55abf61SChaoyong He }
671c55abf61SChaoyong He 
672c55abf61SChaoyong He static int
673c55abf61SChaoyong He nfp_udp_tunnel_port_add(struct rte_eth_dev *dev,
674c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
675c55abf61SChaoyong He {
676c55abf61SChaoyong He 	int ret;
677c55abf61SChaoyong He 	uint32_t idx;
678c55abf61SChaoyong He 	uint16_t vxlan_port;
679c55abf61SChaoyong He 	struct nfp_net_hw *hw;
680c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
681c55abf61SChaoyong He 
6829d723baaSChaoyong He 	hw = dev->data->dev_private;
683c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
684c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
685c55abf61SChaoyong He 
686c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
687c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel");
688c55abf61SChaoyong He 		return -ENOTSUP;
689c55abf61SChaoyong He 	}
690c55abf61SChaoyong He 
691c55abf61SChaoyong He 	ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx);
692c55abf61SChaoyong He 	if (ret != 0) {
693c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx");
694c55abf61SChaoyong He 		return -EINVAL;
695c55abf61SChaoyong He 	}
696c55abf61SChaoyong He 
697c55abf61SChaoyong He 	if (hw->vxlan_usecnt[idx] == 0) {
698c55abf61SChaoyong He 		ret = nfp_net_set_vxlan_port(hw, idx, vxlan_port);
699c55abf61SChaoyong He 		if (ret != 0) {
700c55abf61SChaoyong He 			PMD_DRV_LOG(ERR, "Failed set vxlan port");
701c55abf61SChaoyong He 			return -EINVAL;
702c55abf61SChaoyong He 		}
703c55abf61SChaoyong He 	}
704c55abf61SChaoyong He 
705c55abf61SChaoyong He 	hw->vxlan_usecnt[idx]++;
706c55abf61SChaoyong He 
707c55abf61SChaoyong He 	return 0;
708c55abf61SChaoyong He }
709c55abf61SChaoyong He 
710c55abf61SChaoyong He static int
711c55abf61SChaoyong He nfp_udp_tunnel_port_del(struct rte_eth_dev *dev,
712c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
713c55abf61SChaoyong He {
714c55abf61SChaoyong He 	int ret;
715c55abf61SChaoyong He 	uint32_t idx;
716c55abf61SChaoyong He 	uint16_t vxlan_port;
717c55abf61SChaoyong He 	struct nfp_net_hw *hw;
718c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
719c55abf61SChaoyong He 
7209d723baaSChaoyong He 	hw = dev->data->dev_private;
721c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
722c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
723c55abf61SChaoyong He 
724c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
725c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel");
726c55abf61SChaoyong He 		return -ENOTSUP;
727c55abf61SChaoyong He 	}
728c55abf61SChaoyong He 
729c55abf61SChaoyong He 	ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx);
730c55abf61SChaoyong He 	if (ret != 0 || hw->vxlan_usecnt[idx] == 0) {
731c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx");
732c55abf61SChaoyong He 		return -EINVAL;
733c55abf61SChaoyong He 	}
734c55abf61SChaoyong He 
735c55abf61SChaoyong He 	hw->vxlan_usecnt[idx]--;
736c55abf61SChaoyong He 
737c55abf61SChaoyong He 	if (hw->vxlan_usecnt[idx] == 0) {
738c55abf61SChaoyong He 		ret = nfp_net_set_vxlan_port(hw, idx, 0);
739c55abf61SChaoyong He 		if (ret != 0) {
740c55abf61SChaoyong He 			PMD_DRV_LOG(ERR, "Failed set vxlan port");
741c55abf61SChaoyong He 			return -EINVAL;
742c55abf61SChaoyong He 		}
743c55abf61SChaoyong He 	}
744c55abf61SChaoyong He 
745c55abf61SChaoyong He 	return 0;
746c55abf61SChaoyong He }
747c55abf61SChaoyong He 
748646ea79cSHeinrich Kuhn /* Initialise and register driver with DPDK Application */
7498d961320SJin Liu static const struct eth_dev_ops nfp_net_eth_dev_ops = {
750646ea79cSHeinrich Kuhn 	.dev_configure          = nfp_net_configure,
751646ea79cSHeinrich Kuhn 	.dev_start              = nfp_net_start,
752646ea79cSHeinrich Kuhn 	.dev_stop               = nfp_net_stop,
753646ea79cSHeinrich Kuhn 	.dev_set_link_up        = nfp_net_set_link_up,
754646ea79cSHeinrich Kuhn 	.dev_set_link_down      = nfp_net_set_link_down,
755646ea79cSHeinrich Kuhn 	.dev_close              = nfp_net_close,
756646ea79cSHeinrich Kuhn 	.promiscuous_enable     = nfp_net_promisc_enable,
757646ea79cSHeinrich Kuhn 	.promiscuous_disable    = nfp_net_promisc_disable,
7584a86c36bSQin Ke 	.allmulticast_enable    = nfp_net_allmulticast_enable,
7594a86c36bSQin Ke 	.allmulticast_disable   = nfp_net_allmulticast_disable,
760646ea79cSHeinrich Kuhn 	.link_update            = nfp_net_link_update,
761646ea79cSHeinrich Kuhn 	.stats_get              = nfp_net_stats_get,
762646ea79cSHeinrich Kuhn 	.stats_reset            = nfp_net_stats_reset,
763f26e8239SJames Hershaw 	.xstats_get             = nfp_net_xstats_get,
764f26e8239SJames Hershaw 	.xstats_reset           = nfp_net_xstats_reset,
765f26e8239SJames Hershaw 	.xstats_get_names       = nfp_net_xstats_get_names,
766f26e8239SJames Hershaw 	.xstats_get_by_id       = nfp_net_xstats_get_by_id,
767f26e8239SJames Hershaw 	.xstats_get_names_by_id = nfp_net_xstats_get_names_by_id,
768646ea79cSHeinrich Kuhn 	.dev_infos_get          = nfp_net_infos_get,
769646ea79cSHeinrich Kuhn 	.dev_supported_ptypes_get = nfp_net_supported_ptypes_get,
770646ea79cSHeinrich Kuhn 	.mtu_set                = nfp_net_dev_mtu_set,
7710a94d6bcSJin Liu 	.mac_addr_set           = nfp_net_set_mac_addr,
772646ea79cSHeinrich Kuhn 	.vlan_offload_set       = nfp_net_vlan_offload_set,
773646ea79cSHeinrich Kuhn 	.reta_update            = nfp_net_reta_update,
774646ea79cSHeinrich Kuhn 	.reta_query             = nfp_net_reta_query,
775646ea79cSHeinrich Kuhn 	.rss_hash_update        = nfp_net_rss_hash_update,
776646ea79cSHeinrich Kuhn 	.rss_hash_conf_get      = nfp_net_rss_hash_conf_get,
777646ea79cSHeinrich Kuhn 	.rx_queue_setup         = nfp_net_rx_queue_setup,
778646ea79cSHeinrich Kuhn 	.rx_queue_release       = nfp_net_rx_queue_release,
7798d961320SJin Liu 	.tx_queue_setup         = nfp_net_tx_queue_setup,
78052ddc4c2SJin Liu 	.tx_queue_release       = nfp_net_tx_queue_release,
78152ddc4c2SJin Liu 	.rx_queue_intr_enable   = nfp_rx_queue_intr_enable,
78252ddc4c2SJin Liu 	.rx_queue_intr_disable  = nfp_rx_queue_intr_disable,
783c55abf61SChaoyong He 	.udp_tunnel_port_add    = nfp_udp_tunnel_port_add,
784c55abf61SChaoyong He 	.udp_tunnel_port_del    = nfp_udp_tunnel_port_del,
785128c8ad9SChaoyong He 	.fw_version_get         = nfp_net_firmware_version_get,
78651d15e82SZerun Fu 	.flow_ctrl_get          = nfp_net_flow_ctrl_get,
78768aa3537SZerun Fu 	.flow_ctrl_set          = nfp_net_flow_ctrl_set,
7880b9079d2SChaoyong He 	.flow_ops_get           = nfp_net_flow_ops_get,
7890786add9SZerun Fu 	.fec_get_capability     = nfp_net_fec_get_capability,
790c6835a32SZerun Fu 	.fec_get                = nfp_net_fec_get,
79137bd1b84SZerun Fu 	.fec_set                = nfp_net_fec_set,
79252ddc4c2SJin Liu };
79352ddc4c2SJin Liu 
794ee8ca64eSChaoyong He static inline void
795ee8ca64eSChaoyong He nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw,
796ee8ca64eSChaoyong He 		struct rte_eth_dev *eth_dev)
797266470b2SJin Liu {
798ee8ca64eSChaoyong He 	if (hw->ver.extend == NFP_NET_CFG_VERSION_DP_NFD3)
799ee8ca64eSChaoyong He 		eth_dev->tx_pkt_burst = nfp_net_nfd3_xmit_pkts;
800ee8ca64eSChaoyong He 	else
801ee8ca64eSChaoyong He 		eth_dev->tx_pkt_burst = nfp_net_nfdk_xmit_pkts;
802266470b2SJin Liu 
8038d961320SJin Liu 	eth_dev->dev_ops = &nfp_net_eth_dev_ops;
804266470b2SJin Liu 	eth_dev->rx_queue_count = nfp_net_rx_queue_count;
805266470b2SJin Liu 	eth_dev->rx_pkt_burst = &nfp_net_recv_pkts;
806266470b2SJin Liu }
807266470b2SJin Liu 
808646ea79cSHeinrich Kuhn static int
809646ea79cSHeinrich Kuhn nfp_net_init(struct rte_eth_dev *eth_dev)
810646ea79cSHeinrich Kuhn {
81149952141SChaoyong He 	int err;
81249952141SChaoyong He 	uint16_t port;
8130314a8ffSChaoyong He 	uint64_t rx_base;
8140314a8ffSChaoyong He 	uint64_t tx_base;
8154a9bb682SChaoyong He 	struct nfp_hw *hw;
8164a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
81749952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
81849952141SChaoyong He 	struct rte_pci_device *pci_dev;
81949952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
820646ea79cSHeinrich Kuhn 
821646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
82265f6915dSChaoyong He 	net_hw = eth_dev->data->dev_private;
823646ea79cSHeinrich Kuhn 
824646ea79cSHeinrich Kuhn 	/* Use backpointer here to the PF of this eth_dev */
82565f6915dSChaoyong He 	pf_dev = net_hw->pf_dev;
826646ea79cSHeinrich Kuhn 
827968ec1c3SChaoyong He 	/* Use backpointer to the CoreNIC app struct */
828968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
829968ec1c3SChaoyong He 
830646ea79cSHeinrich Kuhn 	port = ((struct nfp_net_hw *)eth_dev->data->dev_private)->idx;
8318ceb85c3SChaoyong He 	if (port > 7) {
832646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "Port value is wrong");
833646ea79cSHeinrich Kuhn 		return -ENODEV;
834646ea79cSHeinrich Kuhn 	}
835646ea79cSHeinrich Kuhn 
8364a9bb682SChaoyong He 	hw = &net_hw->super;
837646ea79cSHeinrich Kuhn 
838030b2b19SChaoyong He 	PMD_INIT_LOG(DEBUG, "Working with physical port number: %hu, "
8394a9bb682SChaoyong He 			"NFP internal port number: %d", port, net_hw->nfp_idx);
840646ea79cSHeinrich Kuhn 
841646ea79cSHeinrich Kuhn 	rte_eth_copy_pci_info(eth_dev, pci_dev);
842646ea79cSHeinrich Kuhn 
8438ad2cc8fSPeng Zhang 	if (port == 0 || pf_dev->multi_pf.enabled) {
844f26e8239SJames Hershaw 		uint32_t min_size;
845f26e8239SJames Hershaw 
8464a9bb682SChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar;
8474a9bb682SChaoyong He 		min_size = NFP_MAC_STATS_SIZE * net_hw->pf_dev->nfp_eth_table->max_index;
8484a9bb682SChaoyong He 		net_hw->mac_stats_bar = nfp_rtsym_map(net_hw->pf_dev->sym_tbl, "_mac_stats",
8494a9bb682SChaoyong He 				min_size, &net_hw->mac_stats_area);
8504a9bb682SChaoyong He 		if (net_hw->mac_stats_bar == NULL) {
851f26e8239SJames Hershaw 			PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for _mac_stats_bar");
852f26e8239SJames Hershaw 			return -EIO;
853f26e8239SJames Hershaw 		}
854b0c496abSChaoyong He 
8554a9bb682SChaoyong He 		net_hw->mac_stats = net_hw->mac_stats_bar;
856646ea79cSHeinrich Kuhn 	} else {
857a6189a67SJin Liu 		/* Use port offset in pf ctrl_bar for this ports control bar */
8584a9bb682SChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar + (port * NFP_NET_CFG_BAR_SZ);
8594a9bb682SChaoyong He 		net_hw->mac_stats = app_fw_nic->ports[0]->mac_stats_bar +
8604a9bb682SChaoyong He 				(net_hw->nfp_idx * NFP_MAC_STATS_SIZE);
861646ea79cSHeinrich Kuhn 	}
862646ea79cSHeinrich Kuhn 
8634a9bb682SChaoyong He 	PMD_INIT_LOG(DEBUG, "ctrl bar: %p", hw->ctrl_bar);
8644a9bb682SChaoyong He 	PMD_INIT_LOG(DEBUG, "MAC stats: %p", net_hw->mac_stats);
865646ea79cSHeinrich Kuhn 
8664a9bb682SChaoyong He 	err = nfp_net_common_init(pci_dev, net_hw);
867cd4397ebSPeng Zhang 	if (err != 0)
86836994566SChaoyong He 		goto free_area;
869fd392f84SPeng Zhang 
870eecdfcc1SShihong Wang 	err = nfp_net_tlv_caps_parse(eth_dev);
871eecdfcc1SShihong Wang 	if (err != 0) {
872eecdfcc1SShihong Wang 		PMD_INIT_LOG(ERR, "Failed to parser TLV caps");
873eecdfcc1SShihong Wang 		return err;
87436994566SChaoyong He 		goto free_area;
875eecdfcc1SShihong Wang 	}
876eecdfcc1SShihong Wang 
87754713740SChang Miao 	err = nfp_ipsec_init(eth_dev);
87854713740SChang Miao 	if (err != 0) {
87954713740SChang Miao 		PMD_INIT_LOG(ERR, "Failed to init IPsec module");
88036994566SChaoyong He 		goto free_area;
88154713740SChang Miao 	}
88254713740SChang Miao 
8834a9bb682SChaoyong He 	nfp_net_ethdev_ops_mount(net_hw, eth_dev);
884266470b2SJin Liu 
8854a9bb682SChaoyong He 	net_hw->eth_xstats_base = rte_malloc("rte_eth_xstat", sizeof(struct rte_eth_xstat) *
886f26e8239SJames Hershaw 			nfp_net_xstats_size(eth_dev), 0);
8874a9bb682SChaoyong He 	if (net_hw->eth_xstats_base == NULL) {
888f26e8239SJames Hershaw 		PMD_INIT_LOG(ERR, "no memory for xstats base values on device %s!",
889f26e8239SJames Hershaw 				pci_dev->device.name);
89036994566SChaoyong He 		err = -ENOMEM;
89136994566SChaoyong He 		goto ipsec_exit;
892f26e8239SJames Hershaw 	}
893f26e8239SJames Hershaw 
894646ea79cSHeinrich Kuhn 	/* Work out where in the BAR the queues start. */
8954a9bb682SChaoyong He 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
8964a9bb682SChaoyong He 	rx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_RXQ);
897646ea79cSHeinrich Kuhn 
8984a9bb682SChaoyong He 	net_hw->tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
8994a9bb682SChaoyong He 	net_hw->rx_bar = pf_dev->qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ;
9004a9bb682SChaoyong He 	eth_dev->data->dev_private = net_hw;
901646ea79cSHeinrich Kuhn 
902646ea79cSHeinrich Kuhn 	PMD_INIT_LOG(DEBUG, "ctrl_bar: %p, tx_bar: %p, rx_bar: %p",
9034a9bb682SChaoyong He 			hw->ctrl_bar, net_hw->tx_bar, net_hw->rx_bar);
904646ea79cSHeinrich Kuhn 
9054a9bb682SChaoyong He 	nfp_net_cfg_queue_setup(net_hw);
9064a9bb682SChaoyong He 	net_hw->mtu = RTE_ETHER_MTU;
907646ea79cSHeinrich Kuhn 
908646ea79cSHeinrich Kuhn 	/* VLAN insertion is incompatible with LSOv2 */
9094a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LSO2) != 0)
9104a9bb682SChaoyong He 		hw->cap &= ~NFP_NET_CFG_CTRL_TXVLAN;
911646ea79cSHeinrich Kuhn 
9124a9bb682SChaoyong He 	nfp_net_log_device_information(net_hw);
913646ea79cSHeinrich Kuhn 
914646ea79cSHeinrich Kuhn 	/* Initializing spinlock for reconfigs */
9154a9bb682SChaoyong He 	rte_spinlock_init(&hw->reconfig_lock);
916646ea79cSHeinrich Kuhn 
917646ea79cSHeinrich Kuhn 	/* Allocating memory for mac addr */
918f4d24fe9SChaoyong He 	eth_dev->data->mac_addrs = rte_zmalloc("mac_addr", RTE_ETHER_ADDR_LEN, 0);
919646ea79cSHeinrich Kuhn 	if (eth_dev->data->mac_addrs == NULL) {
920646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Failed to space for MAC address");
92136994566SChaoyong He 		err = -ENOMEM;
92236994566SChaoyong He 		goto xstats_free;
923646ea79cSHeinrich Kuhn 	}
924646ea79cSHeinrich Kuhn 
925968ec1c3SChaoyong He 	nfp_net_pf_read_mac(app_fw_nic, port);
926503ac807SChaoyong He 	nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
927646ea79cSHeinrich Kuhn 
9284a9bb682SChaoyong He 	if (rte_is_valid_assigned_ether_addr(&hw->mac_addr) == 0) {
929a6189a67SJin Liu 		PMD_INIT_LOG(INFO, "Using random mac address for port %d", port);
930646ea79cSHeinrich Kuhn 		/* Using random mac addresses for VFs */
9314a9bb682SChaoyong He 		rte_eth_random_addr(&hw->mac_addr.addr_bytes[0]);
932503ac807SChaoyong He 		nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
933646ea79cSHeinrich Kuhn 	}
934646ea79cSHeinrich Kuhn 
935646ea79cSHeinrich Kuhn 	/* Copying mac address to DPDK eth_dev struct */
9364a9bb682SChaoyong He 	rte_ether_addr_copy(&hw->mac_addr, eth_dev->data->mac_addrs);
937646ea79cSHeinrich Kuhn 
9384a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) == 0)
939646ea79cSHeinrich Kuhn 		eth_dev->data->dev_flags |= RTE_ETH_DEV_NOLIVE_MAC_ADDR;
940646ea79cSHeinrich Kuhn 
941646ea79cSHeinrich Kuhn 	eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
942646ea79cSHeinrich Kuhn 
943030b2b19SChaoyong He 	PMD_INIT_LOG(INFO, "port %d VendorID=%#x DeviceID=%#x "
944c2c4f87bSAman Deep Singh 			"mac=" RTE_ETHER_ADDR_PRT_FMT,
945646ea79cSHeinrich Kuhn 			eth_dev->data->port_id, pci_dev->id.vendor_id,
946646ea79cSHeinrich Kuhn 			pci_dev->id.device_id,
9474a9bb682SChaoyong He 			RTE_ETHER_ADDR_BYTES(&hw->mac_addr));
948646ea79cSHeinrich Kuhn 
949646ea79cSHeinrich Kuhn 	/* Registering LSC interrupt handler */
950d61138d4SHarman Kalra 	rte_intr_callback_register(pci_dev->intr_handle,
951a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)eth_dev);
952646ea79cSHeinrich Kuhn 	/* Telling the firmware about the LSC interrupt entry */
9534a9bb682SChaoyong He 	nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
95494d0631aSPeng Zhang 	/* Unmask the LSC interrupt */
95594d0631aSPeng Zhang 	nfp_net_irq_unmask(eth_dev);
956646ea79cSHeinrich Kuhn 	/* Recording current stats counters values */
957646ea79cSHeinrich Kuhn 	nfp_net_stats_reset(eth_dev);
958646ea79cSHeinrich Kuhn 
9598153bc6fSChaoyong He 	if ((hw->cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) {
9608153bc6fSChaoyong He 		err = nfp_net_flow_priv_init(pf_dev, port);
9618153bc6fSChaoyong He 		if (err != 0) {
9628153bc6fSChaoyong He 			PMD_INIT_LOG(ERR, "Init net flow priv failed");
9638153bc6fSChaoyong He 			goto xstats_free;
9648153bc6fSChaoyong He 		}
9658153bc6fSChaoyong He 	}
9668153bc6fSChaoyong He 
967646ea79cSHeinrich Kuhn 	return 0;
96836994566SChaoyong He 
96936994566SChaoyong He xstats_free:
97036994566SChaoyong He 	rte_free(net_hw->eth_xstats_base);
97136994566SChaoyong He ipsec_exit:
97236994566SChaoyong He 	nfp_ipsec_uninit(eth_dev);
97336994566SChaoyong He free_area:
97436994566SChaoyong He 	if (net_hw->mac_stats_area != NULL)
97536994566SChaoyong He 		nfp_cpp_area_release_free(net_hw->mac_stats_area);
97636994566SChaoyong He 
97736994566SChaoyong He 	return err;
978646ea79cSHeinrich Kuhn }
979646ea79cSHeinrich Kuhn 
980646ea79cSHeinrich Kuhn #define DEFAULT_FW_PATH       "/lib/firmware/netronome"
981646ea79cSHeinrich Kuhn 
982646ea79cSHeinrich Kuhn static int
983ebfb540eSPeng Zhang nfp_fw_get_name(struct rte_pci_device *dev,
984f4d24fe9SChaoyong He 		struct nfp_nsp *nsp,
985ebfb540eSPeng Zhang 		char *card,
986ebfb540eSPeng Zhang 		char *fw_name,
987ebfb540eSPeng Zhang 		size_t fw_size)
988646ea79cSHeinrich Kuhn {
98949952141SChaoyong He 	char serial[40];
990ff627b74SChaoyong He 	uint16_t interface;
991ff627b74SChaoyong He 	uint32_t cpp_serial_len;
992ff627b74SChaoyong He 	const uint8_t *cpp_serial;
99349952141SChaoyong He 	struct nfp_cpp *cpp = nfp_nsp_cpp(nsp);
994ff627b74SChaoyong He 
995ff627b74SChaoyong He 	cpp_serial_len = nfp_cpp_serial(cpp, &cpp_serial);
996ff627b74SChaoyong He 	if (cpp_serial_len != NFP_SERIAL_LEN)
997ff627b74SChaoyong He 		return -ERANGE;
998ff627b74SChaoyong He 
999ff627b74SChaoyong He 	interface = nfp_cpp_interface(cpp);
1000646ea79cSHeinrich Kuhn 
1001646ea79cSHeinrich Kuhn 	/* Looking for firmware file in order of priority */
1002646ea79cSHeinrich Kuhn 
1003646ea79cSHeinrich Kuhn 	/* First try to find a firmware image specific for this device */
1004646ea79cSHeinrich Kuhn 	snprintf(serial, sizeof(serial),
1005646ea79cSHeinrich Kuhn 			"serial-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
1006ff627b74SChaoyong He 			cpp_serial[0], cpp_serial[1], cpp_serial[2], cpp_serial[3],
1007ff627b74SChaoyong He 			cpp_serial[4], cpp_serial[5], interface >> 8, interface & 0xff);
1008ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/%s.nffw", DEFAULT_FW_PATH, serial);
1009646ea79cSHeinrich Kuhn 
1010646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1011ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1012ebfb540eSPeng Zhang 		return 0;
1013b0c496abSChaoyong He 
1014646ea79cSHeinrich Kuhn 	/* Then try the PCI name */
1015ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/pci-%s.nffw", DEFAULT_FW_PATH,
10163ddb4cc0SPeng Zhang 			dev->name);
1017646ea79cSHeinrich Kuhn 
1018646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1019ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1020ebfb540eSPeng Zhang 		return 0;
1021646ea79cSHeinrich Kuhn 
1022646ea79cSHeinrich Kuhn 	/* Finally try the card type and media */
1023ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/%s", DEFAULT_FW_PATH, card);
1024646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1025ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1026ebfb540eSPeng Zhang 		return 0;
1027c01e5c0cSChaoyong He 
1028646ea79cSHeinrich Kuhn 	return -ENOENT;
1029ebfb540eSPeng Zhang }
1030646ea79cSHeinrich Kuhn 
1031ebfb540eSPeng Zhang static int
1032ebfb540eSPeng Zhang nfp_fw_upload(struct nfp_nsp *nsp,
1033ebfb540eSPeng Zhang 		char *fw_name)
1034ebfb540eSPeng Zhang {
1035ebfb540eSPeng Zhang 	int err;
1036ebfb540eSPeng Zhang 	void *fw_buf;
1037ebfb540eSPeng Zhang 	size_t fsize;
1038ebfb540eSPeng Zhang 
1039ebfb540eSPeng Zhang 	err = rte_firmware_read(fw_name, &fw_buf, &fsize);
1040ebfb540eSPeng Zhang 	if (err != 0) {
1041ebfb540eSPeng Zhang 		PMD_DRV_LOG(ERR, "firmware %s not found!", fw_name);
1042ebfb540eSPeng Zhang 		return -ENOENT;
1043ebfb540eSPeng Zhang 	}
1044ebfb540eSPeng Zhang 
1045646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %zu",
1046646ea79cSHeinrich Kuhn 			fw_name, fsize);
1047646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Uploading the firmware ...");
10482e634b03SPeng Zhang 	if (nfp_nsp_load_fw(nsp, fw_buf, fsize) < 0) {
10492e634b03SPeng Zhang 		free(fw_buf);
10502e634b03SPeng Zhang 		PMD_DRV_LOG(ERR, "Firmware load failed.");
10512e634b03SPeng Zhang 		return -EIO;
10522e634b03SPeng Zhang 	}
10532e634b03SPeng Zhang 
1054646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Done");
1055646ea79cSHeinrich Kuhn 
1056646ea79cSHeinrich Kuhn 	free(fw_buf);
1057646ea79cSHeinrich Kuhn 
1058646ea79cSHeinrich Kuhn 	return 0;
1059646ea79cSHeinrich Kuhn }
1060646ea79cSHeinrich Kuhn 
10613b00109dSPeng Zhang static void
10623b00109dSPeng Zhang nfp_fw_unload(struct nfp_cpp *cpp)
10633b00109dSPeng Zhang {
10643b00109dSPeng Zhang 	struct nfp_nsp *nsp;
10653b00109dSPeng Zhang 
10663b00109dSPeng Zhang 	nsp = nfp_nsp_open(cpp);
10673b00109dSPeng Zhang 	if (nsp == NULL)
10683b00109dSPeng Zhang 		return;
10693b00109dSPeng Zhang 
10703b00109dSPeng Zhang 	nfp_nsp_device_soft_reset(nsp);
10713b00109dSPeng Zhang 	nfp_nsp_close(nsp);
10723b00109dSPeng Zhang }
10733b00109dSPeng Zhang 
1074646ea79cSHeinrich Kuhn static int
1075*a2bc299dSPeng Zhang nfp_fw_check_change(struct nfp_cpp *cpp,
1076*a2bc299dSPeng Zhang 		char *fw_name,
1077*a2bc299dSPeng Zhang 		bool *fw_changed)
1078*a2bc299dSPeng Zhang {
1079*a2bc299dSPeng Zhang 	int ret;
1080*a2bc299dSPeng Zhang 	struct nfp_net_hw hw;
1081*a2bc299dSPeng Zhang 	uint32_t new_version = 0;
1082*a2bc299dSPeng Zhang 	uint32_t old_version = 0;
1083*a2bc299dSPeng Zhang 
1084*a2bc299dSPeng Zhang 	ret = nfp_elf_get_fw_version(&new_version, fw_name);
1085*a2bc299dSPeng Zhang 	if (ret != 0)
1086*a2bc299dSPeng Zhang 		return ret;
1087*a2bc299dSPeng Zhang 
1088*a2bc299dSPeng Zhang 	hw.cpp = cpp;
1089*a2bc299dSPeng Zhang 	nfp_net_get_fw_version(&hw, &old_version);
1090*a2bc299dSPeng Zhang 
1091*a2bc299dSPeng Zhang 	if (new_version != old_version) {
1092*a2bc299dSPeng Zhang 		PMD_DRV_LOG(INFO, "FW version is changed, new %u, old %u",
1093*a2bc299dSPeng Zhang 				new_version, old_version);
1094*a2bc299dSPeng Zhang 		*fw_changed = true;
1095*a2bc299dSPeng Zhang 	} else {
1096*a2bc299dSPeng Zhang 		PMD_DRV_LOG(INFO, "FW version is not changed and is %u", new_version);
1097*a2bc299dSPeng Zhang 		*fw_changed = false;
1098*a2bc299dSPeng Zhang 	}
1099*a2bc299dSPeng Zhang 
1100*a2bc299dSPeng Zhang 	return 0;
1101*a2bc299dSPeng Zhang }
1102*a2bc299dSPeng Zhang 
1103*a2bc299dSPeng Zhang static int
1104ebfb540eSPeng Zhang nfp_fw_reload(struct nfp_nsp *nsp,
1105ebfb540eSPeng Zhang 		char *fw_name)
11068ba461d1SPeng Zhang {
11078ba461d1SPeng Zhang 	int err;
11088ba461d1SPeng Zhang 
11098ba461d1SPeng Zhang 	nfp_nsp_device_soft_reset(nsp);
1110ebfb540eSPeng Zhang 	err = nfp_fw_upload(nsp, fw_name);
11118ba461d1SPeng Zhang 	if (err != 0)
11128ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP firmware load failed");
11138ba461d1SPeng Zhang 
11148ba461d1SPeng Zhang 	return err;
11158ba461d1SPeng Zhang }
11168ba461d1SPeng Zhang 
1117a99ca614SPeng Zhang static bool
1118a99ca614SPeng Zhang nfp_fw_skip_load(const struct nfp_dev_info *dev_info,
11198ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
11208ba461d1SPeng Zhang {
112174397a7aSPeng Zhang 	uint8_t i;
112274397a7aSPeng Zhang 	uint64_t tmp_beat;
11238ba461d1SPeng Zhang 	uint32_t port_num;
11248b9a83eaSPeng Zhang 	uint8_t in_use = 0;
112574397a7aSPeng Zhang 	uint64_t beat[dev_info->pf_num_per_unit];
112674397a7aSPeng Zhang 	uint32_t offset[dev_info->pf_num_per_unit];
11278b9a83eaSPeng Zhang 	uint8_t abnormal = dev_info->pf_num_per_unit;
112874397a7aSPeng Zhang 
112974397a7aSPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
113074397a7aSPeng Zhang 		offset[port_num] = NFP_BEAT_OFFSET(port_num);
113174397a7aSPeng Zhang 		beat[port_num] = nn_readq(multi_pf->beat_addr + offset[port_num]);
11328b9a83eaSPeng Zhang 		if (beat[port_num] == 0)
11338b9a83eaSPeng Zhang 			abnormal--;
113474397a7aSPeng Zhang 	}
11358ba461d1SPeng Zhang 
11368b9a83eaSPeng Zhang 	if (abnormal == 0)
11378b9a83eaSPeng Zhang 		return true;
11388b9a83eaSPeng Zhang 
113974397a7aSPeng Zhang 	for (i = 0; i < 3; i++) {
114074397a7aSPeng Zhang 		sleep(1);
11418ba461d1SPeng Zhang 		for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
11428ba461d1SPeng Zhang 			if (port_num == multi_pf->function_id)
11438ba461d1SPeng Zhang 				continue;
11448ba461d1SPeng Zhang 
11458b9a83eaSPeng Zhang 			if (beat[port_num] == 0)
11468b9a83eaSPeng Zhang 				continue;
11478b9a83eaSPeng Zhang 
114874397a7aSPeng Zhang 			tmp_beat = nn_readq(multi_pf->beat_addr + offset[port_num]);
11498b9a83eaSPeng Zhang 			if (tmp_beat != beat[port_num]) {
11508b9a83eaSPeng Zhang 				in_use++;
11518b9a83eaSPeng Zhang 				abnormal--;
11528b9a83eaSPeng Zhang 				beat[port_num] = 0;
11538b9a83eaSPeng Zhang 			}
11548b9a83eaSPeng Zhang 		}
11558b9a83eaSPeng Zhang 
11568b9a83eaSPeng Zhang 		if (abnormal == 0)
1157a99ca614SPeng Zhang 			return true;
11588ba461d1SPeng Zhang 	}
11598b9a83eaSPeng Zhang 
11608b9a83eaSPeng Zhang 	if (in_use != 0) {
11618b9a83eaSPeng Zhang 		PMD_DRV_LOG(WARNING, "Abnormal %u != 0, the nic has port which is exit abnormally.",
11628b9a83eaSPeng Zhang 				abnormal);
11638b9a83eaSPeng Zhang 		return true;
11648ba461d1SPeng Zhang 	}
11658ba461d1SPeng Zhang 
1166a99ca614SPeng Zhang 	return false;
11678ba461d1SPeng Zhang }
1168*a2bc299dSPeng Zhang static int
1169*a2bc299dSPeng Zhang nfp_fw_reload_for_single_pf(struct nfp_nsp *nsp,
1170*a2bc299dSPeng Zhang 		char *fw_name,
1171*a2bc299dSPeng Zhang 		struct nfp_cpp *cpp)
1172*a2bc299dSPeng Zhang {
1173*a2bc299dSPeng Zhang 	int ret;
1174*a2bc299dSPeng Zhang 	bool fw_changed = true;
1175*a2bc299dSPeng Zhang 
1176*a2bc299dSPeng Zhang 	if (nfp_nsp_fw_loaded(nsp)) {
1177*a2bc299dSPeng Zhang 		ret = nfp_fw_check_change(cpp, fw_name, &fw_changed);
1178*a2bc299dSPeng Zhang 		if (ret != 0)
1179*a2bc299dSPeng Zhang 			return ret;
1180*a2bc299dSPeng Zhang 	}
1181*a2bc299dSPeng Zhang 
1182*a2bc299dSPeng Zhang 	if (!fw_changed)
1183*a2bc299dSPeng Zhang 		return 0;
1184*a2bc299dSPeng Zhang 
1185*a2bc299dSPeng Zhang 	ret = nfp_fw_reload(nsp, fw_name);
1186*a2bc299dSPeng Zhang 	if (ret != 0)
1187*a2bc299dSPeng Zhang 		return ret;
1188*a2bc299dSPeng Zhang 
1189*a2bc299dSPeng Zhang 	return 0;
1190*a2bc299dSPeng Zhang }
11918ba461d1SPeng Zhang 
11928ba461d1SPeng Zhang static int
1193*a2bc299dSPeng Zhang nfp_fw_reload_for_multi_pf(struct nfp_nsp *nsp,
1194ebfb540eSPeng Zhang 		char *fw_name,
11958ba461d1SPeng Zhang 		struct nfp_cpp *cpp,
11968ba461d1SPeng Zhang 		const struct nfp_dev_info *dev_info,
11978ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
11988ba461d1SPeng Zhang {
11998ba461d1SPeng Zhang 	int err;
1200*a2bc299dSPeng Zhang 	bool fw_changed = true;
1201a99ca614SPeng Zhang 	bool skip_load_fw = false;
12028ba461d1SPeng Zhang 
12038ba461d1SPeng Zhang 	err = nfp_net_keepalive_init(cpp, multi_pf);
12048ba461d1SPeng Zhang 	if (err != 0) {
1205a99ca614SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP init beat failed");
12068ba461d1SPeng Zhang 		return err;
12078ba461d1SPeng Zhang 	}
12088ba461d1SPeng Zhang 
12098ba461d1SPeng Zhang 	err = nfp_net_keepalive_start(multi_pf);
12108ba461d1SPeng Zhang 	if (err != 0) {
12118ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP write beat failed");
1212*a2bc299dSPeng Zhang 		goto keepalive_uninit;
12138ba461d1SPeng Zhang 	}
12148ba461d1SPeng Zhang 
1215*a2bc299dSPeng Zhang 	if (nfp_nsp_fw_loaded(nsp)) {
1216*a2bc299dSPeng Zhang 		err = nfp_fw_check_change(cpp, fw_name, &fw_changed);
1217*a2bc299dSPeng Zhang 		if (err != 0)
1218*a2bc299dSPeng Zhang 			goto keepalive_stop;
1219*a2bc299dSPeng Zhang 	}
1220*a2bc299dSPeng Zhang 
1221*a2bc299dSPeng Zhang 	if (!fw_changed)
1222a99ca614SPeng Zhang 		skip_load_fw = nfp_fw_skip_load(dev_info, multi_pf);
1223a99ca614SPeng Zhang 
1224a99ca614SPeng Zhang 	if (skip_load_fw)
1225a99ca614SPeng Zhang 		return 0;
1226a99ca614SPeng Zhang 
1227a99ca614SPeng Zhang 	err = nfp_fw_reload(nsp, fw_name);
1228*a2bc299dSPeng Zhang 	if (err != 0)
1229*a2bc299dSPeng Zhang 		goto keepalive_stop;
12308ba461d1SPeng Zhang 
1231b67a7b40SPeng Zhang 	nfp_net_keepalive_clear_others(dev_info, multi_pf);
1232b67a7b40SPeng Zhang 
1233a99ca614SPeng Zhang 	return 0;
1234*a2bc299dSPeng Zhang 
1235*a2bc299dSPeng Zhang keepalive_stop:
1236*a2bc299dSPeng Zhang 	nfp_net_keepalive_stop(multi_pf);
1237*a2bc299dSPeng Zhang keepalive_uninit:
1238*a2bc299dSPeng Zhang 	nfp_net_keepalive_uninit(multi_pf);
1239*a2bc299dSPeng Zhang 
1240*a2bc299dSPeng Zhang 	return err;
1241a99ca614SPeng Zhang }
1242a99ca614SPeng Zhang 
12438ba461d1SPeng Zhang static int
1244a6189a67SJin Liu nfp_fw_setup(struct rte_pci_device *dev,
1245a6189a67SJin Liu 		struct nfp_cpp *cpp,
1246a6189a67SJin Liu 		struct nfp_eth_table *nfp_eth_table,
12478ba461d1SPeng Zhang 		struct nfp_hwinfo *hwinfo,
12488ba461d1SPeng Zhang 		const struct nfp_dev_info *dev_info,
12498ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
1250646ea79cSHeinrich Kuhn {
125149952141SChaoyong He 	int err;
1252ebfb540eSPeng Zhang 	char fw_name[125];
125349952141SChaoyong He 	char card_desc[100];
1254646ea79cSHeinrich Kuhn 	struct nfp_nsp *nsp;
1255646ea79cSHeinrich Kuhn 	const char *nfp_fw_model;
1256646ea79cSHeinrich Kuhn 
125706be30d4SPeng Zhang 	nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "nffw.partno");
125806be30d4SPeng Zhang 	if (nfp_fw_model == NULL)
1259646ea79cSHeinrich Kuhn 		nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "assembly.partno");
1260646ea79cSHeinrich Kuhn 
1261c01e5c0cSChaoyong He 	if (nfp_fw_model != NULL) {
1262646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(INFO, "firmware model found: %s", nfp_fw_model);
1263646ea79cSHeinrich Kuhn 	} else {
1264646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "firmware model NOT found");
1265646ea79cSHeinrich Kuhn 		return -EIO;
1266646ea79cSHeinrich Kuhn 	}
1267646ea79cSHeinrich Kuhn 
1268646ea79cSHeinrich Kuhn 	if (nfp_eth_table->count == 0 || nfp_eth_table->count > 8) {
1269646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "NFP ethernet table reports wrong ports: %u",
1270646ea79cSHeinrich Kuhn 				nfp_eth_table->count);
1271646ea79cSHeinrich Kuhn 		return -EIO;
1272646ea79cSHeinrich Kuhn 	}
1273646ea79cSHeinrich Kuhn 
1274646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "NFP ethernet port table reports %u ports",
1275646ea79cSHeinrich Kuhn 			nfp_eth_table->count);
1276646ea79cSHeinrich Kuhn 
1277646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Port speed: %u", nfp_eth_table->ports[0].speed);
1278646ea79cSHeinrich Kuhn 
1279646ea79cSHeinrich Kuhn 	snprintf(card_desc, sizeof(card_desc), "nic_%s_%dx%d.nffw",
1280646ea79cSHeinrich Kuhn 			nfp_fw_model, nfp_eth_table->count,
1281646ea79cSHeinrich Kuhn 			nfp_eth_table->ports[0].speed / 1000);
1282646ea79cSHeinrich Kuhn 
1283646ea79cSHeinrich Kuhn 	nsp = nfp_nsp_open(cpp);
1284a6189a67SJin Liu 	if (nsp == NULL) {
1285646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle");
1286646ea79cSHeinrich Kuhn 		return -EIO;
1287646ea79cSHeinrich Kuhn 	}
1288646ea79cSHeinrich Kuhn 
1289ebfb540eSPeng Zhang 	err = nfp_fw_get_name(dev, nsp, card_desc, fw_name, sizeof(fw_name));
1290ebfb540eSPeng Zhang 	if (err != 0) {
1291ebfb540eSPeng Zhang 		PMD_DRV_LOG(ERR, "Can't find suitable firmware.");
1292ebfb540eSPeng Zhang 		nfp_nsp_close(nsp);
1293ebfb540eSPeng Zhang 		return err;
1294ebfb540eSPeng Zhang 	}
1295ebfb540eSPeng Zhang 
12968ba461d1SPeng Zhang 	if (multi_pf->enabled)
1297*a2bc299dSPeng Zhang 		err = nfp_fw_reload_for_multi_pf(nsp, fw_name, cpp, dev_info, multi_pf);
12988ba461d1SPeng Zhang 	else
1299*a2bc299dSPeng Zhang 		err = nfp_fw_reload_for_single_pf(nsp, fw_name, cpp);
1300646ea79cSHeinrich Kuhn 
1301646ea79cSHeinrich Kuhn 	nfp_nsp_close(nsp);
1302646ea79cSHeinrich Kuhn 	return err;
1303646ea79cSHeinrich Kuhn }
1304646ea79cSHeinrich Kuhn 
13058ad2cc8fSPeng Zhang static inline bool
1306a508fa23SPeng Zhang nfp_check_multi_pf_from_fw(uint32_t total_vnics)
1307a508fa23SPeng Zhang {
1308a508fa23SPeng Zhang 	if (total_vnics == 1)
1309a508fa23SPeng Zhang 		return true;
1310a508fa23SPeng Zhang 
1311a508fa23SPeng Zhang 	return false;
1312a508fa23SPeng Zhang }
1313a508fa23SPeng Zhang 
1314a508fa23SPeng Zhang static inline bool
13158ad2cc8fSPeng Zhang nfp_check_multi_pf_from_nsp(struct rte_pci_device *pci_dev,
13168ad2cc8fSPeng Zhang 		struct nfp_cpp *cpp)
13178ad2cc8fSPeng Zhang {
13188ad2cc8fSPeng Zhang 	bool flag;
13198ad2cc8fSPeng Zhang 	struct nfp_nsp *nsp;
13208ad2cc8fSPeng Zhang 
13218ad2cc8fSPeng Zhang 	nsp = nfp_nsp_open(cpp);
13228ad2cc8fSPeng Zhang 	if (nsp == NULL) {
13238ad2cc8fSPeng Zhang 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle");
13248ad2cc8fSPeng Zhang 		return false;
13258ad2cc8fSPeng Zhang 	}
13268ad2cc8fSPeng Zhang 
13278ad2cc8fSPeng Zhang 	flag = (nfp_nsp_get_abi_ver_major(nsp) > 0) &&
13288ad2cc8fSPeng Zhang 			(pci_dev->id.device_id == PCI_DEVICE_ID_NFP3800_PF_NIC);
13298ad2cc8fSPeng Zhang 
13308ad2cc8fSPeng Zhang 	nfp_nsp_close(nsp);
13318ad2cc8fSPeng Zhang 	return flag;
13328ad2cc8fSPeng Zhang }
13338ad2cc8fSPeng Zhang 
1334a6189a67SJin Liu static int
133595f978efSPeng Zhang nfp_enable_multi_pf(struct nfp_pf_dev *pf_dev)
133695f978efSPeng Zhang {
133795f978efSPeng Zhang 	int err = 0;
133895f978efSPeng Zhang 	uint64_t tx_base;
133995f978efSPeng Zhang 	uint8_t *ctrl_bar;
134095f978efSPeng Zhang 	struct nfp_hw *hw;
134195f978efSPeng Zhang 	uint32_t cap_extend;
134295f978efSPeng Zhang 	struct nfp_net_hw net_hw;
134395f978efSPeng Zhang 	struct nfp_cpp_area *area;
134495f978efSPeng Zhang 	char name[RTE_ETH_NAME_MAX_LEN];
134595f978efSPeng Zhang 
134695f978efSPeng Zhang 	memset(&net_hw, 0, sizeof(struct nfp_net_hw));
134795f978efSPeng Zhang 
134895f978efSPeng Zhang 	/* Map the symbol table */
134995f978efSPeng Zhang 	snprintf(name, sizeof(name), "_pf%u_net_bar0",
135095f978efSPeng Zhang 			pf_dev->multi_pf.function_id);
135195f978efSPeng Zhang 	ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, name, NFP_NET_CFG_BAR_SZ,
135295f978efSPeng Zhang 			&area);
135395f978efSPeng Zhang 	if (ctrl_bar == NULL) {
135495f978efSPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to find data vNIC memory symbol");
135595f978efSPeng Zhang 		return -ENODEV;
135695f978efSPeng Zhang 	}
135795f978efSPeng Zhang 
135895f978efSPeng Zhang 	hw = &net_hw.super;
135995f978efSPeng Zhang 	hw->ctrl_bar = ctrl_bar;
136095f978efSPeng Zhang 
136195f978efSPeng Zhang 	cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
136295f978efSPeng Zhang 	if ((cap_extend & NFP_NET_CFG_CTRL_MULTI_PF) == 0) {
136395f978efSPeng Zhang 		PMD_INIT_LOG(ERR, "Loaded firmware doesn't support multiple PF");
136495f978efSPeng Zhang 		err = -EINVAL;
136595f978efSPeng Zhang 		goto end;
136695f978efSPeng Zhang 	}
136795f978efSPeng Zhang 
136895f978efSPeng Zhang 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
136995f978efSPeng Zhang 	net_hw.tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
137095f978efSPeng Zhang 	nfp_net_cfg_queue_setup(&net_hw);
137195f978efSPeng Zhang 	rte_spinlock_init(&hw->reconfig_lock);
137295f978efSPeng Zhang 	nfp_ext_reconfig(&net_hw.super, NFP_NET_CFG_CTRL_MULTI_PF, NFP_NET_CFG_UPDATE_GEN);
137395f978efSPeng Zhang end:
137495f978efSPeng Zhang 	nfp_cpp_area_release_free(area);
137595f978efSPeng Zhang 	return err;
137695f978efSPeng Zhang }
137795f978efSPeng Zhang 
137895f978efSPeng Zhang static int
13790314a8ffSChaoyong He nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev,
13800314a8ffSChaoyong He 		const struct nfp_dev_info *dev_info)
1381646ea79cSHeinrich Kuhn {
13828ceb85c3SChaoyong He 	uint8_t i;
13833b00109dSPeng Zhang 	uint8_t id;
1384e7978635SChaoyong He 	int ret = 0;
13858ceb85c3SChaoyong He 	uint32_t total_vnics;
1386646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
1387968ec1c3SChaoyong He 	unsigned int numa_node;
1388646ea79cSHeinrich Kuhn 	struct rte_eth_dev *eth_dev;
1389968ec1c3SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
1390a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
13913b00109dSPeng Zhang 	char bar_name[RTE_ETH_NAME_MAX_LEN];
1392646ea79cSHeinrich Kuhn 	char port_name[RTE_ETH_NAME_MAX_LEN];
13933b00109dSPeng Zhang 	char vnic_name[RTE_ETH_NAME_MAX_LEN];
1394646ea79cSHeinrich Kuhn 
1395968ec1c3SChaoyong He 	nfp_eth_table = pf_dev->nfp_eth_table;
1396968ec1c3SChaoyong He 	PMD_INIT_LOG(INFO, "Total physical ports: %d", nfp_eth_table->count);
13973b00109dSPeng Zhang 	id = nfp_function_id_get(pf_dev, 0);
1398968ec1c3SChaoyong He 
1399968ec1c3SChaoyong He 	/* Allocate memory for the CoreNIC app */
1400968ec1c3SChaoyong He 	app_fw_nic = rte_zmalloc("nfp_app_fw_nic", sizeof(*app_fw_nic), 0);
1401968ec1c3SChaoyong He 	if (app_fw_nic == NULL)
1402968ec1c3SChaoyong He 		return -ENOMEM;
1403968ec1c3SChaoyong He 
1404968ec1c3SChaoyong He 	/* Point the app_fw_priv pointer in the PF to the coreNIC app */
1405968ec1c3SChaoyong He 	pf_dev->app_fw_priv = app_fw_nic;
1406968ec1c3SChaoyong He 
1407968ec1c3SChaoyong He 	/* Read the number of vNIC's created for the PF */
14083b00109dSPeng Zhang 	snprintf(vnic_name, sizeof(vnic_name), "nfd_cfg_pf%u_num_ports", id);
14093b00109dSPeng Zhang 	total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, vnic_name, &ret);
1410e7978635SChaoyong He 	if (ret != 0 || total_vnics == 0 || total_vnics > 8) {
14113b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "%s symbol with wrong value", vnic_name);
1412968ec1c3SChaoyong He 		ret = -ENODEV;
1413968ec1c3SChaoyong He 		goto app_cleanup;
1414968ec1c3SChaoyong He 	}
1415968ec1c3SChaoyong He 
1416a508fa23SPeng Zhang 	if (pf_dev->multi_pf.enabled) {
1417a508fa23SPeng Zhang 		if (!nfp_check_multi_pf_from_fw(total_vnics)) {
1418a508fa23SPeng Zhang 			PMD_INIT_LOG(ERR, "NSP report multipf, but FW report not multipf");
1419a508fa23SPeng Zhang 			ret = -ENODEV;
1420a508fa23SPeng Zhang 			goto app_cleanup;
1421a508fa23SPeng Zhang 		}
1422a508fa23SPeng Zhang 	} else {
1423968ec1c3SChaoyong He 		/*
1424968ec1c3SChaoyong He 		 * For coreNIC the number of vNICs exposed should be the same as the
142540688372SChaoyong He 		 * number of physical ports.
1426968ec1c3SChaoyong He 		 */
14278ceb85c3SChaoyong He 		if (total_vnics != nfp_eth_table->count) {
1428968ec1c3SChaoyong He 			PMD_INIT_LOG(ERR, "Total physical ports do not match number of vNICs");
1429968ec1c3SChaoyong He 			ret = -ENODEV;
1430968ec1c3SChaoyong He 			goto app_cleanup;
1431968ec1c3SChaoyong He 		}
1432a508fa23SPeng Zhang 	}
1433968ec1c3SChaoyong He 
1434968ec1c3SChaoyong He 	/* Populate coreNIC app properties */
1435968ec1c3SChaoyong He 	app_fw_nic->total_phyports = total_vnics;
1436968ec1c3SChaoyong He 	app_fw_nic->pf_dev = pf_dev;
1437968ec1c3SChaoyong He 	if (total_vnics > 1)
1438968ec1c3SChaoyong He 		app_fw_nic->multiport = true;
1439968ec1c3SChaoyong He 
1440968ec1c3SChaoyong He 	/* Map the symbol table */
14413b00109dSPeng Zhang 	snprintf(bar_name, sizeof(bar_name), "_pf%u_net_bar0", id);
14423b00109dSPeng Zhang 	pf_dev->ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, bar_name,
1443d5e9fc86SChaoyong He 			app_fw_nic->total_phyports * NFP_NET_CFG_BAR_SZ,
1444d5e9fc86SChaoyong He 			&pf_dev->ctrl_area);
1445968ec1c3SChaoyong He 	if (pf_dev->ctrl_bar == NULL) {
14463b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for %s", bar_name);
1447968ec1c3SChaoyong He 		ret = -EIO;
1448968ec1c3SChaoyong He 		goto app_cleanup;
1449968ec1c3SChaoyong He 	}
1450968ec1c3SChaoyong He 
1451968ec1c3SChaoyong He 	PMD_INIT_LOG(DEBUG, "ctrl bar: %p", pf_dev->ctrl_bar);
1452968ec1c3SChaoyong He 
1453968ec1c3SChaoyong He 	/* Loop through all physical ports on PF */
1454968ec1c3SChaoyong He 	numa_node = rte_socket_id();
1455968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
1456c92c83d4SPeng Zhang 		if (pf_dev->multi_pf.enabled)
1457c92c83d4SPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s",
1458c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name);
1459c92c83d4SPeng Zhang 		else
14603b00109dSPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s_port%u",
1461c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name, i);
1462646ea79cSHeinrich Kuhn 
1463646ea79cSHeinrich Kuhn 		/* Allocate a eth_dev for this phyport */
1464646ea79cSHeinrich Kuhn 		eth_dev = rte_eth_dev_allocate(port_name);
1465a6189a67SJin Liu 		if (eth_dev == NULL) {
1466646ea79cSHeinrich Kuhn 			ret = -ENODEV;
1467646ea79cSHeinrich Kuhn 			goto port_cleanup;
1468646ea79cSHeinrich Kuhn 		}
1469646ea79cSHeinrich Kuhn 
1470646ea79cSHeinrich Kuhn 		/* Allocate memory for this phyport */
1471f4d24fe9SChaoyong He 		eth_dev->data->dev_private = rte_zmalloc_socket(port_name,
1472f4d24fe9SChaoyong He 				sizeof(struct nfp_net_hw),
1473646ea79cSHeinrich Kuhn 				RTE_CACHE_LINE_SIZE, numa_node);
1474a6189a67SJin Liu 		if (eth_dev->data->dev_private == NULL) {
1475646ea79cSHeinrich Kuhn 			ret = -ENOMEM;
1476646ea79cSHeinrich Kuhn 			rte_eth_dev_release_port(eth_dev);
1477646ea79cSHeinrich Kuhn 			goto port_cleanup;
1478646ea79cSHeinrich Kuhn 		}
1479646ea79cSHeinrich Kuhn 
14809d723baaSChaoyong He 		hw = eth_dev->data->dev_private;
1481c92c83d4SPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
1482646ea79cSHeinrich Kuhn 
1483646ea79cSHeinrich Kuhn 		/* Add this device to the PF's array of physical ports */
14843b00109dSPeng Zhang 		app_fw_nic->ports[id] = hw;
1485646ea79cSHeinrich Kuhn 
14860314a8ffSChaoyong He 		hw->dev_info = dev_info;
1487646ea79cSHeinrich Kuhn 		hw->pf_dev = pf_dev;
1488646ea79cSHeinrich Kuhn 		hw->cpp = pf_dev->cpp;
1489646ea79cSHeinrich Kuhn 		hw->eth_dev = eth_dev;
14903b00109dSPeng Zhang 		hw->idx = id;
14913b00109dSPeng Zhang 		hw->nfp_idx = nfp_eth_table->ports[id].index;
1492646ea79cSHeinrich Kuhn 
1493646ea79cSHeinrich Kuhn 		eth_dev->device = &pf_dev->pci_dev->device;
1494646ea79cSHeinrich Kuhn 
149540688372SChaoyong He 		/*
149640688372SChaoyong He 		 * Ctrl/tx/rx BAR mappings and remaining init happens in
149740688372SChaoyong He 		 * @nfp_net_init()
1498646ea79cSHeinrich Kuhn 		 */
1499646ea79cSHeinrich Kuhn 		ret = nfp_net_init(eth_dev);
1500c01e5c0cSChaoyong He 		if (ret != 0) {
1501646ea79cSHeinrich Kuhn 			ret = -ENODEV;
1502646ea79cSHeinrich Kuhn 			goto port_cleanup;
1503646ea79cSHeinrich Kuhn 		}
1504646ea79cSHeinrich Kuhn 
1505646ea79cSHeinrich Kuhn 		rte_eth_dev_probing_finish(eth_dev);
1506646ea79cSHeinrich Kuhn 
1507646ea79cSHeinrich Kuhn 	} /* End loop, all ports on this PF */
1508968ec1c3SChaoyong He 
1509968ec1c3SChaoyong He 	return 0;
1510646ea79cSHeinrich Kuhn 
1511646ea79cSHeinrich Kuhn port_cleanup:
1512968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
15133b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
15148153bc6fSChaoyong He 		hw = app_fw_nic->ports[id];
15153b00109dSPeng Zhang 
15168153bc6fSChaoyong He 		if (hw != NULL && hw->eth_dev != NULL) {
15178153bc6fSChaoyong He 			nfp_net_uninit(hw->eth_dev);
15188153bc6fSChaoyong He 			rte_eth_dev_release_port(hw->eth_dev);
1519646ea79cSHeinrich Kuhn 		}
1520646ea79cSHeinrich Kuhn 	}
15218b8f116bSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
1522968ec1c3SChaoyong He app_cleanup:
1523968ec1c3SChaoyong He 	rte_free(app_fw_nic);
1524a6189a67SJin Liu 
1525646ea79cSHeinrich Kuhn 	return ret;
1526646ea79cSHeinrich Kuhn }
1527646ea79cSHeinrich Kuhn 
1528a6189a67SJin Liu static int
1529c7a6970fSZerun Fu nfp_net_hwinfo_set(uint8_t function_id,
1530c7a6970fSZerun Fu 		struct nfp_rtsym_table *sym_tbl,
1531c7a6970fSZerun Fu 		struct nfp_cpp *cpp)
1532c7a6970fSZerun Fu {
1533c7a6970fSZerun Fu 	int ret = 0;
1534c7a6970fSZerun Fu 	uint64_t app_cap;
1535c7a6970fSZerun Fu 	uint8_t sp_indiff;
1536c7a6970fSZerun Fu 	struct nfp_nsp *nsp;
1537c7a6970fSZerun Fu 	char hw_info[RTE_ETH_NAME_MAX_LEN];
1538c7a6970fSZerun Fu 	char app_cap_name[RTE_ETH_NAME_MAX_LEN];
1539c7a6970fSZerun Fu 
1540c7a6970fSZerun Fu 	/* Read the app capabilities of the firmware loaded */
1541c7a6970fSZerun Fu 	snprintf(app_cap_name, sizeof(app_cap_name), "_pf%u_net_app_cap", function_id);
1542c7a6970fSZerun Fu 	app_cap = nfp_rtsym_read_le(sym_tbl, app_cap_name, &ret);
1543c7a6970fSZerun Fu 	if (ret != 0) {
1544c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Couldn't read app_fw_cap from firmware.");
1545c7a6970fSZerun Fu 		return ret;
1546c7a6970fSZerun Fu 	}
1547c7a6970fSZerun Fu 
1548c7a6970fSZerun Fu 	/* Calculate the value of sp_indiff and write to hw_info */
1549c7a6970fSZerun Fu 	sp_indiff = app_cap & NFP_NET_APP_CAP_SP_INDIFF;
1550c7a6970fSZerun Fu 	snprintf(hw_info, sizeof(hw_info), "sp_indiff=%u", sp_indiff);
1551c7a6970fSZerun Fu 
1552c7a6970fSZerun Fu 	nsp = nfp_nsp_open(cpp);
1553c7a6970fSZerun Fu 	if (nsp == NULL) {
1554c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Couldn't get NSP.");
1555c7a6970fSZerun Fu 		return -EIO;
1556c7a6970fSZerun Fu 	}
1557c7a6970fSZerun Fu 
1558c7a6970fSZerun Fu 	ret = nfp_nsp_hwinfo_set(nsp, hw_info, sizeof(hw_info));
1559c7a6970fSZerun Fu 	nfp_nsp_close(nsp);
1560c7a6970fSZerun Fu 	if (ret != 0) {
1561c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set parameter to hwinfo.");
1562c7a6970fSZerun Fu 		return ret;
1563c7a6970fSZerun Fu 	}
1564c7a6970fSZerun Fu 
1565c7a6970fSZerun Fu 	return 0;
1566c7a6970fSZerun Fu }
1567c7a6970fSZerun Fu 
15683110ab73SZerun Fu const uint32_t nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
15693110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M]     = RTE_ETH_LINK_SPEED_10M,
15703110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M_HD]  = RTE_ETH_LINK_SPEED_10M_HD,
15713110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M]    = RTE_ETH_LINK_SPEED_100M,
15723110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M_HD] = RTE_ETH_LINK_SPEED_100M_HD,
15733110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_1G]      = RTE_ETH_LINK_SPEED_1G,
15743110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_2P5G]    = RTE_ETH_LINK_SPEED_2_5G,
15753110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_5G]      = RTE_ETH_LINK_SPEED_5G,
15763110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10G]     = RTE_ETH_LINK_SPEED_10G,
15773110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_CX]     = RTE_ETH_LINK_SPEED_1G,
15783110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_KX]     = RTE_ETH_LINK_SPEED_1G,
15793110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KX4]     = RTE_ETH_LINK_SPEED_10G,
15803110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KR]      = RTE_ETH_LINK_SPEED_10G,
15813110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CX4]     = RTE_ETH_LINK_SPEED_10G,
15823110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CR]      = RTE_ETH_LINK_SPEED_10G,
15833110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_SR]      = RTE_ETH_LINK_SPEED_10G,
15843110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_ER]      = RTE_ETH_LINK_SPEED_10G,
15853110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR]      = RTE_ETH_LINK_SPEED_25G,
15863110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR_S]    = RTE_ETH_LINK_SPEED_25G,
15873110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR]      = RTE_ETH_LINK_SPEED_25G,
15883110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR_S]    = RTE_ETH_LINK_SPEED_25G,
15893110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_SR]      = RTE_ETH_LINK_SPEED_25G,
15903110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_CR4]     = RTE_ETH_LINK_SPEED_40G,
15913110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_KR4]     = RTE_ETH_LINK_SPEED_40G,
15923110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_SR4]     = RTE_ETH_LINK_SPEED_40G,
15933110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_LR4]     = RTE_ETH_LINK_SPEED_40G,
15943110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_KR]      = RTE_ETH_LINK_SPEED_50G,
15953110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_SR]      = RTE_ETH_LINK_SPEED_50G,
15963110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_CR]      = RTE_ETH_LINK_SPEED_50G,
15973110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_LR]      = RTE_ETH_LINK_SPEED_50G,
15983110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_ER]      = RTE_ETH_LINK_SPEED_50G,
15993110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_FR]      = RTE_ETH_LINK_SPEED_50G,
16003110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KR4]    = RTE_ETH_LINK_SPEED_100G,
16013110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_SR4]    = RTE_ETH_LINK_SPEED_100G,
16023110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR4]    = RTE_ETH_LINK_SPEED_100G,
16033110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KP4]    = RTE_ETH_LINK_SPEED_100G,
16043110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR10]   = RTE_ETH_LINK_SPEED_100G,
16053110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_LR]      = RTE_ETH_LINK_SPEED_10G,
16063110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_LR]      = RTE_ETH_LINK_SPEED_25G,
16073110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_ER]      = RTE_ETH_LINK_SPEED_25G
16083110ab73SZerun Fu };
16093110ab73SZerun Fu 
16103110ab73SZerun Fu static int
16113110ab73SZerun Fu nfp_net_speed_capa_get_real(struct nfp_eth_media_buf *media_buf,
16123110ab73SZerun Fu 		struct nfp_pf_dev *pf_dev)
16133110ab73SZerun Fu {
16143110ab73SZerun Fu 	uint32_t i;
16153110ab73SZerun Fu 	uint32_t j;
16163110ab73SZerun Fu 	uint32_t offset;
16173110ab73SZerun Fu 	uint32_t speed_capa = 0;
16183110ab73SZerun Fu 	uint64_t supported_modes;
16193110ab73SZerun Fu 
16203110ab73SZerun Fu 	for (i = 0; i < RTE_DIM(media_buf->supported_modes); i++) {
16213110ab73SZerun Fu 		supported_modes = media_buf->supported_modes[i];
16223110ab73SZerun Fu 		offset = i * UINT64_BIT;
16233110ab73SZerun Fu 		for (j = 0; j < UINT64_BIT; j++) {
16243110ab73SZerun Fu 			if (supported_modes == 0)
16253110ab73SZerun Fu 				break;
16263110ab73SZerun Fu 
16273110ab73SZerun Fu 			if ((supported_modes & 1) != 0) {
16283110ab73SZerun Fu 				if ((j + offset) >= NFP_MEDIA_LINK_MODES_NUMBER) {
16293110ab73SZerun Fu 					PMD_DRV_LOG(ERR, "Invalid offset of media table.");
16303110ab73SZerun Fu 					return -EINVAL;
16313110ab73SZerun Fu 				}
16323110ab73SZerun Fu 
16333110ab73SZerun Fu 				speed_capa |= nfp_eth_media_table[j + offset];
16343110ab73SZerun Fu 			}
16353110ab73SZerun Fu 
16363110ab73SZerun Fu 			supported_modes = supported_modes >> 1;
16373110ab73SZerun Fu 		}
16383110ab73SZerun Fu 	}
16393110ab73SZerun Fu 
16403110ab73SZerun Fu 	pf_dev->speed_capa = speed_capa;
16413110ab73SZerun Fu 
16423110ab73SZerun Fu 	return pf_dev->speed_capa == 0 ? -EINVAL : 0;
16433110ab73SZerun Fu }
16443110ab73SZerun Fu 
16453110ab73SZerun Fu static int
16463110ab73SZerun Fu nfp_net_speed_capa_get(struct nfp_pf_dev *pf_dev,
16473110ab73SZerun Fu 		uint32_t port_id)
16483110ab73SZerun Fu {
16493110ab73SZerun Fu 	int ret;
16503110ab73SZerun Fu 	struct nfp_nsp *nsp;
16513110ab73SZerun Fu 	struct nfp_eth_media_buf media_buf;
16523110ab73SZerun Fu 
16533110ab73SZerun Fu 	media_buf.eth_index = pf_dev->nfp_eth_table->ports[port_id].eth_index;
16543110ab73SZerun Fu 	pf_dev->speed_capa = 0;
16553110ab73SZerun Fu 
16563110ab73SZerun Fu 	nsp = nfp_nsp_open(pf_dev->cpp);
16573110ab73SZerun Fu 	if (nsp == NULL) {
16583110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Couldn't get NSP.");
16593110ab73SZerun Fu 		return -EIO;
16603110ab73SZerun Fu 	}
16613110ab73SZerun Fu 
16623110ab73SZerun Fu 	ret = nfp_nsp_read_media(nsp, &media_buf, sizeof(media_buf));
16633110ab73SZerun Fu 	nfp_nsp_close(nsp);
16643110ab73SZerun Fu 	if (ret != 0) {
16653110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to read media.");
16663110ab73SZerun Fu 		return ret;
16673110ab73SZerun Fu 	}
16683110ab73SZerun Fu 
16693110ab73SZerun Fu 	ret = nfp_net_speed_capa_get_real(&media_buf, pf_dev);
16703110ab73SZerun Fu 	if (ret < 0) {
16713110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Speed capability is invalid.");
16723110ab73SZerun Fu 		return ret;
16733110ab73SZerun Fu 	}
16743110ab73SZerun Fu 
16753110ab73SZerun Fu 	return 0;
16763110ab73SZerun Fu }
16773110ab73SZerun Fu 
1678c7a6970fSZerun Fu static int
1679a6189a67SJin Liu nfp_pf_init(struct rte_pci_device *pci_dev)
1680646ea79cSHeinrich Kuhn {
16816b4273a0SLong Wu 	void *sync;
16829e442599SShihong Wang 	uint32_t i;
16833b00109dSPeng Zhang 	uint32_t id;
1684e7978635SChaoyong He 	int ret = 0;
16855c464d6aSJin Liu 	uint64_t addr;
16863b00109dSPeng Zhang 	uint32_t index;
1687925c27ecSChaoyong He 	uint32_t cpp_id;
16883b00109dSPeng Zhang 	uint8_t function_id;
1689a6189a67SJin Liu 	struct nfp_cpp *cpp;
1690a6189a67SJin Liu 	struct nfp_pf_dev *pf_dev;
1691a6189a67SJin Liu 	struct nfp_hwinfo *hwinfo;
169249952141SChaoyong He 	enum nfp_app_fw_id app_fw_id;
1693a6189a67SJin Liu 	char name[RTE_ETH_NAME_MAX_LEN];
1694a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
16953b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
1696a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
16970314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
1698646ea79cSHeinrich Kuhn 
1699a6189a67SJin Liu 	if (pci_dev == NULL)
1700a6189a67SJin Liu 		return -ENODEV;
1701646ea79cSHeinrich Kuhn 
170284aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
170384aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
170484aaba5aSChaoyong He 		return -ENODEV;
170584aaba5aSChaoyong He 	}
170684aaba5aSChaoyong He 
17070314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
17080314a8ffSChaoyong He 	if (dev_info == NULL) {
17090314a8ffSChaoyong He 		PMD_INIT_LOG(ERR, "Not supported device ID");
17100314a8ffSChaoyong He 		return -ENODEV;
17110314a8ffSChaoyong He 	}
17120314a8ffSChaoyong He 
17138ad2cc8fSPeng Zhang 	/* Allocate memory for the PF "device" */
17143b00109dSPeng Zhang 	function_id = (pci_dev->addr.function) & 0x07;
17153b00109dSPeng Zhang 	snprintf(name, sizeof(name), "nfp_pf%u", function_id);
17168ad2cc8fSPeng Zhang 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
17178ad2cc8fSPeng Zhang 	if (pf_dev == NULL) {
17188ad2cc8fSPeng Zhang 		PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device");
17198ad2cc8fSPeng Zhang 		return -ENOMEM;
17208ad2cc8fSPeng Zhang 	}
17218ad2cc8fSPeng Zhang 
17226b4273a0SLong Wu 	sync = nfp_sync_alloc();
17236b4273a0SLong Wu 	if (sync == NULL) {
17246b4273a0SLong Wu 		PMD_INIT_LOG(ERR, "Failed to alloc sync zone.");
17256b4273a0SLong Wu 		ret = -ENOMEM;
17266b4273a0SLong Wu 		goto pf_cleanup;
17276b4273a0SLong Wu 	}
17286b4273a0SLong Wu 
1729646ea79cSHeinrich Kuhn 	/*
1730646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
1731646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
1732646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
1733646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
1734646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
1735646ea79cSHeinrich Kuhn 	 */
1736646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
17371fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
1738646ea79cSHeinrich Kuhn 	else
17391fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
1740646ea79cSHeinrich Kuhn 
1741a6189a67SJin Liu 	if (cpp == NULL) {
1742646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
17438ad2cc8fSPeng Zhang 		ret = -EIO;
17446b4273a0SLong Wu 		goto sync_free;
1745646ea79cSHeinrich Kuhn 	}
1746646ea79cSHeinrich Kuhn 
1747646ea79cSHeinrich Kuhn 	hwinfo = nfp_hwinfo_read(cpp);
1748a6189a67SJin Liu 	if (hwinfo == NULL) {
1749646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error reading hwinfo table");
1750646ea79cSHeinrich Kuhn 		ret = -EIO;
1751968ec1c3SChaoyong He 		goto cpp_cleanup;
1752646ea79cSHeinrich Kuhn 	}
1753646ea79cSHeinrich Kuhn 
1754968ec1c3SChaoyong He 	/* Read the number of physical ports from hardware */
1755646ea79cSHeinrich Kuhn 	nfp_eth_table = nfp_eth_read_ports(cpp);
1756a6189a67SJin Liu 	if (nfp_eth_table == NULL) {
1757646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error reading NFP ethernet table");
1758646ea79cSHeinrich Kuhn 		ret = -EIO;
1759646ea79cSHeinrich Kuhn 		goto hwinfo_cleanup;
1760646ea79cSHeinrich Kuhn 	}
1761646ea79cSHeinrich Kuhn 
17628ad2cc8fSPeng Zhang 	pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_nsp(pci_dev, cpp);
17633b00109dSPeng Zhang 	pf_dev->multi_pf.function_id = function_id;
17648ad2cc8fSPeng Zhang 
17659e442599SShihong Wang 	/* Force the physical port down to clear the possible DMA error */
17663b00109dSPeng Zhang 	for (i = 0; i < nfp_eth_table->count; i++) {
17673b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
17683b00109dSPeng Zhang 		index = nfp_eth_table->ports[id].index;
17693b00109dSPeng Zhang 		nfp_eth_set_configured(cpp, index, 0);
17703b00109dSPeng Zhang 	}
17719e442599SShihong Wang 
17728ba461d1SPeng Zhang 	if (nfp_fw_setup(pci_dev, cpp, nfp_eth_table, hwinfo,
17738ba461d1SPeng Zhang 			dev_info, &pf_dev->multi_pf) != 0) {
1774646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error when uploading firmware");
1775646ea79cSHeinrich Kuhn 		ret = -EIO;
1776646ea79cSHeinrich Kuhn 		goto eth_table_cleanup;
1777646ea79cSHeinrich Kuhn 	}
1778646ea79cSHeinrich Kuhn 
1779646ea79cSHeinrich Kuhn 	/* Now the symbol table should be there */
1780646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
1781a6189a67SJin Liu 	if (sym_tbl == NULL) {
1782f4d24fe9SChaoyong He 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table");
1783646ea79cSHeinrich Kuhn 		ret = -EIO;
17843b00109dSPeng Zhang 		goto fw_cleanup;
1785646ea79cSHeinrich Kuhn 	}
1786646ea79cSHeinrich Kuhn 
1787968ec1c3SChaoyong He 	/* Read the app ID of the firmware loaded */
17883b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
17893b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
1790e7978635SChaoyong He 	if (ret != 0) {
17913b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "Couldn't read %s from firmware", app_name);
1792646ea79cSHeinrich Kuhn 		ret = -EIO;
1793646ea79cSHeinrich Kuhn 		goto sym_tbl_cleanup;
1794646ea79cSHeinrich Kuhn 	}
1795646ea79cSHeinrich Kuhn 
1796c7a6970fSZerun Fu 	/* Write sp_indiff to hw_info */
1797c7a6970fSZerun Fu 	ret = nfp_net_hwinfo_set(function_id, sym_tbl, cpp);
1798c7a6970fSZerun Fu 	if (ret != 0) {
1799c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set hwinfo.");
1800c7a6970fSZerun Fu 		ret = -EIO;
1801c7a6970fSZerun Fu 		goto sym_tbl_cleanup;
1802c7a6970fSZerun Fu 	}
1803c7a6970fSZerun Fu 
1804646ea79cSHeinrich Kuhn 	/* Populate the newly created PF device */
1805968ec1c3SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
1806646ea79cSHeinrich Kuhn 	pf_dev->cpp = cpp;
1807646ea79cSHeinrich Kuhn 	pf_dev->hwinfo = hwinfo;
1808646ea79cSHeinrich Kuhn 	pf_dev->sym_tbl = sym_tbl;
1809646ea79cSHeinrich Kuhn 	pf_dev->pci_dev = pci_dev;
1810968ec1c3SChaoyong He 	pf_dev->nfp_eth_table = nfp_eth_table;
18116b4273a0SLong Wu 	pf_dev->sync = sync;
1812646ea79cSHeinrich Kuhn 
18133110ab73SZerun Fu 	/* Get the speed capability */
18143110ab73SZerun Fu 	for (i = 0; i < nfp_eth_table->count; i++) {
18153110ab73SZerun Fu 		id = nfp_function_id_get(pf_dev, i);
18163110ab73SZerun Fu 		ret = nfp_net_speed_capa_get(pf_dev, id);
18173110ab73SZerun Fu 		if (ret != 0) {
18183110ab73SZerun Fu 			PMD_INIT_LOG(ERR, "Failed to get speed capability.");
18193110ab73SZerun Fu 			ret = -EIO;
18203110ab73SZerun Fu 			goto sym_tbl_cleanup;
18213110ab73SZerun Fu 		}
18223110ab73SZerun Fu 	}
18233110ab73SZerun Fu 
182440688372SChaoyong He 	/* Configure access to tx/rx vNIC BARs */
18250314a8ffSChaoyong He 	addr = nfp_qcp_queue_offset(dev_info, 0);
1826925c27ecSChaoyong He 	cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0);
18270314a8ffSChaoyong He 
1828711e4559SChaoyong He 	pf_dev->qc_bar = nfp_cpp_map_area(pf_dev->cpp, cpp_id,
18290314a8ffSChaoyong He 			addr, dev_info->qc_area_sz, &pf_dev->qc_area);
1830711e4559SChaoyong He 	if (pf_dev->qc_bar == NULL) {
1831646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for net.qc");
1832646ea79cSHeinrich Kuhn 		ret = -EIO;
18338ad2cc8fSPeng Zhang 		goto sym_tbl_cleanup;
1834646ea79cSHeinrich Kuhn 	}
1835646ea79cSHeinrich Kuhn 
1836030b2b19SChaoyong He 	PMD_INIT_LOG(DEBUG, "qc_bar address: %p", pf_dev->qc_bar);
1837646ea79cSHeinrich Kuhn 
1838a6189a67SJin Liu 	/*
1839968ec1c3SChaoyong He 	 * PF initialization has been done at this point. Call app specific
184040688372SChaoyong He 	 * init code now.
1841646ea79cSHeinrich Kuhn 	 */
1842968ec1c3SChaoyong He 	switch (pf_dev->app_fw_id) {
1843968ec1c3SChaoyong He 	case NFP_APP_FW_CORE_NIC:
184495f978efSPeng Zhang 		if (pf_dev->multi_pf.enabled) {
184595f978efSPeng Zhang 			ret = nfp_enable_multi_pf(pf_dev);
184695f978efSPeng Zhang 			if (ret != 0)
184795f978efSPeng Zhang 				goto hwqueues_cleanup;
184895f978efSPeng Zhang 		}
184995f978efSPeng Zhang 
1850968ec1c3SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing coreNIC");
18510314a8ffSChaoyong He 		ret = nfp_init_app_fw_nic(pf_dev, dev_info);
1852968ec1c3SChaoyong He 		if (ret != 0) {
1853968ec1c3SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
1854968ec1c3SChaoyong He 			goto hwqueues_cleanup;
1855968ec1c3SChaoyong He 		}
1856968ec1c3SChaoyong He 		break;
1857b1880421SChaoyong He 	case NFP_APP_FW_FLOWER_NIC:
1858b1880421SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing Flower");
18590314a8ffSChaoyong He 		ret = nfp_init_app_fw_flower(pf_dev, dev_info);
1860b1880421SChaoyong He 		if (ret != 0) {
1861b1880421SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
1862b1880421SChaoyong He 			goto hwqueues_cleanup;
1863b1880421SChaoyong He 		}
1864b1880421SChaoyong He 		break;
1865968ec1c3SChaoyong He 	default:
1866968ec1c3SChaoyong He 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded");
1867968ec1c3SChaoyong He 		ret = -EINVAL;
1868646ea79cSHeinrich Kuhn 		goto hwqueues_cleanup;
1869646ea79cSHeinrich Kuhn 	}
1870646ea79cSHeinrich Kuhn 
187140688372SChaoyong He 	/* Register the CPP bridge service here for primary use */
1872bab0e6f4SChaoyong He 	ret = nfp_enable_cpp_service(pf_dev);
1873dee23e6cSChaoyong He 	if (ret != 0)
1874dee23e6cSChaoyong He 		PMD_INIT_LOG(INFO, "Enable cpp service failed.");
1875646ea79cSHeinrich Kuhn 
1876646ea79cSHeinrich Kuhn 	return 0;
1877646ea79cSHeinrich Kuhn 
1878646ea79cSHeinrich Kuhn hwqueues_cleanup:
1879528812a6SChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
1880646ea79cSHeinrich Kuhn sym_tbl_cleanup:
1881646ea79cSHeinrich Kuhn 	free(sym_tbl);
18823b00109dSPeng Zhang fw_cleanup:
18833b00109dSPeng Zhang 	nfp_fw_unload(cpp);
18848ba461d1SPeng Zhang 	nfp_net_keepalive_stop(&pf_dev->multi_pf);
1885b67a7b40SPeng Zhang 	nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
1886528812a6SChaoyong He 	nfp_net_keepalive_uninit(&pf_dev->multi_pf);
1887646ea79cSHeinrich Kuhn eth_table_cleanup:
1888646ea79cSHeinrich Kuhn 	free(nfp_eth_table);
1889646ea79cSHeinrich Kuhn hwinfo_cleanup:
1890646ea79cSHeinrich Kuhn 	free(hwinfo);
1891968ec1c3SChaoyong He cpp_cleanup:
1892968ec1c3SChaoyong He 	nfp_cpp_free(cpp);
18936b4273a0SLong Wu sync_free:
18946b4273a0SLong Wu 	nfp_sync_free(sync);
18958ad2cc8fSPeng Zhang pf_cleanup:
18968ad2cc8fSPeng Zhang 	rte_free(pf_dev);
18977feb8909SChaoyong He 
1898646ea79cSHeinrich Kuhn 	return ret;
1899646ea79cSHeinrich Kuhn }
1900646ea79cSHeinrich Kuhn 
1901d5f39e07SChaoyong He static int
1902016141b1SChaoyong He nfp_secondary_init_app_fw_nic(struct nfp_pf_dev *pf_dev)
1903d5f39e07SChaoyong He {
19048ceb85c3SChaoyong He 	uint32_t i;
1905d5f39e07SChaoyong He 	int err = 0;
1906d5f39e07SChaoyong He 	int ret = 0;
19073b00109dSPeng Zhang 	uint8_t function_id;
19088ceb85c3SChaoyong He 	uint32_t total_vnics;
1909d5f39e07SChaoyong He 	struct nfp_net_hw *hw;
19103b00109dSPeng Zhang 	char pf_name[RTE_ETH_NAME_MAX_LEN];
1911d5f39e07SChaoyong He 
1912d5f39e07SChaoyong He 	/* Read the number of vNIC's created for the PF */
19133b00109dSPeng Zhang 	function_id = (pf_dev->pci_dev->addr.function) & 0x07;
19143b00109dSPeng Zhang 	snprintf(pf_name, sizeof(pf_name), "nfd_cfg_pf%u_num_ports", function_id);
19153b00109dSPeng Zhang 	total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, pf_name, &err);
19168ceb85c3SChaoyong He 	if (err != 0 || total_vnics == 0 || total_vnics > 8) {
19173b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "%s symbol with wrong value", pf_name);
1918d5f39e07SChaoyong He 		return -ENODEV;
1919d5f39e07SChaoyong He 	}
1920d5f39e07SChaoyong He 
1921d5f39e07SChaoyong He 	for (i = 0; i < total_vnics; i++) {
1922d5f39e07SChaoyong He 		struct rte_eth_dev *eth_dev;
1923d5f39e07SChaoyong He 		char port_name[RTE_ETH_NAME_MAX_LEN];
19243b00109dSPeng Zhang 
19253b00109dSPeng Zhang 		if (nfp_check_multi_pf_from_fw(total_vnics))
1926c92c83d4SPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s",
1927c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name);
1928c92c83d4SPeng Zhang 		else
19298ceb85c3SChaoyong He 			snprintf(port_name, sizeof(port_name), "%s_port%u",
1930c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name, i);
1931d5f39e07SChaoyong He 
1932d5f39e07SChaoyong He 		PMD_INIT_LOG(DEBUG, "Secondary attaching to port %s", port_name);
1933d5f39e07SChaoyong He 		eth_dev = rte_eth_dev_attach_secondary(port_name);
1934d5f39e07SChaoyong He 		if (eth_dev == NULL) {
1935d5f39e07SChaoyong He 			PMD_INIT_LOG(ERR, "Secondary process attach to port %s failed", port_name);
1936d5f39e07SChaoyong He 			ret = -ENODEV;
1937d5f39e07SChaoyong He 			break;
1938d5f39e07SChaoyong He 		}
1939d5f39e07SChaoyong He 
1940acb6bebfSChaoyong He 		eth_dev->process_private = pf_dev;
19419d723baaSChaoyong He 		hw = eth_dev->data->dev_private;
1942ee8ca64eSChaoyong He 		nfp_net_ethdev_ops_mount(hw, eth_dev);
1943d5f39e07SChaoyong He 
1944d5f39e07SChaoyong He 		rte_eth_dev_probing_finish(eth_dev);
1945d5f39e07SChaoyong He 	}
1946d5f39e07SChaoyong He 
1947d5f39e07SChaoyong He 	return ret;
1948d5f39e07SChaoyong He }
1949d5f39e07SChaoyong He 
1950646ea79cSHeinrich Kuhn /*
1951646ea79cSHeinrich Kuhn  * When attaching to the NFP4000/6000 PF on a secondary process there
1952646ea79cSHeinrich Kuhn  * is no need to initialise the PF again. Only minimal work is required
195340688372SChaoyong He  * here.
1954646ea79cSHeinrich Kuhn  */
1955a6189a67SJin Liu static int
1956a6189a67SJin Liu nfp_pf_secondary_init(struct rte_pci_device *pci_dev)
1957646ea79cSHeinrich Kuhn {
19586b4273a0SLong Wu 	void *sync;
1959968ec1c3SChaoyong He 	int ret = 0;
1960a6189a67SJin Liu 	struct nfp_cpp *cpp;
19613b00109dSPeng Zhang 	uint8_t function_id;
1962016141b1SChaoyong He 	struct nfp_pf_dev *pf_dev;
1963d5f39e07SChaoyong He 	enum nfp_app_fw_id app_fw_id;
1964016141b1SChaoyong He 	char name[RTE_ETH_NAME_MAX_LEN];
1965a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
19660314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
19673b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
1968646ea79cSHeinrich Kuhn 
1969a6189a67SJin Liu 	if (pci_dev == NULL)
1970646ea79cSHeinrich Kuhn 		return -ENODEV;
1971646ea79cSHeinrich Kuhn 
197284aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
197384aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
197484aaba5aSChaoyong He 		return -ENODEV;
197584aaba5aSChaoyong He 	}
197684aaba5aSChaoyong He 
19770314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
19780314a8ffSChaoyong He 	if (dev_info == NULL) {
19790314a8ffSChaoyong He 		PMD_INIT_LOG(ERR, "Not supported device ID");
19800314a8ffSChaoyong He 		return -ENODEV;
19810314a8ffSChaoyong He 	}
19820314a8ffSChaoyong He 
1983016141b1SChaoyong He 	/* Allocate memory for the PF "device" */
1984016141b1SChaoyong He 	snprintf(name, sizeof(name), "nfp_pf%d", 0);
1985016141b1SChaoyong He 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
1986016141b1SChaoyong He 	if (pf_dev == NULL) {
1987016141b1SChaoyong He 		PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device");
1988016141b1SChaoyong He 		return -ENOMEM;
1989016141b1SChaoyong He 	}
1990016141b1SChaoyong He 
19916b4273a0SLong Wu 	sync = nfp_sync_alloc();
19926b4273a0SLong Wu 	if (sync == NULL) {
19936b4273a0SLong Wu 		PMD_INIT_LOG(ERR, "Failed to alloc sync zone.");
19946b4273a0SLong Wu 		ret = -ENOMEM;
19956b4273a0SLong Wu 		goto pf_cleanup;
19966b4273a0SLong Wu 	}
19976b4273a0SLong Wu 
1998646ea79cSHeinrich Kuhn 	/*
1999646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
2000646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
2001646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
2002646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
2003646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
2004646ea79cSHeinrich Kuhn 	 */
2005646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
20061fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
2007646ea79cSHeinrich Kuhn 	else
20081fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
2009646ea79cSHeinrich Kuhn 
2010a6189a67SJin Liu 	if (cpp == NULL) {
2011646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
2012016141b1SChaoyong He 		ret = -EIO;
20136b4273a0SLong Wu 		goto sync_free;
2014646ea79cSHeinrich Kuhn 	}
2015646ea79cSHeinrich Kuhn 
2016646ea79cSHeinrich Kuhn 	/*
2017646ea79cSHeinrich Kuhn 	 * We don't have access to the PF created in the primary process
201840688372SChaoyong He 	 * here so we have to read the number of ports from firmware.
2019646ea79cSHeinrich Kuhn 	 */
2020646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
2021a6189a67SJin Liu 	if (sym_tbl == NULL) {
2022f4d24fe9SChaoyong He 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table");
2023016141b1SChaoyong He 		ret = -EIO;
20246b4273a0SLong Wu 		goto sync_free;
2025646ea79cSHeinrich Kuhn 	}
2026646ea79cSHeinrich Kuhn 
2027d5f39e07SChaoyong He 	/* Read the app ID of the firmware loaded */
20283b00109dSPeng Zhang 	function_id = pci_dev->addr.function & 0x7;
20293b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
20303b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
2031e7978635SChaoyong He 	if (ret != 0) {
20323b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "Couldn't read %s from fw", app_name);
2033016141b1SChaoyong He 		ret = -EIO;
2034968ec1c3SChaoyong He 		goto sym_tbl_cleanup;
2035968ec1c3SChaoyong He 	}
2036646ea79cSHeinrich Kuhn 
2037016141b1SChaoyong He 	/* Populate the newly created PF device */
2038016141b1SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
2039016141b1SChaoyong He 	pf_dev->cpp = cpp;
2040016141b1SChaoyong He 	pf_dev->sym_tbl = sym_tbl;
2041016141b1SChaoyong He 	pf_dev->pci_dev = pci_dev;
20426b4273a0SLong Wu 	pf_dev->sync = sync;
2043016141b1SChaoyong He 
2044016141b1SChaoyong He 	/* Call app specific init code now */
2045d5f39e07SChaoyong He 	switch (app_fw_id) {
2046d5f39e07SChaoyong He 	case NFP_APP_FW_CORE_NIC:
2047d5f39e07SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing coreNIC");
2048016141b1SChaoyong He 		ret = nfp_secondary_init_app_fw_nic(pf_dev);
2049d5f39e07SChaoyong He 		if (ret != 0) {
2050d5f39e07SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
2051d5f39e07SChaoyong He 			goto sym_tbl_cleanup;
2052646ea79cSHeinrich Kuhn 		}
2053d5f39e07SChaoyong He 		break;
2054b1880421SChaoyong He 	case NFP_APP_FW_FLOWER_NIC:
2055b1880421SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing Flower");
2056016141b1SChaoyong He 		ret = nfp_secondary_init_app_fw_flower(pf_dev);
2057b1880421SChaoyong He 		if (ret != 0) {
2058b1880421SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
2059b1880421SChaoyong He 			goto sym_tbl_cleanup;
2060b1880421SChaoyong He 		}
2061b1880421SChaoyong He 		break;
2062d5f39e07SChaoyong He 	default:
2063d5f39e07SChaoyong He 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded");
2064d5f39e07SChaoyong He 		ret = -EINVAL;
2065d5f39e07SChaoyong He 		goto sym_tbl_cleanup;
2066646ea79cSHeinrich Kuhn 	}
2067646ea79cSHeinrich Kuhn 
2068016141b1SChaoyong He 	return 0;
2069016141b1SChaoyong He 
2070968ec1c3SChaoyong He sym_tbl_cleanup:
2071968ec1c3SChaoyong He 	free(sym_tbl);
20726b4273a0SLong Wu sync_free:
20736b4273a0SLong Wu 	nfp_sync_free(sync);
2074016141b1SChaoyong He pf_cleanup:
2075016141b1SChaoyong He 	rte_free(pf_dev);
2076968ec1c3SChaoyong He 
2077968ec1c3SChaoyong He 	return ret;
2078646ea79cSHeinrich Kuhn }
2079646ea79cSHeinrich Kuhn 
2080a6189a67SJin Liu static int
2081a6189a67SJin Liu nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
2082646ea79cSHeinrich Kuhn 		struct rte_pci_device *dev)
2083646ea79cSHeinrich Kuhn {
2084646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
2085646ea79cSHeinrich Kuhn 		return nfp_pf_init(dev);
2086646ea79cSHeinrich Kuhn 	else
2087646ea79cSHeinrich Kuhn 		return nfp_pf_secondary_init(dev);
2088646ea79cSHeinrich Kuhn }
2089646ea79cSHeinrich Kuhn 
2090646ea79cSHeinrich Kuhn static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
2091646ea79cSHeinrich Kuhn 	{
2092646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
20935c464d6aSJin Liu 				PCI_DEVICE_ID_NFP3800_PF_NIC)
20945c464d6aSJin Liu 	},
20955c464d6aSJin Liu 	{
20965c464d6aSJin Liu 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2097646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP4000_PF_NIC)
2098646ea79cSHeinrich Kuhn 	},
2099646ea79cSHeinrich Kuhn 	{
2100646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2101646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP6000_PF_NIC)
2102646ea79cSHeinrich Kuhn 	},
2103646ea79cSHeinrich Kuhn 	{
21045aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
21055aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP3800_PF_NIC)
21065aedd4c3SJames Hershaw 	},
21075aedd4c3SJames Hershaw 	{
21085aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
21095aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP4000_PF_NIC)
21105aedd4c3SJames Hershaw 	},
21115aedd4c3SJames Hershaw 	{
21125aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
21135aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP6000_PF_NIC)
21145aedd4c3SJames Hershaw 	},
21155aedd4c3SJames Hershaw 	{
2116646ea79cSHeinrich Kuhn 		.vendor_id = 0,
2117646ea79cSHeinrich Kuhn 	},
2118646ea79cSHeinrich Kuhn };
2119646ea79cSHeinrich Kuhn 
2120a6189a67SJin Liu static int
2121a6189a67SJin Liu nfp_pci_uninit(struct rte_eth_dev *eth_dev)
2122646ea79cSHeinrich Kuhn {
2123646ea79cSHeinrich Kuhn 	uint16_t port_id;
212449952141SChaoyong He 	struct rte_pci_device *pci_dev;
2125646ea79cSHeinrich Kuhn 
2126646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
2127646ea79cSHeinrich Kuhn 
2128646ea79cSHeinrich Kuhn 	/* Free up all physical ports under PF */
2129646ea79cSHeinrich Kuhn 	RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device)
2130646ea79cSHeinrich Kuhn 		rte_eth_dev_close(port_id);
2131646ea79cSHeinrich Kuhn 	/*
2132646ea79cSHeinrich Kuhn 	 * Ports can be closed and freed but hotplugging is not
213340688372SChaoyong He 	 * currently supported.
2134646ea79cSHeinrich Kuhn 	 */
2135646ea79cSHeinrich Kuhn 	return -ENOTSUP;
2136646ea79cSHeinrich Kuhn }
2137646ea79cSHeinrich Kuhn 
2138a6189a67SJin Liu static int
2139a6189a67SJin Liu eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
2140646ea79cSHeinrich Kuhn {
2141646ea79cSHeinrich Kuhn 	return rte_eth_dev_pci_generic_remove(pci_dev, nfp_pci_uninit);
2142646ea79cSHeinrich Kuhn }
2143646ea79cSHeinrich Kuhn 
2144646ea79cSHeinrich Kuhn static struct rte_pci_driver rte_nfp_net_pf_pmd = {
2145646ea79cSHeinrich Kuhn 	.id_table = pci_id_nfp_pf_net_map,
2146646ea79cSHeinrich Kuhn 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
2147646ea79cSHeinrich Kuhn 	.probe = nfp_pf_pci_probe,
2148646ea79cSHeinrich Kuhn 	.remove = eth_nfp_pci_remove,
2149646ea79cSHeinrich Kuhn };
2150646ea79cSHeinrich Kuhn 
2151d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI(NFP_PF_DRIVER_NAME, rte_nfp_net_pf_pmd);
2152d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI_TABLE(NFP_PF_DRIVER_NAME, pci_id_nfp_pf_net_map);
2153d505ee1dSChaoyong He RTE_PMD_REGISTER_KMOD_DEP(NFP_PF_DRIVER_NAME, "* igb_uio | uio_pci_generic | vfio");
2154