xref: /dpdk/drivers/net/nfp/nfp_ethdev.c (revision c92c83d4ac997c09e6ea0df80e49d9c622686f94)
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"
17646ea79cSHeinrich Kuhn #include "nfpcore/nfp_hwinfo.h"
18646ea79cSHeinrich Kuhn #include "nfpcore/nfp_rtsym.h"
19646ea79cSHeinrich Kuhn #include "nfpcore/nfp_nsp.h"
20796f1aecSChaoyong He #include "nfpcore/nfp6000_pcie.h"
218ba461d1SPeng Zhang #include "nfpcore/nfp_resource.h"
22646ea79cSHeinrich Kuhn 
23646ea79cSHeinrich Kuhn #include "nfp_cpp_bridge.h"
2454713740SChang Miao #include "nfp_ipsec.h"
255a95b024SChaoyong He #include "nfp_logs.h"
268153bc6fSChaoyong He #include "nfp_net_flow.h"
27b1880421SChaoyong He 
28c7a6970fSZerun Fu /* 64-bit per app capabilities */
29c7a6970fSZerun Fu #define NFP_NET_APP_CAP_SP_INDIFF       RTE_BIT64(0) /* Indifferent to port speed */
30c7a6970fSZerun Fu 
31d505ee1dSChaoyong He #define NFP_PF_DRIVER_NAME net_nfp_pf
32d505ee1dSChaoyong He 
33a243128bSChaoyong He static void
34f4d24fe9SChaoyong He nfp_net_pf_read_mac(struct nfp_app_fw_nic *app_fw_nic,
358ceb85c3SChaoyong He 		uint16_t port)
36646ea79cSHeinrich Kuhn {
3749952141SChaoyong He 	struct nfp_net_hw *hw;
38646ea79cSHeinrich Kuhn 	struct nfp_eth_table *nfp_eth_table;
39646ea79cSHeinrich Kuhn 
40646ea79cSHeinrich Kuhn 	/* Grab a pointer to the correct physical port */
41968ec1c3SChaoyong He 	hw = app_fw_nic->ports[port];
42646ea79cSHeinrich Kuhn 
43a243128bSChaoyong He 	nfp_eth_table = app_fw_nic->pf_dev->nfp_eth_table;
44646ea79cSHeinrich Kuhn 
45ef759759SChaoyong He 	rte_ether_addr_copy(&nfp_eth_table->ports[port].mac_addr, &hw->super.mac_addr);
46646ea79cSHeinrich Kuhn }
47646ea79cSHeinrich Kuhn 
48009f43d5SZerun Fu static uint32_t
49009f43d5SZerun Fu nfp_net_speed_bitmap2speed(uint32_t speeds_bitmap)
50009f43d5SZerun Fu {
51009f43d5SZerun Fu 	switch (speeds_bitmap) {
52009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M_HD:
53009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
54009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10M:
55009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10M;
56009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M_HD:
57009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
58009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100M:
59009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100M;
60009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_1G:
61009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_1G;
62009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_2_5G:
63009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_2_5G;
64009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_5G:
65009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_5G;
66009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_10G:
67009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_10G;
68009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_20G:
69009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_20G;
70009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_25G:
71009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_25G;
72009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_40G:
73009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_40G;
74009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_50G:
75009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_50G;
76009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_56G:
77009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_56G;
78009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_100G:
79009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_100G;
80009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_200G:
81009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_200G;
82009f43d5SZerun Fu 	case RTE_ETH_LINK_SPEED_400G:
83009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_400G;
84009f43d5SZerun Fu 	default:
85009f43d5SZerun Fu 		return RTE_ETH_SPEED_NUM_NONE;
86009f43d5SZerun Fu 	}
87009f43d5SZerun Fu }
88009f43d5SZerun Fu 
89009f43d5SZerun Fu static int
90009f43d5SZerun Fu nfp_net_nfp4000_speed_configure_check(uint16_t port_id,
91009f43d5SZerun Fu 		uint32_t configure_speed,
92009f43d5SZerun Fu 		struct nfp_eth_table *nfp_eth_table)
93009f43d5SZerun Fu {
94009f43d5SZerun Fu 	switch (port_id) {
95009f43d5SZerun Fu 	case 0:
96009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_25G &&
97009f43d5SZerun Fu 				nfp_eth_table->ports[1].speed == RTE_ETH_SPEED_NUM_10G) {
98009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
99009f43d5SZerun Fu 			return -ENOTSUP;
100009f43d5SZerun Fu 		}
101009f43d5SZerun Fu 		break;
102009f43d5SZerun Fu 	case 1:
103009f43d5SZerun Fu 		if (configure_speed == RTE_ETH_SPEED_NUM_10G &&
104009f43d5SZerun Fu 				nfp_eth_table->ports[0].speed == RTE_ETH_SPEED_NUM_25G) {
105009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "The speed configuration is not supported for NFP4000.");
106009f43d5SZerun Fu 			return -ENOTSUP;
107009f43d5SZerun Fu 		}
108009f43d5SZerun Fu 		break;
109009f43d5SZerun Fu 	default:
110009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "The port id is invalid.");
111009f43d5SZerun Fu 		return -EINVAL;
112009f43d5SZerun Fu 	}
113009f43d5SZerun Fu 
114009f43d5SZerun Fu 	return 0;
115009f43d5SZerun Fu }
116009f43d5SZerun Fu 
117009f43d5SZerun Fu static int
118009f43d5SZerun Fu nfp_net_speed_configure(struct rte_eth_dev *dev,
119009f43d5SZerun Fu 		struct nfp_net_hw *net_hw)
120009f43d5SZerun Fu {
121009f43d5SZerun Fu 	int ret;
122009f43d5SZerun Fu 	uint32_t speed_capa;
123009f43d5SZerun Fu 	struct nfp_nsp *nsp;
124009f43d5SZerun Fu 	uint32_t link_speeds;
125009f43d5SZerun Fu 	uint32_t configure_speed;
126009f43d5SZerun Fu 	struct nfp_eth_table_port *eth_port;
127009f43d5SZerun Fu 	struct nfp_eth_table *nfp_eth_table;
128009f43d5SZerun Fu 
129009f43d5SZerun Fu 	nfp_eth_table = net_hw->pf_dev->nfp_eth_table;
130009f43d5SZerun Fu 	eth_port = &nfp_eth_table->ports[net_hw->idx];
131009f43d5SZerun Fu 
132009f43d5SZerun Fu 	speed_capa = net_hw->pf_dev->speed_capa;
133009f43d5SZerun Fu 	if (speed_capa == 0) {
134009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Speed_capa is invalid.");
135009f43d5SZerun Fu 		return -EINVAL;
136009f43d5SZerun Fu 	}
137009f43d5SZerun Fu 
138009f43d5SZerun Fu 	link_speeds = dev->data->dev_conf.link_speeds;
139009f43d5SZerun Fu 	configure_speed = nfp_net_speed_bitmap2speed(speed_capa & link_speeds);
140009f43d5SZerun Fu 	if (configure_speed == RTE_ETH_SPEED_NUM_NONE &&
141009f43d5SZerun Fu 			link_speeds != RTE_ETH_LINK_SPEED_AUTONEG) {
142009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Configured speed is invalid.");
143009f43d5SZerun Fu 		return -EINVAL;
144009f43d5SZerun Fu 	}
145009f43d5SZerun Fu 
146009f43d5SZerun Fu 	/* NFP4000 does not allow the port 0 25Gbps and port 1 10Gbps at the same time. */
147009f43d5SZerun Fu 	if (net_hw->device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) {
148009f43d5SZerun Fu 		ret = nfp_net_nfp4000_speed_configure_check(net_hw->idx,
149009f43d5SZerun Fu 				configure_speed, nfp_eth_table);
150009f43d5SZerun Fu 		if (ret != 0) {
151009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to configure speed for NFP4000.");
152009f43d5SZerun Fu 			return ret;
153009f43d5SZerun Fu 		}
154009f43d5SZerun Fu 	}
155009f43d5SZerun Fu 
156009f43d5SZerun Fu 	nsp = nfp_eth_config_start(net_hw->cpp, eth_port->index);
157009f43d5SZerun Fu 	if (nsp == NULL) {
158009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Couldn't get NSP.");
159009f43d5SZerun Fu 		return -EIO;
160009f43d5SZerun Fu 	}
161009f43d5SZerun Fu 
162009f43d5SZerun Fu 	if (link_speeds == RTE_ETH_LINK_SPEED_AUTONEG) {
163009f43d5SZerun Fu 		if (eth_port->supp_aneg) {
164009f43d5SZerun Fu 			ret = nfp_eth_set_aneg(nsp, NFP_ANEG_AUTO);
165009f43d5SZerun Fu 			if (ret != 0) {
166009f43d5SZerun Fu 				PMD_DRV_LOG(ERR, "Failed to set ANEG enable.");
167009f43d5SZerun Fu 				goto config_cleanup;
168009f43d5SZerun Fu 			}
169009f43d5SZerun Fu 		}
170009f43d5SZerun Fu 	} else {
171009f43d5SZerun Fu 		ret = nfp_eth_set_aneg(nsp, NFP_ANEG_DISABLED);
172009f43d5SZerun Fu 		if (ret != 0) {
173009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set ANEG disable.");
174009f43d5SZerun Fu 			goto config_cleanup;
175009f43d5SZerun Fu 		}
176009f43d5SZerun Fu 
177009f43d5SZerun Fu 		ret = nfp_eth_set_speed(nsp, configure_speed);
178009f43d5SZerun Fu 		if (ret != 0) {
179009f43d5SZerun Fu 			PMD_DRV_LOG(ERR, "Failed to set speed.");
180009f43d5SZerun Fu 			goto config_cleanup;
181009f43d5SZerun Fu 		}
182009f43d5SZerun Fu 	}
183009f43d5SZerun Fu 
184009f43d5SZerun Fu 	return nfp_eth_config_commit_end(nsp);
185009f43d5SZerun Fu 
186009f43d5SZerun Fu config_cleanup:
187009f43d5SZerun Fu 	nfp_eth_config_cleanup_end(nsp);
188009f43d5SZerun Fu 
189009f43d5SZerun Fu 	return ret;
190009f43d5SZerun Fu }
191009f43d5SZerun Fu 
192646ea79cSHeinrich Kuhn static int
193646ea79cSHeinrich Kuhn nfp_net_start(struct rte_eth_dev *dev)
194646ea79cSHeinrich Kuhn {
19549952141SChaoyong He 	int ret;
19649952141SChaoyong He 	uint16_t i;
19772d1dea6SChaoyong He 	struct nfp_hw *hw;
19849952141SChaoyong He 	uint32_t new_ctrl;
199acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
20049952141SChaoyong He 	uint32_t update = 0;
2012e7c3612SQin Ke 	uint32_t cap_extend;
20249952141SChaoyong He 	uint32_t intr_vector;
20349952141SChaoyong He 	uint32_t ctrl_extend = 0;
20472d1dea6SChaoyong He 	struct nfp_net_hw *net_hw;
205646ea79cSHeinrich Kuhn 	struct nfp_pf_dev *pf_dev;
206646ea79cSHeinrich Kuhn 	struct rte_eth_rxmode *rxmode;
20749952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
20849952141SChaoyong He 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
20949952141SChaoyong He 	struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
210646ea79cSHeinrich Kuhn 
2119d723baaSChaoyong He 	net_hw = dev->data->dev_private;
21265f6915dSChaoyong He 	pf_dev = net_hw->pf_dev;
213968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
21472d1dea6SChaoyong He 	hw = &net_hw->super;
215646ea79cSHeinrich Kuhn 
216646ea79cSHeinrich Kuhn 	/* Disabling queues just in case... */
217646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
218646ea79cSHeinrich Kuhn 
219646ea79cSHeinrich Kuhn 	/* Enabling the required queues in the device */
220646ea79cSHeinrich Kuhn 	nfp_net_enable_queues(dev);
221646ea79cSHeinrich Kuhn 
222009f43d5SZerun Fu 	/* Configure the port speed and the auto-negotiation mode. */
223009f43d5SZerun Fu 	ret = nfp_net_speed_configure(dev, net_hw);
224009f43d5SZerun Fu 	if (ret < 0) {
225009f43d5SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to set the speed and auto-negotiation mode.");
226009f43d5SZerun Fu 		return ret;
227009f43d5SZerun Fu 	}
228009f43d5SZerun Fu 
22940688372SChaoyong He 	/* Check and configure queue intr-vector mapping */
230646ea79cSHeinrich Kuhn 	if (dev->data->dev_conf.intr_conf.rxq != 0) {
231968ec1c3SChaoyong He 		if (app_fw_nic->multiport) {
232646ea79cSHeinrich Kuhn 			PMD_INIT_LOG(ERR, "PMD rx interrupt is not supported "
233646ea79cSHeinrich Kuhn 					"with NFP multiport PF");
234646ea79cSHeinrich Kuhn 				return -EINVAL;
235646ea79cSHeinrich Kuhn 		}
236b0c496abSChaoyong He 
237f4d24fe9SChaoyong He 		if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_UIO) {
238646ea79cSHeinrich Kuhn 			/*
239646ea79cSHeinrich Kuhn 			 * Better not to share LSC with RX interrupts.
24040688372SChaoyong He 			 * Unregistering LSC interrupt handler.
241646ea79cSHeinrich Kuhn 			 */
242e7978635SChaoyong He 			rte_intr_callback_unregister(intr_handle,
243646ea79cSHeinrich Kuhn 					nfp_net_dev_interrupt_handler, (void *)dev);
244646ea79cSHeinrich Kuhn 
245646ea79cSHeinrich Kuhn 			if (dev->data->nb_rx_queues > 1) {
246646ea79cSHeinrich Kuhn 				PMD_INIT_LOG(ERR, "PMD rx interrupt only "
247646ea79cSHeinrich Kuhn 						"supports 1 queue with UIO");
248646ea79cSHeinrich Kuhn 				return -EIO;
249646ea79cSHeinrich Kuhn 			}
250646ea79cSHeinrich Kuhn 		}
251b0c496abSChaoyong He 
252646ea79cSHeinrich Kuhn 		intr_vector = dev->data->nb_rx_queues;
253c01e5c0cSChaoyong He 		if (rte_intr_efd_enable(intr_handle, intr_vector) != 0)
254646ea79cSHeinrich Kuhn 			return -1;
255646ea79cSHeinrich Kuhn 
256646ea79cSHeinrich Kuhn 		nfp_configure_rx_interrupt(dev, intr_handle);
257646ea79cSHeinrich Kuhn 		update = NFP_NET_CFG_UPDATE_MSIX;
258646ea79cSHeinrich Kuhn 	}
259646ea79cSHeinrich Kuhn 
260dbad6f64SPeng Zhang 	/* Checking MTU set */
26172d1dea6SChaoyong He 	if (dev->data->mtu > net_hw->flbufsz) {
262dbad6f64SPeng Zhang 		PMD_INIT_LOG(ERR, "MTU (%u) can't be larger than the current NFP_FRAME_SIZE (%u)",
26372d1dea6SChaoyong He 				dev->data->mtu, net_hw->flbufsz);
264dbad6f64SPeng Zhang 		return -ERANGE;
265dbad6f64SPeng Zhang 	}
266dbad6f64SPeng Zhang 
267646ea79cSHeinrich Kuhn 	rte_intr_enable(intr_handle);
268646ea79cSHeinrich Kuhn 
269646ea79cSHeinrich Kuhn 	new_ctrl = nfp_check_offloads(dev);
270646ea79cSHeinrich Kuhn 
271646ea79cSHeinrich Kuhn 	/* Writing configuration parameters in the device */
27272d1dea6SChaoyong He 	nfp_net_params_setup(net_hw);
273646ea79cSHeinrich Kuhn 
274c4de52ecSChaoyong He 	rxmode = &dev->data->dev_conf.rxmode;
275c01e5c0cSChaoyong He 	if ((rxmode->mq_mode & RTE_ETH_MQ_RX_RSS) != 0) {
276646ea79cSHeinrich Kuhn 		nfp_net_rss_config_default(dev);
277646ea79cSHeinrich Kuhn 		update |= NFP_NET_CFG_UPDATE_RSS;
27872d1dea6SChaoyong He 		new_ctrl |= nfp_net_cfg_ctrl_rss(hw->cap);
279646ea79cSHeinrich Kuhn 	}
280646ea79cSHeinrich Kuhn 
281646ea79cSHeinrich Kuhn 	/* Enable device */
282646ea79cSHeinrich Kuhn 	new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
283646ea79cSHeinrich Kuhn 
284646ea79cSHeinrich Kuhn 	update |= NFP_NET_CFG_UPDATE_GEN | NFP_NET_CFG_UPDATE_RING;
285646ea79cSHeinrich Kuhn 
286c55abf61SChaoyong He 	/* Enable vxlan */
28772d1dea6SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_VXLAN) != 0) {
288c55abf61SChaoyong He 		new_ctrl |= NFP_NET_CFG_CTRL_VXLAN;
289c55abf61SChaoyong He 		update |= NFP_NET_CFG_UPDATE_VXLAN;
290c925a157SFei Qin 	}
291c55abf61SChaoyong He 
29272d1dea6SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_RINGCFG) != 0)
293646ea79cSHeinrich Kuhn 		new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG;
294646ea79cSHeinrich Kuhn 
29572d1dea6SChaoyong He 	if (nfp_reconfig(hw, new_ctrl, update) != 0)
296646ea79cSHeinrich Kuhn 		return -EIO;
297646ea79cSHeinrich Kuhn 
2981e80c074SChaoyong He 	hw->ctrl = new_ctrl;
2991e80c074SChaoyong He 
3002e7c3612SQin Ke 	/* Enable packet type offload by extend ctrl word1. */
30172d1dea6SChaoyong He 	cap_extend = hw->cap_ext;
3022e7c3612SQin Ke 	if ((cap_extend & NFP_NET_CFG_CTRL_PKT_TYPE) != 0)
3032e7c3612SQin Ke 		ctrl_extend = NFP_NET_CFG_CTRL_PKT_TYPE;
3042e7c3612SQin Ke 
30554713740SChang Miao 	if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0)
3069177c800SChaoyong He 		ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC |
3079177c800SChaoyong He 				NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP |
3089177c800SChaoyong He 				NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP;
30954713740SChang Miao 
3108153bc6fSChaoyong He 	/* Enable flow steer by extend ctrl word1. */
3118153bc6fSChaoyong He 	if ((cap_extend & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
3128153bc6fSChaoyong He 		ctrl_extend |= NFP_NET_CFG_CTRL_FLOW_STEER;
3138153bc6fSChaoyong He 
3142e7c3612SQin Ke 	update = NFP_NET_CFG_UPDATE_GEN;
31572d1dea6SChaoyong He 	if (nfp_ext_reconfig(hw, ctrl_extend, update) != 0)
3162e7c3612SQin Ke 		return -EIO;
3172e7c3612SQin Ke 
31872d1dea6SChaoyong He 	hw->ctrl_ext = ctrl_extend;
319b4b6988aSChaoyong He 
320646ea79cSHeinrich Kuhn 	/*
321646ea79cSHeinrich Kuhn 	 * Allocating rte mbufs for configured rx queues.
32240688372SChaoyong He 	 * This requires queues being enabled before.
323646ea79cSHeinrich Kuhn 	 */
324c01e5c0cSChaoyong He 	if (nfp_net_rx_freelist_setup(dev) != 0) {
325646ea79cSHeinrich Kuhn 		ret = -ENOMEM;
326646ea79cSHeinrich Kuhn 		goto error;
327646ea79cSHeinrich Kuhn 	}
328646ea79cSHeinrich Kuhn 
329646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
330acb6bebfSChaoyong He 		cpp = net_hw->cpp;
331646ea79cSHeinrich Kuhn 	else
332acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
333acb6bebfSChaoyong He 
334acb6bebfSChaoyong He 	/* Configure the physical port up */
335acb6bebfSChaoyong He 	nfp_eth_set_configured(cpp, net_hw->nfp_idx, 1);
336646ea79cSHeinrich Kuhn 
337c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_rx_queues; i++)
338c46216e7SJie Hai 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
339c46216e7SJie Hai 	for (i = 0; i < dev->data->nb_tx_queues; i++)
340c46216e7SJie Hai 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
341c46216e7SJie Hai 
342646ea79cSHeinrich Kuhn 	return 0;
343646ea79cSHeinrich Kuhn 
344646ea79cSHeinrich Kuhn error:
345646ea79cSHeinrich Kuhn 	/*
346646ea79cSHeinrich Kuhn 	 * An error returned by this function should mean the app
347646ea79cSHeinrich Kuhn 	 * exiting and then the system releasing all the memory
348646ea79cSHeinrich Kuhn 	 * allocated even memory coming from hugepages.
349646ea79cSHeinrich Kuhn 	 *
350646ea79cSHeinrich Kuhn 	 * The device could be enabled at this point with some queues
351646ea79cSHeinrich Kuhn 	 * ready for getting packets. This is true if the call to
352646ea79cSHeinrich Kuhn 	 * nfp_net_rx_freelist_setup() succeeds for some queues but
353646ea79cSHeinrich Kuhn 	 * fails for subsequent queues.
354646ea79cSHeinrich Kuhn 	 *
355646ea79cSHeinrich Kuhn 	 * This should make the app exiting but better if we tell the
356646ea79cSHeinrich Kuhn 	 * device first.
357646ea79cSHeinrich Kuhn 	 */
358646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
359646ea79cSHeinrich Kuhn 
360646ea79cSHeinrich Kuhn 	return ret;
361646ea79cSHeinrich Kuhn }
362646ea79cSHeinrich Kuhn 
363646ea79cSHeinrich Kuhn /* Set the link up. */
364646ea79cSHeinrich Kuhn static int
365646ea79cSHeinrich Kuhn nfp_net_set_link_up(struct rte_eth_dev *dev)
366646ea79cSHeinrich Kuhn {
367acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
368646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
369646ea79cSHeinrich Kuhn 
3709d723baaSChaoyong He 	hw = dev->data->dev_private;
371646ea79cSHeinrich Kuhn 
372646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
373acb6bebfSChaoyong He 		cpp = hw->cpp;
374646ea79cSHeinrich Kuhn 	else
375acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
376acb6bebfSChaoyong He 
377acb6bebfSChaoyong He 	return nfp_eth_set_configured(cpp, hw->nfp_idx, 1);
378646ea79cSHeinrich Kuhn }
379646ea79cSHeinrich Kuhn 
380646ea79cSHeinrich Kuhn /* Set the link down. */
381646ea79cSHeinrich Kuhn static int
382646ea79cSHeinrich Kuhn nfp_net_set_link_down(struct rte_eth_dev *dev)
383646ea79cSHeinrich Kuhn {
384acb6bebfSChaoyong He 	struct nfp_cpp *cpp;
385646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
386646ea79cSHeinrich Kuhn 
3879d723baaSChaoyong He 	hw = dev->data->dev_private;
388646ea79cSHeinrich Kuhn 
389646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
390acb6bebfSChaoyong He 		cpp = hw->cpp;
391646ea79cSHeinrich Kuhn 	else
392acb6bebfSChaoyong He 		cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp;
393acb6bebfSChaoyong He 
394acb6bebfSChaoyong He 	return nfp_eth_set_configured(cpp, hw->nfp_idx, 0);
395646ea79cSHeinrich Kuhn }
396646ea79cSHeinrich Kuhn 
3973b00109dSPeng Zhang static uint8_t
3983b00109dSPeng Zhang nfp_function_id_get(const struct nfp_pf_dev *pf_dev,
3993b00109dSPeng Zhang 		uint8_t phy_port)
4003b00109dSPeng Zhang {
4013b00109dSPeng Zhang 	if (pf_dev->multi_pf.enabled)
4023b00109dSPeng Zhang 		return pf_dev->multi_pf.function_id;
4033b00109dSPeng Zhang 
4043b00109dSPeng Zhang 	return phy_port;
4053b00109dSPeng Zhang }
4063b00109dSPeng Zhang 
4078ba461d1SPeng Zhang static void
4088ba461d1SPeng Zhang nfp_net_beat_timer(void *arg)
4098ba461d1SPeng Zhang {
4108ba461d1SPeng Zhang 	uint64_t cur_sec;
4118ba461d1SPeng Zhang 	struct nfp_multi_pf *multi_pf = arg;
4128ba461d1SPeng Zhang 
4138ba461d1SPeng Zhang 	cur_sec = rte_rdtsc();
4148ba461d1SPeng Zhang 	nn_writeq(cur_sec, multi_pf->beat_addr + NFP_BEAT_OFFSET(multi_pf->function_id));
4158ba461d1SPeng Zhang 
4168ba461d1SPeng Zhang 	/* Beat once per second. */
4178ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
4188ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
4198ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Error setting alarm");
4208ba461d1SPeng Zhang 	}
4218ba461d1SPeng Zhang }
4228ba461d1SPeng Zhang 
4238ba461d1SPeng Zhang static int
4248ba461d1SPeng Zhang nfp_net_keepalive_init(struct nfp_cpp *cpp,
4258ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
4268ba461d1SPeng Zhang {
4278ba461d1SPeng Zhang 	uint8_t *base;
4288ba461d1SPeng Zhang 	uint64_t addr;
4298ba461d1SPeng Zhang 	uint32_t size;
4308ba461d1SPeng Zhang 	uint32_t cpp_id;
4318ba461d1SPeng Zhang 	struct nfp_resource *res;
4328ba461d1SPeng Zhang 
4338ba461d1SPeng Zhang 	res = nfp_resource_acquire(cpp, NFP_RESOURCE_KEEPALIVE);
4348ba461d1SPeng Zhang 	if (res == NULL)
4358ba461d1SPeng Zhang 		return -EIO;
4368ba461d1SPeng Zhang 
4378ba461d1SPeng Zhang 	cpp_id = nfp_resource_cpp_id(res);
4388ba461d1SPeng Zhang 	addr = nfp_resource_address(res);
4398ba461d1SPeng Zhang 	size = nfp_resource_size(res);
4408ba461d1SPeng Zhang 
4418ba461d1SPeng Zhang 	nfp_resource_release(res);
4428ba461d1SPeng Zhang 
4438ba461d1SPeng Zhang 	/* Allocate a fixed area for keepalive. */
4448ba461d1SPeng Zhang 	base = nfp_cpp_map_area(cpp, cpp_id, addr, size, &multi_pf->beat_area);
4458ba461d1SPeng Zhang 	if (base == NULL) {
4468ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Failed to map area for keepalive.");
4478ba461d1SPeng Zhang 		return -EIO;
4488ba461d1SPeng Zhang 	}
4498ba461d1SPeng Zhang 
4508ba461d1SPeng Zhang 	multi_pf->beat_addr = base;
4518ba461d1SPeng Zhang 
4528ba461d1SPeng Zhang 	return 0;
4538ba461d1SPeng Zhang }
4548ba461d1SPeng Zhang 
4558ba461d1SPeng Zhang static void
4568ba461d1SPeng Zhang nfp_net_keepalive_uninit(struct nfp_multi_pf *multi_pf)
4578ba461d1SPeng Zhang {
4588ba461d1SPeng Zhang 	nfp_cpp_area_release_free(multi_pf->beat_area);
4598ba461d1SPeng Zhang }
4608ba461d1SPeng Zhang 
4618ba461d1SPeng Zhang static int
4628ba461d1SPeng Zhang nfp_net_keepalive_start(struct nfp_multi_pf *multi_pf)
4638ba461d1SPeng Zhang {
4648ba461d1SPeng Zhang 	if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer,
4658ba461d1SPeng Zhang 			(void *)multi_pf) < 0) {
4668ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "Error setting alarm");
4678ba461d1SPeng Zhang 		return -EIO;
4688ba461d1SPeng Zhang 	}
4698ba461d1SPeng Zhang 
4708ba461d1SPeng Zhang 	return 0;
4718ba461d1SPeng Zhang }
4728ba461d1SPeng Zhang 
4738ba461d1SPeng Zhang static void
474b67a7b40SPeng Zhang nfp_net_keepalive_clear(uint8_t *beat_addr,
475b67a7b40SPeng Zhang 		uint8_t function_id)
476b67a7b40SPeng Zhang {
477b67a7b40SPeng Zhang 	nn_writeq(0, beat_addr + NFP_BEAT_OFFSET(function_id));
478b67a7b40SPeng Zhang }
479b67a7b40SPeng Zhang 
480b67a7b40SPeng Zhang static void
481b67a7b40SPeng Zhang nfp_net_keepalive_clear_others(const struct nfp_dev_info *dev_info,
482b67a7b40SPeng Zhang 		struct nfp_multi_pf *multi_pf)
483b67a7b40SPeng Zhang {
484b67a7b40SPeng Zhang 	uint8_t port_num;
485b67a7b40SPeng Zhang 
486b67a7b40SPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
487b67a7b40SPeng Zhang 		if (port_num == multi_pf->function_id)
488b67a7b40SPeng Zhang 			continue;
489b67a7b40SPeng Zhang 
490b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(multi_pf->beat_addr, port_num);
491b67a7b40SPeng Zhang 	}
492b67a7b40SPeng Zhang }
493b67a7b40SPeng Zhang 
494b67a7b40SPeng Zhang static void
4958ba461d1SPeng Zhang nfp_net_keepalive_stop(struct nfp_multi_pf *multi_pf)
4968ba461d1SPeng Zhang {
4978ba461d1SPeng Zhang 	/* Cancel keepalive for multiple PF setup */
4988ba461d1SPeng Zhang 	rte_eal_alarm_cancel(nfp_net_beat_timer, (void *)multi_pf);
4998ba461d1SPeng Zhang }
5008ba461d1SPeng Zhang 
5018b8f116bSChaoyong He static void
5028b8f116bSChaoyong He nfp_net_uninit(struct rte_eth_dev *eth_dev)
5038b8f116bSChaoyong He {
5048b8f116bSChaoyong He 	struct nfp_net_hw *net_hw;
5058b8f116bSChaoyong He 
5068b8f116bSChaoyong He 	net_hw = eth_dev->data->dev_private;
5078153bc6fSChaoyong He 
5088153bc6fSChaoyong He 	if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0)
5098153bc6fSChaoyong He 		nfp_net_flow_priv_uninit(net_hw->pf_dev, net_hw->idx);
5108153bc6fSChaoyong He 
5118b8f116bSChaoyong He 	rte_free(net_hw->eth_xstats_base);
5128b8f116bSChaoyong He 	nfp_ipsec_uninit(eth_dev);
5138b8f116bSChaoyong He 	if (net_hw->mac_stats_area != NULL)
5148b8f116bSChaoyong He 		nfp_cpp_area_release_free(net_hw->mac_stats_area);
5158b8f116bSChaoyong He }
5168b8f116bSChaoyong He 
51766d5f53dSChaoyong He static void
51866d5f53dSChaoyong He nfp_cleanup_port_app_fw_nic(struct nfp_pf_dev *pf_dev,
51966d5f53dSChaoyong He 		uint8_t id)
52066d5f53dSChaoyong He {
52166d5f53dSChaoyong He 	struct rte_eth_dev *eth_dev;
52266d5f53dSChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
52366d5f53dSChaoyong He 
52466d5f53dSChaoyong He 	app_fw_nic = pf_dev->app_fw_priv;
52566d5f53dSChaoyong He 	if (app_fw_nic->ports[id] != NULL) {
52666d5f53dSChaoyong He 		eth_dev = app_fw_nic->ports[id]->eth_dev;
52766d5f53dSChaoyong He 		if (eth_dev != NULL)
52866d5f53dSChaoyong He 			nfp_net_uninit(eth_dev);
52966d5f53dSChaoyong He 
53066d5f53dSChaoyong He 		app_fw_nic->ports[id] = NULL;
53166d5f53dSChaoyong He 	}
53266d5f53dSChaoyong He }
53366d5f53dSChaoyong He 
53466d5f53dSChaoyong He static void
53566d5f53dSChaoyong He nfp_uninit_app_fw_nic(struct nfp_pf_dev *pf_dev)
53666d5f53dSChaoyong He {
53766d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
53866d5f53dSChaoyong He 	rte_free(pf_dev->app_fw_priv);
53966d5f53dSChaoyong He }
54066d5f53dSChaoyong He 
54166d5f53dSChaoyong He void
54266d5f53dSChaoyong He nfp_pf_uninit(struct nfp_pf_dev *pf_dev)
54366d5f53dSChaoyong He {
54466d5f53dSChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
54566d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
54666d5f53dSChaoyong He 	if (pf_dev->multi_pf.enabled) {
54766d5f53dSChaoyong He 		nfp_net_keepalive_stop(&pf_dev->multi_pf);
548b67a7b40SPeng Zhang 		nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
54966d5f53dSChaoyong He 		nfp_net_keepalive_uninit(&pf_dev->multi_pf);
55066d5f53dSChaoyong He 	}
55166d5f53dSChaoyong He 	free(pf_dev->nfp_eth_table);
55266d5f53dSChaoyong He 	free(pf_dev->hwinfo);
55366d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
55466d5f53dSChaoyong He 	rte_free(pf_dev);
55566d5f53dSChaoyong He }
55666d5f53dSChaoyong He 
55766d5f53dSChaoyong He static int
55866d5f53dSChaoyong He nfp_pf_secondary_uninit(struct nfp_pf_dev *pf_dev)
55966d5f53dSChaoyong He {
56066d5f53dSChaoyong He 	free(pf_dev->sym_tbl);
56166d5f53dSChaoyong He 	nfp_cpp_free(pf_dev->cpp);
56266d5f53dSChaoyong He 	rte_free(pf_dev);
56366d5f53dSChaoyong He 
56466d5f53dSChaoyong He 	return 0;
56566d5f53dSChaoyong He }
56666d5f53dSChaoyong He 
567646ea79cSHeinrich Kuhn /* Reset and stop device. The device can not be restarted. */
568646ea79cSHeinrich Kuhn static int
569646ea79cSHeinrich Kuhn nfp_net_close(struct rte_eth_dev *dev)
570646ea79cSHeinrich Kuhn {
5718ceb85c3SChaoyong He 	uint8_t i;
5723b00109dSPeng Zhang 	uint8_t id;
57349952141SChaoyong He 	struct nfp_net_hw *hw;
57449952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
57549952141SChaoyong He 	struct rte_pci_device *pci_dev;
57649952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
577646ea79cSHeinrich Kuhn 
57866d5f53dSChaoyong He 	/*
57966d5f53dSChaoyong He 	 * In secondary process, a released eth device can be found by its name
58066d5f53dSChaoyong He 	 * in shared memory.
58166d5f53dSChaoyong He 	 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the
58266d5f53dSChaoyong He 	 * eth device has been released.
58366d5f53dSChaoyong He 	 */
58466d5f53dSChaoyong He 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
58566d5f53dSChaoyong He 		if (dev->state == RTE_ETH_DEV_UNUSED)
586646ea79cSHeinrich Kuhn 			return 0;
587646ea79cSHeinrich Kuhn 
58866d5f53dSChaoyong He 		nfp_pf_secondary_uninit(dev->process_private);
58966d5f53dSChaoyong He 		return 0;
59066d5f53dSChaoyong He 	}
59166d5f53dSChaoyong He 
5929d723baaSChaoyong He 	hw = dev->data->dev_private;
59365f6915dSChaoyong He 	pf_dev = hw->pf_dev;
594646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(dev);
595968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
596646ea79cSHeinrich Kuhn 
597646ea79cSHeinrich Kuhn 	/*
598646ea79cSHeinrich Kuhn 	 * We assume that the DPDK application is stopping all the
599646ea79cSHeinrich Kuhn 	 * threads/queues before calling the device close function.
600646ea79cSHeinrich Kuhn 	 */
601646ea79cSHeinrich Kuhn 	nfp_net_disable_queues(dev);
602646ea79cSHeinrich Kuhn 
603646ea79cSHeinrich Kuhn 	/* Clear queues */
6041c8d02bbSJin Liu 	nfp_net_close_tx_queue(dev);
6051c8d02bbSJin Liu 	nfp_net_close_rx_queue(dev);
606646ea79cSHeinrich Kuhn 
607851f03e1SHeinrich Kuhn 	/* Cancel possible impending LSC work here before releasing the port */
608f4d24fe9SChaoyong He 	rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev);
609851f03e1SHeinrich Kuhn 
610646ea79cSHeinrich Kuhn 	/* Only free PF resources after all physical ports have been closed */
611646ea79cSHeinrich Kuhn 	/* Mark this port as unused and free device priv resources */
612f58bde00SChaoyong He 	nn_cfg_writeb(&hw->super, NFP_NET_CFG_LSC, 0xff);
61366d5f53dSChaoyong He 
61466d5f53dSChaoyong He 	if (pf_dev->app_fw_id != NFP_APP_FW_CORE_NIC)
61566d5f53dSChaoyong He 		return -EINVAL;
61666d5f53dSChaoyong He 
61766d5f53dSChaoyong He 	nfp_cleanup_port_app_fw_nic(pf_dev, hw->idx);
618646ea79cSHeinrich Kuhn 
619968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
6203b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
6213b00109dSPeng Zhang 
622646ea79cSHeinrich Kuhn 		/* Check to see if ports are still in use */
6233b00109dSPeng Zhang 		if (app_fw_nic->ports[id] != NULL)
624646ea79cSHeinrich Kuhn 			return 0;
625646ea79cSHeinrich Kuhn 	}
626646ea79cSHeinrich Kuhn 
62766d5f53dSChaoyong He 	/* Enable in nfp_net_start() */
628d61138d4SHarman Kalra 	rte_intr_disable(pci_dev->intr_handle);
629646ea79cSHeinrich Kuhn 
63066d5f53dSChaoyong He 	/* Register in nfp_net_init() */
631d61138d4SHarman Kalra 	rte_intr_callback_unregister(pci_dev->intr_handle,
632a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)dev);
633646ea79cSHeinrich Kuhn 
63466d5f53dSChaoyong He 	nfp_uninit_app_fw_nic(pf_dev);
63566d5f53dSChaoyong He 	nfp_pf_uninit(pf_dev);
63666d5f53dSChaoyong He 
637646ea79cSHeinrich Kuhn 	return 0;
638646ea79cSHeinrich Kuhn }
639646ea79cSHeinrich Kuhn 
640c55abf61SChaoyong He static int
641c55abf61SChaoyong He nfp_net_find_vxlan_idx(struct nfp_net_hw *hw,
642c55abf61SChaoyong He 		uint16_t port,
643c55abf61SChaoyong He 		uint32_t *idx)
644c55abf61SChaoyong He {
645c55abf61SChaoyong He 	uint32_t i;
646c55abf61SChaoyong He 	int free_idx = -1;
647c55abf61SChaoyong He 
648c55abf61SChaoyong He 	for (i = 0; i < NFP_NET_N_VXLAN_PORTS; i++) {
649c55abf61SChaoyong He 		if (hw->vxlan_ports[i] == port) {
650c55abf61SChaoyong He 			free_idx = i;
651c55abf61SChaoyong He 			break;
652c55abf61SChaoyong He 		}
653c55abf61SChaoyong He 
654c55abf61SChaoyong He 		if (hw->vxlan_usecnt[i] == 0) {
655c55abf61SChaoyong He 			free_idx = i;
656c55abf61SChaoyong He 			break;
657c55abf61SChaoyong He 		}
658c55abf61SChaoyong He 	}
659c55abf61SChaoyong He 
660c55abf61SChaoyong He 	if (free_idx == -1)
661c55abf61SChaoyong He 		return -EINVAL;
662c55abf61SChaoyong He 
663c55abf61SChaoyong He 	*idx = free_idx;
664c55abf61SChaoyong He 
665c55abf61SChaoyong He 	return 0;
666c55abf61SChaoyong He }
667c55abf61SChaoyong He 
668c55abf61SChaoyong He static int
669c55abf61SChaoyong He nfp_udp_tunnel_port_add(struct rte_eth_dev *dev,
670c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
671c55abf61SChaoyong He {
672c55abf61SChaoyong He 	int ret;
673c55abf61SChaoyong He 	uint32_t idx;
674c55abf61SChaoyong He 	uint16_t vxlan_port;
675c55abf61SChaoyong He 	struct nfp_net_hw *hw;
676c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
677c55abf61SChaoyong He 
6789d723baaSChaoyong He 	hw = dev->data->dev_private;
679c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
680c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
681c55abf61SChaoyong He 
682c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
683c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel");
684c55abf61SChaoyong He 		return -ENOTSUP;
685c55abf61SChaoyong He 	}
686c55abf61SChaoyong He 
687c55abf61SChaoyong He 	ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx);
688c55abf61SChaoyong He 	if (ret != 0) {
689c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx");
690c55abf61SChaoyong He 		return -EINVAL;
691c55abf61SChaoyong He 	}
692c55abf61SChaoyong He 
693c55abf61SChaoyong He 	if (hw->vxlan_usecnt[idx] == 0) {
694c55abf61SChaoyong He 		ret = nfp_net_set_vxlan_port(hw, idx, vxlan_port);
695c55abf61SChaoyong He 		if (ret != 0) {
696c55abf61SChaoyong He 			PMD_DRV_LOG(ERR, "Failed set vxlan port");
697c55abf61SChaoyong He 			return -EINVAL;
698c55abf61SChaoyong He 		}
699c55abf61SChaoyong He 	}
700c55abf61SChaoyong He 
701c55abf61SChaoyong He 	hw->vxlan_usecnt[idx]++;
702c55abf61SChaoyong He 
703c55abf61SChaoyong He 	return 0;
704c55abf61SChaoyong He }
705c55abf61SChaoyong He 
706c55abf61SChaoyong He static int
707c55abf61SChaoyong He nfp_udp_tunnel_port_del(struct rte_eth_dev *dev,
708c55abf61SChaoyong He 		struct rte_eth_udp_tunnel *tunnel_udp)
709c55abf61SChaoyong He {
710c55abf61SChaoyong He 	int ret;
711c55abf61SChaoyong He 	uint32_t idx;
712c55abf61SChaoyong He 	uint16_t vxlan_port;
713c55abf61SChaoyong He 	struct nfp_net_hw *hw;
714c55abf61SChaoyong He 	enum rte_eth_tunnel_type tnl_type;
715c55abf61SChaoyong He 
7169d723baaSChaoyong He 	hw = dev->data->dev_private;
717c55abf61SChaoyong He 	vxlan_port = tunnel_udp->udp_port;
718c55abf61SChaoyong He 	tnl_type   = tunnel_udp->prot_type;
719c55abf61SChaoyong He 
720c55abf61SChaoyong He 	if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) {
721c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Not VXLAN tunnel");
722c55abf61SChaoyong He 		return -ENOTSUP;
723c55abf61SChaoyong He 	}
724c55abf61SChaoyong He 
725c55abf61SChaoyong He 	ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx);
726c55abf61SChaoyong He 	if (ret != 0 || hw->vxlan_usecnt[idx] == 0) {
727c55abf61SChaoyong He 		PMD_DRV_LOG(ERR, "Failed find valid vxlan idx");
728c55abf61SChaoyong He 		return -EINVAL;
729c55abf61SChaoyong He 	}
730c55abf61SChaoyong He 
731c55abf61SChaoyong He 	hw->vxlan_usecnt[idx]--;
732c55abf61SChaoyong He 
733c55abf61SChaoyong He 	if (hw->vxlan_usecnt[idx] == 0) {
734c55abf61SChaoyong He 		ret = nfp_net_set_vxlan_port(hw, idx, 0);
735c55abf61SChaoyong He 		if (ret != 0) {
736c55abf61SChaoyong He 			PMD_DRV_LOG(ERR, "Failed set vxlan port");
737c55abf61SChaoyong He 			return -EINVAL;
738c55abf61SChaoyong He 		}
739c55abf61SChaoyong He 	}
740c55abf61SChaoyong He 
741c55abf61SChaoyong He 	return 0;
742c55abf61SChaoyong He }
743c55abf61SChaoyong He 
744646ea79cSHeinrich Kuhn /* Initialise and register driver with DPDK Application */
7458d961320SJin Liu static const struct eth_dev_ops nfp_net_eth_dev_ops = {
746646ea79cSHeinrich Kuhn 	.dev_configure          = nfp_net_configure,
747646ea79cSHeinrich Kuhn 	.dev_start              = nfp_net_start,
748646ea79cSHeinrich Kuhn 	.dev_stop               = nfp_net_stop,
749646ea79cSHeinrich Kuhn 	.dev_set_link_up        = nfp_net_set_link_up,
750646ea79cSHeinrich Kuhn 	.dev_set_link_down      = nfp_net_set_link_down,
751646ea79cSHeinrich Kuhn 	.dev_close              = nfp_net_close,
752646ea79cSHeinrich Kuhn 	.promiscuous_enable     = nfp_net_promisc_enable,
753646ea79cSHeinrich Kuhn 	.promiscuous_disable    = nfp_net_promisc_disable,
7544a86c36bSQin Ke 	.allmulticast_enable    = nfp_net_allmulticast_enable,
7554a86c36bSQin Ke 	.allmulticast_disable   = nfp_net_allmulticast_disable,
756646ea79cSHeinrich Kuhn 	.link_update            = nfp_net_link_update,
757646ea79cSHeinrich Kuhn 	.stats_get              = nfp_net_stats_get,
758646ea79cSHeinrich Kuhn 	.stats_reset            = nfp_net_stats_reset,
759f26e8239SJames Hershaw 	.xstats_get             = nfp_net_xstats_get,
760f26e8239SJames Hershaw 	.xstats_reset           = nfp_net_xstats_reset,
761f26e8239SJames Hershaw 	.xstats_get_names       = nfp_net_xstats_get_names,
762f26e8239SJames Hershaw 	.xstats_get_by_id       = nfp_net_xstats_get_by_id,
763f26e8239SJames Hershaw 	.xstats_get_names_by_id = nfp_net_xstats_get_names_by_id,
764646ea79cSHeinrich Kuhn 	.dev_infos_get          = nfp_net_infos_get,
765646ea79cSHeinrich Kuhn 	.dev_supported_ptypes_get = nfp_net_supported_ptypes_get,
766646ea79cSHeinrich Kuhn 	.mtu_set                = nfp_net_dev_mtu_set,
7670a94d6bcSJin Liu 	.mac_addr_set           = nfp_net_set_mac_addr,
768646ea79cSHeinrich Kuhn 	.vlan_offload_set       = nfp_net_vlan_offload_set,
769646ea79cSHeinrich Kuhn 	.reta_update            = nfp_net_reta_update,
770646ea79cSHeinrich Kuhn 	.reta_query             = nfp_net_reta_query,
771646ea79cSHeinrich Kuhn 	.rss_hash_update        = nfp_net_rss_hash_update,
772646ea79cSHeinrich Kuhn 	.rss_hash_conf_get      = nfp_net_rss_hash_conf_get,
773646ea79cSHeinrich Kuhn 	.rx_queue_setup         = nfp_net_rx_queue_setup,
774646ea79cSHeinrich Kuhn 	.rx_queue_release       = nfp_net_rx_queue_release,
7758d961320SJin Liu 	.tx_queue_setup         = nfp_net_tx_queue_setup,
77652ddc4c2SJin Liu 	.tx_queue_release       = nfp_net_tx_queue_release,
77752ddc4c2SJin Liu 	.rx_queue_intr_enable   = nfp_rx_queue_intr_enable,
77852ddc4c2SJin Liu 	.rx_queue_intr_disable  = nfp_rx_queue_intr_disable,
779c55abf61SChaoyong He 	.udp_tunnel_port_add    = nfp_udp_tunnel_port_add,
780c55abf61SChaoyong He 	.udp_tunnel_port_del    = nfp_udp_tunnel_port_del,
781128c8ad9SChaoyong He 	.fw_version_get         = nfp_net_firmware_version_get,
78251d15e82SZerun Fu 	.flow_ctrl_get          = nfp_net_flow_ctrl_get,
78368aa3537SZerun Fu 	.flow_ctrl_set          = nfp_net_flow_ctrl_set,
7840b9079d2SChaoyong He 	.flow_ops_get           = nfp_net_flow_ops_get,
7850786add9SZerun Fu 	.fec_get_capability     = nfp_net_fec_get_capability,
786c6835a32SZerun Fu 	.fec_get                = nfp_net_fec_get,
78737bd1b84SZerun Fu 	.fec_set                = nfp_net_fec_set,
78852ddc4c2SJin Liu };
78952ddc4c2SJin Liu 
790ee8ca64eSChaoyong He static inline void
791ee8ca64eSChaoyong He nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw,
792ee8ca64eSChaoyong He 		struct rte_eth_dev *eth_dev)
793266470b2SJin Liu {
794ee8ca64eSChaoyong He 	if (hw->ver.extend == NFP_NET_CFG_VERSION_DP_NFD3)
795ee8ca64eSChaoyong He 		eth_dev->tx_pkt_burst = nfp_net_nfd3_xmit_pkts;
796ee8ca64eSChaoyong He 	else
797ee8ca64eSChaoyong He 		eth_dev->tx_pkt_burst = nfp_net_nfdk_xmit_pkts;
798266470b2SJin Liu 
7998d961320SJin Liu 	eth_dev->dev_ops = &nfp_net_eth_dev_ops;
800266470b2SJin Liu 	eth_dev->rx_queue_count = nfp_net_rx_queue_count;
801266470b2SJin Liu 	eth_dev->rx_pkt_burst = &nfp_net_recv_pkts;
802266470b2SJin Liu }
803266470b2SJin Liu 
804646ea79cSHeinrich Kuhn static int
805646ea79cSHeinrich Kuhn nfp_net_init(struct rte_eth_dev *eth_dev)
806646ea79cSHeinrich Kuhn {
80749952141SChaoyong He 	int err;
80849952141SChaoyong He 	uint16_t port;
8090314a8ffSChaoyong He 	uint64_t rx_base;
8100314a8ffSChaoyong He 	uint64_t tx_base;
8114a9bb682SChaoyong He 	struct nfp_hw *hw;
8124a9bb682SChaoyong He 	struct nfp_net_hw *net_hw;
81349952141SChaoyong He 	struct nfp_pf_dev *pf_dev;
81449952141SChaoyong He 	struct rte_pci_device *pci_dev;
81549952141SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
816646ea79cSHeinrich Kuhn 
817646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
81865f6915dSChaoyong He 	net_hw = eth_dev->data->dev_private;
819646ea79cSHeinrich Kuhn 
820646ea79cSHeinrich Kuhn 	/* Use backpointer here to the PF of this eth_dev */
82165f6915dSChaoyong He 	pf_dev = net_hw->pf_dev;
822646ea79cSHeinrich Kuhn 
823968ec1c3SChaoyong He 	/* Use backpointer to the CoreNIC app struct */
824968ec1c3SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
825968ec1c3SChaoyong He 
826646ea79cSHeinrich Kuhn 	port = ((struct nfp_net_hw *)eth_dev->data->dev_private)->idx;
8278ceb85c3SChaoyong He 	if (port > 7) {
828646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "Port value is wrong");
829646ea79cSHeinrich Kuhn 		return -ENODEV;
830646ea79cSHeinrich Kuhn 	}
831646ea79cSHeinrich Kuhn 
8324a9bb682SChaoyong He 	hw = &net_hw->super;
833646ea79cSHeinrich Kuhn 
834030b2b19SChaoyong He 	PMD_INIT_LOG(DEBUG, "Working with physical port number: %hu, "
8354a9bb682SChaoyong He 			"NFP internal port number: %d", port, net_hw->nfp_idx);
836646ea79cSHeinrich Kuhn 
837646ea79cSHeinrich Kuhn 	rte_eth_copy_pci_info(eth_dev, pci_dev);
838646ea79cSHeinrich Kuhn 
8398ad2cc8fSPeng Zhang 	if (port == 0 || pf_dev->multi_pf.enabled) {
840f26e8239SJames Hershaw 		uint32_t min_size;
841f26e8239SJames Hershaw 
8424a9bb682SChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar;
8434a9bb682SChaoyong He 		min_size = NFP_MAC_STATS_SIZE * net_hw->pf_dev->nfp_eth_table->max_index;
8444a9bb682SChaoyong He 		net_hw->mac_stats_bar = nfp_rtsym_map(net_hw->pf_dev->sym_tbl, "_mac_stats",
8454a9bb682SChaoyong He 				min_size, &net_hw->mac_stats_area);
8464a9bb682SChaoyong He 		if (net_hw->mac_stats_bar == NULL) {
847f26e8239SJames Hershaw 			PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for _mac_stats_bar");
848f26e8239SJames Hershaw 			return -EIO;
849f26e8239SJames Hershaw 		}
850b0c496abSChaoyong He 
8514a9bb682SChaoyong He 		net_hw->mac_stats = net_hw->mac_stats_bar;
852646ea79cSHeinrich Kuhn 	} else {
853a6189a67SJin Liu 		/* Use port offset in pf ctrl_bar for this ports control bar */
8544a9bb682SChaoyong He 		hw->ctrl_bar = pf_dev->ctrl_bar + (port * NFP_NET_CFG_BAR_SZ);
8554a9bb682SChaoyong He 		net_hw->mac_stats = app_fw_nic->ports[0]->mac_stats_bar +
8564a9bb682SChaoyong He 				(net_hw->nfp_idx * NFP_MAC_STATS_SIZE);
857646ea79cSHeinrich Kuhn 	}
858646ea79cSHeinrich Kuhn 
8594a9bb682SChaoyong He 	PMD_INIT_LOG(DEBUG, "ctrl bar: %p", hw->ctrl_bar);
8604a9bb682SChaoyong He 	PMD_INIT_LOG(DEBUG, "MAC stats: %p", net_hw->mac_stats);
861646ea79cSHeinrich Kuhn 
8624a9bb682SChaoyong He 	err = nfp_net_common_init(pci_dev, net_hw);
863cd4397ebSPeng Zhang 	if (err != 0)
86436994566SChaoyong He 		goto free_area;
865fd392f84SPeng Zhang 
866eecdfcc1SShihong Wang 	err = nfp_net_tlv_caps_parse(eth_dev);
867eecdfcc1SShihong Wang 	if (err != 0) {
868eecdfcc1SShihong Wang 		PMD_INIT_LOG(ERR, "Failed to parser TLV caps");
869eecdfcc1SShihong Wang 		return err;
87036994566SChaoyong He 		goto free_area;
871eecdfcc1SShihong Wang 	}
872eecdfcc1SShihong Wang 
87354713740SChang Miao 	err = nfp_ipsec_init(eth_dev);
87454713740SChang Miao 	if (err != 0) {
87554713740SChang Miao 		PMD_INIT_LOG(ERR, "Failed to init IPsec module");
87636994566SChaoyong He 		goto free_area;
87754713740SChang Miao 	}
87854713740SChang Miao 
8794a9bb682SChaoyong He 	nfp_net_ethdev_ops_mount(net_hw, eth_dev);
880266470b2SJin Liu 
8814a9bb682SChaoyong He 	net_hw->eth_xstats_base = rte_malloc("rte_eth_xstat", sizeof(struct rte_eth_xstat) *
882f26e8239SJames Hershaw 			nfp_net_xstats_size(eth_dev), 0);
8834a9bb682SChaoyong He 	if (net_hw->eth_xstats_base == NULL) {
884f26e8239SJames Hershaw 		PMD_INIT_LOG(ERR, "no memory for xstats base values on device %s!",
885f26e8239SJames Hershaw 				pci_dev->device.name);
88636994566SChaoyong He 		err = -ENOMEM;
88736994566SChaoyong He 		goto ipsec_exit;
888f26e8239SJames Hershaw 	}
889f26e8239SJames Hershaw 
890646ea79cSHeinrich Kuhn 	/* Work out where in the BAR the queues start. */
8914a9bb682SChaoyong He 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
8924a9bb682SChaoyong He 	rx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_RXQ);
893646ea79cSHeinrich Kuhn 
8944a9bb682SChaoyong He 	net_hw->tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
8954a9bb682SChaoyong He 	net_hw->rx_bar = pf_dev->qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ;
8964a9bb682SChaoyong He 	eth_dev->data->dev_private = net_hw;
897646ea79cSHeinrich Kuhn 
898646ea79cSHeinrich Kuhn 	PMD_INIT_LOG(DEBUG, "ctrl_bar: %p, tx_bar: %p, rx_bar: %p",
8994a9bb682SChaoyong He 			hw->ctrl_bar, net_hw->tx_bar, net_hw->rx_bar);
900646ea79cSHeinrich Kuhn 
9014a9bb682SChaoyong He 	nfp_net_cfg_queue_setup(net_hw);
9024a9bb682SChaoyong He 	net_hw->mtu = RTE_ETHER_MTU;
903646ea79cSHeinrich Kuhn 
904646ea79cSHeinrich Kuhn 	/* VLAN insertion is incompatible with LSOv2 */
9054a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LSO2) != 0)
9064a9bb682SChaoyong He 		hw->cap &= ~NFP_NET_CFG_CTRL_TXVLAN;
907646ea79cSHeinrich Kuhn 
9084a9bb682SChaoyong He 	nfp_net_log_device_information(net_hw);
909646ea79cSHeinrich Kuhn 
910646ea79cSHeinrich Kuhn 	/* Initializing spinlock for reconfigs */
9114a9bb682SChaoyong He 	rte_spinlock_init(&hw->reconfig_lock);
912646ea79cSHeinrich Kuhn 
913646ea79cSHeinrich Kuhn 	/* Allocating memory for mac addr */
914f4d24fe9SChaoyong He 	eth_dev->data->mac_addrs = rte_zmalloc("mac_addr", RTE_ETHER_ADDR_LEN, 0);
915646ea79cSHeinrich Kuhn 	if (eth_dev->data->mac_addrs == NULL) {
916646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Failed to space for MAC address");
91736994566SChaoyong He 		err = -ENOMEM;
91836994566SChaoyong He 		goto xstats_free;
919646ea79cSHeinrich Kuhn 	}
920646ea79cSHeinrich Kuhn 
921968ec1c3SChaoyong He 	nfp_net_pf_read_mac(app_fw_nic, port);
922503ac807SChaoyong He 	nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
923646ea79cSHeinrich Kuhn 
9244a9bb682SChaoyong He 	if (rte_is_valid_assigned_ether_addr(&hw->mac_addr) == 0) {
925a6189a67SJin Liu 		PMD_INIT_LOG(INFO, "Using random mac address for port %d", port);
926646ea79cSHeinrich Kuhn 		/* Using random mac addresses for VFs */
9274a9bb682SChaoyong He 		rte_eth_random_addr(&hw->mac_addr.addr_bytes[0]);
928503ac807SChaoyong He 		nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]);
929646ea79cSHeinrich Kuhn 	}
930646ea79cSHeinrich Kuhn 
931646ea79cSHeinrich Kuhn 	/* Copying mac address to DPDK eth_dev struct */
9324a9bb682SChaoyong He 	rte_ether_addr_copy(&hw->mac_addr, eth_dev->data->mac_addrs);
933646ea79cSHeinrich Kuhn 
9344a9bb682SChaoyong He 	if ((hw->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) == 0)
935646ea79cSHeinrich Kuhn 		eth_dev->data->dev_flags |= RTE_ETH_DEV_NOLIVE_MAC_ADDR;
936646ea79cSHeinrich Kuhn 
937646ea79cSHeinrich Kuhn 	eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
938646ea79cSHeinrich Kuhn 
939030b2b19SChaoyong He 	PMD_INIT_LOG(INFO, "port %d VendorID=%#x DeviceID=%#x "
940c2c4f87bSAman Deep Singh 			"mac=" RTE_ETHER_ADDR_PRT_FMT,
941646ea79cSHeinrich Kuhn 			eth_dev->data->port_id, pci_dev->id.vendor_id,
942646ea79cSHeinrich Kuhn 			pci_dev->id.device_id,
9434a9bb682SChaoyong He 			RTE_ETHER_ADDR_BYTES(&hw->mac_addr));
944646ea79cSHeinrich Kuhn 
945646ea79cSHeinrich Kuhn 	/* Registering LSC interrupt handler */
946d61138d4SHarman Kalra 	rte_intr_callback_register(pci_dev->intr_handle,
947a6189a67SJin Liu 			nfp_net_dev_interrupt_handler, (void *)eth_dev);
948646ea79cSHeinrich Kuhn 	/* Telling the firmware about the LSC interrupt entry */
9494a9bb682SChaoyong He 	nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX);
95094d0631aSPeng Zhang 	/* Unmask the LSC interrupt */
95194d0631aSPeng Zhang 	nfp_net_irq_unmask(eth_dev);
952646ea79cSHeinrich Kuhn 	/* Recording current stats counters values */
953646ea79cSHeinrich Kuhn 	nfp_net_stats_reset(eth_dev);
954646ea79cSHeinrich Kuhn 
9558153bc6fSChaoyong He 	if ((hw->cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) {
9568153bc6fSChaoyong He 		err = nfp_net_flow_priv_init(pf_dev, port);
9578153bc6fSChaoyong He 		if (err != 0) {
9588153bc6fSChaoyong He 			PMD_INIT_LOG(ERR, "Init net flow priv failed");
9598153bc6fSChaoyong He 			goto xstats_free;
9608153bc6fSChaoyong He 		}
9618153bc6fSChaoyong He 	}
9628153bc6fSChaoyong He 
963646ea79cSHeinrich Kuhn 	return 0;
96436994566SChaoyong He 
96536994566SChaoyong He xstats_free:
96636994566SChaoyong He 	rte_free(net_hw->eth_xstats_base);
96736994566SChaoyong He ipsec_exit:
96836994566SChaoyong He 	nfp_ipsec_uninit(eth_dev);
96936994566SChaoyong He free_area:
97036994566SChaoyong He 	if (net_hw->mac_stats_area != NULL)
97136994566SChaoyong He 		nfp_cpp_area_release_free(net_hw->mac_stats_area);
97236994566SChaoyong He 
97336994566SChaoyong He 	return err;
974646ea79cSHeinrich Kuhn }
975646ea79cSHeinrich Kuhn 
976646ea79cSHeinrich Kuhn #define DEFAULT_FW_PATH       "/lib/firmware/netronome"
977646ea79cSHeinrich Kuhn 
978646ea79cSHeinrich Kuhn static int
979ebfb540eSPeng Zhang nfp_fw_get_name(struct rte_pci_device *dev,
980f4d24fe9SChaoyong He 		struct nfp_nsp *nsp,
981ebfb540eSPeng Zhang 		char *card,
982ebfb540eSPeng Zhang 		char *fw_name,
983ebfb540eSPeng Zhang 		size_t fw_size)
984646ea79cSHeinrich Kuhn {
98549952141SChaoyong He 	char serial[40];
986ff627b74SChaoyong He 	uint16_t interface;
987ff627b74SChaoyong He 	uint32_t cpp_serial_len;
988ff627b74SChaoyong He 	const uint8_t *cpp_serial;
98949952141SChaoyong He 	struct nfp_cpp *cpp = nfp_nsp_cpp(nsp);
990ff627b74SChaoyong He 
991ff627b74SChaoyong He 	cpp_serial_len = nfp_cpp_serial(cpp, &cpp_serial);
992ff627b74SChaoyong He 	if (cpp_serial_len != NFP_SERIAL_LEN)
993ff627b74SChaoyong He 		return -ERANGE;
994ff627b74SChaoyong He 
995ff627b74SChaoyong He 	interface = nfp_cpp_interface(cpp);
996646ea79cSHeinrich Kuhn 
997646ea79cSHeinrich Kuhn 	/* Looking for firmware file in order of priority */
998646ea79cSHeinrich Kuhn 
999646ea79cSHeinrich Kuhn 	/* First try to find a firmware image specific for this device */
1000646ea79cSHeinrich Kuhn 	snprintf(serial, sizeof(serial),
1001646ea79cSHeinrich Kuhn 			"serial-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
1002ff627b74SChaoyong He 			cpp_serial[0], cpp_serial[1], cpp_serial[2], cpp_serial[3],
1003ff627b74SChaoyong He 			cpp_serial[4], cpp_serial[5], interface >> 8, interface & 0xff);
1004ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/%s.nffw", DEFAULT_FW_PATH, serial);
1005646ea79cSHeinrich Kuhn 
1006646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1007ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1008ebfb540eSPeng Zhang 		return 0;
1009b0c496abSChaoyong He 
1010646ea79cSHeinrich Kuhn 	/* Then try the PCI name */
1011ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/pci-%s.nffw", DEFAULT_FW_PATH,
10123ddb4cc0SPeng Zhang 			dev->name);
1013646ea79cSHeinrich Kuhn 
1014646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1015ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1016ebfb540eSPeng Zhang 		return 0;
1017646ea79cSHeinrich Kuhn 
1018646ea79cSHeinrich Kuhn 	/* Finally try the card type and media */
1019ebfb540eSPeng Zhang 	snprintf(fw_name, fw_size, "%s/%s", DEFAULT_FW_PATH, card);
1020646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name);
1021ebfb540eSPeng Zhang 	if (access(fw_name, F_OK) == 0)
1022ebfb540eSPeng Zhang 		return 0;
1023c01e5c0cSChaoyong He 
1024646ea79cSHeinrich Kuhn 	return -ENOENT;
1025ebfb540eSPeng Zhang }
1026646ea79cSHeinrich Kuhn 
1027ebfb540eSPeng Zhang static int
1028ebfb540eSPeng Zhang nfp_fw_upload(struct nfp_nsp *nsp,
1029ebfb540eSPeng Zhang 		char *fw_name)
1030ebfb540eSPeng Zhang {
1031ebfb540eSPeng Zhang 	int err;
1032ebfb540eSPeng Zhang 	void *fw_buf;
1033ebfb540eSPeng Zhang 	size_t fsize;
1034ebfb540eSPeng Zhang 
1035ebfb540eSPeng Zhang 	err = rte_firmware_read(fw_name, &fw_buf, &fsize);
1036ebfb540eSPeng Zhang 	if (err != 0) {
1037ebfb540eSPeng Zhang 		PMD_DRV_LOG(ERR, "firmware %s not found!", fw_name);
1038ebfb540eSPeng Zhang 		return -ENOENT;
1039ebfb540eSPeng Zhang 	}
1040ebfb540eSPeng Zhang 
1041646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %zu",
1042646ea79cSHeinrich Kuhn 			fw_name, fsize);
1043646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Uploading the firmware ...");
10442e634b03SPeng Zhang 	if (nfp_nsp_load_fw(nsp, fw_buf, fsize) < 0) {
10452e634b03SPeng Zhang 		free(fw_buf);
10462e634b03SPeng Zhang 		PMD_DRV_LOG(ERR, "Firmware load failed.");
10472e634b03SPeng Zhang 		return -EIO;
10482e634b03SPeng Zhang 	}
10492e634b03SPeng Zhang 
1050646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Done");
1051646ea79cSHeinrich Kuhn 
1052646ea79cSHeinrich Kuhn 	free(fw_buf);
1053646ea79cSHeinrich Kuhn 
1054646ea79cSHeinrich Kuhn 	return 0;
1055646ea79cSHeinrich Kuhn }
1056646ea79cSHeinrich Kuhn 
10573b00109dSPeng Zhang static void
10583b00109dSPeng Zhang nfp_fw_unload(struct nfp_cpp *cpp)
10593b00109dSPeng Zhang {
10603b00109dSPeng Zhang 	struct nfp_nsp *nsp;
10613b00109dSPeng Zhang 
10623b00109dSPeng Zhang 	nsp = nfp_nsp_open(cpp);
10633b00109dSPeng Zhang 	if (nsp == NULL)
10643b00109dSPeng Zhang 		return;
10653b00109dSPeng Zhang 
10663b00109dSPeng Zhang 	nfp_nsp_device_soft_reset(nsp);
10673b00109dSPeng Zhang 	nfp_nsp_close(nsp);
10683b00109dSPeng Zhang }
10693b00109dSPeng Zhang 
1070646ea79cSHeinrich Kuhn static int
1071ebfb540eSPeng Zhang nfp_fw_reload(struct nfp_nsp *nsp,
1072ebfb540eSPeng Zhang 		char *fw_name)
10738ba461d1SPeng Zhang {
10748ba461d1SPeng Zhang 	int err;
10758ba461d1SPeng Zhang 
10768ba461d1SPeng Zhang 	nfp_nsp_device_soft_reset(nsp);
1077ebfb540eSPeng Zhang 	err = nfp_fw_upload(nsp, fw_name);
10788ba461d1SPeng Zhang 	if (err != 0)
10798ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP firmware load failed");
10808ba461d1SPeng Zhang 
10818ba461d1SPeng Zhang 	return err;
10828ba461d1SPeng Zhang }
10838ba461d1SPeng Zhang 
1084a99ca614SPeng Zhang static bool
1085a99ca614SPeng Zhang nfp_fw_skip_load(const struct nfp_dev_info *dev_info,
10868ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
10878ba461d1SPeng Zhang {
108874397a7aSPeng Zhang 	uint8_t i;
108974397a7aSPeng Zhang 	uint64_t tmp_beat;
10908ba461d1SPeng Zhang 	uint32_t port_num;
10918b9a83eaSPeng Zhang 	uint8_t in_use = 0;
109274397a7aSPeng Zhang 	uint64_t beat[dev_info->pf_num_per_unit];
109374397a7aSPeng Zhang 	uint32_t offset[dev_info->pf_num_per_unit];
10948b9a83eaSPeng Zhang 	uint8_t abnormal = dev_info->pf_num_per_unit;
109574397a7aSPeng Zhang 
109674397a7aSPeng Zhang 	for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
109774397a7aSPeng Zhang 		offset[port_num] = NFP_BEAT_OFFSET(port_num);
109874397a7aSPeng Zhang 		beat[port_num] = nn_readq(multi_pf->beat_addr + offset[port_num]);
10998b9a83eaSPeng Zhang 		if (beat[port_num] == 0)
11008b9a83eaSPeng Zhang 			abnormal--;
110174397a7aSPeng Zhang 	}
11028ba461d1SPeng Zhang 
11038b9a83eaSPeng Zhang 	if (abnormal == 0)
11048b9a83eaSPeng Zhang 		return true;
11058b9a83eaSPeng Zhang 
110674397a7aSPeng Zhang 	for (i = 0; i < 3; i++) {
110774397a7aSPeng Zhang 		sleep(1);
11088ba461d1SPeng Zhang 		for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) {
11098ba461d1SPeng Zhang 			if (port_num == multi_pf->function_id)
11108ba461d1SPeng Zhang 				continue;
11118ba461d1SPeng Zhang 
11128b9a83eaSPeng Zhang 			if (beat[port_num] == 0)
11138b9a83eaSPeng Zhang 				continue;
11148b9a83eaSPeng Zhang 
111574397a7aSPeng Zhang 			tmp_beat = nn_readq(multi_pf->beat_addr + offset[port_num]);
11168b9a83eaSPeng Zhang 			if (tmp_beat != beat[port_num]) {
11178b9a83eaSPeng Zhang 				in_use++;
11188b9a83eaSPeng Zhang 				abnormal--;
11198b9a83eaSPeng Zhang 				beat[port_num] = 0;
11208b9a83eaSPeng Zhang 			}
11218b9a83eaSPeng Zhang 		}
11228b9a83eaSPeng Zhang 
11238b9a83eaSPeng Zhang 		if (abnormal == 0)
1124a99ca614SPeng Zhang 			return true;
11258ba461d1SPeng Zhang 	}
11268b9a83eaSPeng Zhang 
11278b9a83eaSPeng Zhang 	if (in_use != 0) {
11288b9a83eaSPeng Zhang 		PMD_DRV_LOG(WARNING, "Abnormal %u != 0, the nic has port which is exit abnormally.",
11298b9a83eaSPeng Zhang 				abnormal);
11308b9a83eaSPeng Zhang 		return true;
11318ba461d1SPeng Zhang 	}
11328ba461d1SPeng Zhang 
1133a99ca614SPeng Zhang 	return false;
11348ba461d1SPeng Zhang }
11358ba461d1SPeng Zhang 
11368ba461d1SPeng Zhang static int
1137ebfb540eSPeng Zhang nfp_fw_reload_for_multipf(struct nfp_nsp *nsp,
1138ebfb540eSPeng Zhang 		char *fw_name,
11398ba461d1SPeng Zhang 		struct nfp_cpp *cpp,
11408ba461d1SPeng Zhang 		const struct nfp_dev_info *dev_info,
11418ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
11428ba461d1SPeng Zhang {
11438ba461d1SPeng Zhang 	int err;
1144a99ca614SPeng Zhang 	bool skip_load_fw = false;
11458ba461d1SPeng Zhang 
11468ba461d1SPeng Zhang 	err = nfp_net_keepalive_init(cpp, multi_pf);
11478ba461d1SPeng Zhang 	if (err != 0) {
1148a99ca614SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP init beat failed");
11498ba461d1SPeng Zhang 		return err;
11508ba461d1SPeng Zhang 	}
11518ba461d1SPeng Zhang 
11528ba461d1SPeng Zhang 	err = nfp_net_keepalive_start(multi_pf);
11538ba461d1SPeng Zhang 	if (err != 0) {
11548ba461d1SPeng Zhang 		nfp_net_keepalive_uninit(multi_pf);
11558ba461d1SPeng Zhang 		PMD_DRV_LOG(ERR, "NFP write beat failed");
1156a99ca614SPeng Zhang 		return err;
11578ba461d1SPeng Zhang 	}
11588ba461d1SPeng Zhang 
1159a99ca614SPeng Zhang 	if (nfp_nsp_fw_loaded(nsp))
1160a99ca614SPeng Zhang 		skip_load_fw = nfp_fw_skip_load(dev_info, multi_pf);
1161a99ca614SPeng Zhang 
1162a99ca614SPeng Zhang 	if (skip_load_fw)
1163a99ca614SPeng Zhang 		return 0;
1164a99ca614SPeng Zhang 
1165a99ca614SPeng Zhang 	err = nfp_fw_reload(nsp, fw_name);
1166a99ca614SPeng Zhang 	if (err != 0) {
1167a99ca614SPeng Zhang 		nfp_net_keepalive_stop(multi_pf);
1168a99ca614SPeng Zhang 		nfp_net_keepalive_uninit(multi_pf);
11698ba461d1SPeng Zhang 		return err;
11708ba461d1SPeng Zhang 	}
11718ba461d1SPeng Zhang 
1172b67a7b40SPeng Zhang 	nfp_net_keepalive_clear_others(dev_info, multi_pf);
1173b67a7b40SPeng Zhang 
1174a99ca614SPeng Zhang 	return 0;
1175a99ca614SPeng Zhang }
1176a99ca614SPeng Zhang 
11778ba461d1SPeng Zhang static int
1178a6189a67SJin Liu nfp_fw_setup(struct rte_pci_device *dev,
1179a6189a67SJin Liu 		struct nfp_cpp *cpp,
1180a6189a67SJin Liu 		struct nfp_eth_table *nfp_eth_table,
11818ba461d1SPeng Zhang 		struct nfp_hwinfo *hwinfo,
11828ba461d1SPeng Zhang 		const struct nfp_dev_info *dev_info,
11838ba461d1SPeng Zhang 		struct nfp_multi_pf *multi_pf)
1184646ea79cSHeinrich Kuhn {
118549952141SChaoyong He 	int err;
1186ebfb540eSPeng Zhang 	char fw_name[125];
118749952141SChaoyong He 	char card_desc[100];
1188646ea79cSHeinrich Kuhn 	struct nfp_nsp *nsp;
1189646ea79cSHeinrich Kuhn 	const char *nfp_fw_model;
1190646ea79cSHeinrich Kuhn 
119106be30d4SPeng Zhang 	nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "nffw.partno");
119206be30d4SPeng Zhang 	if (nfp_fw_model == NULL)
1193646ea79cSHeinrich Kuhn 		nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "assembly.partno");
1194646ea79cSHeinrich Kuhn 
1195c01e5c0cSChaoyong He 	if (nfp_fw_model != NULL) {
1196646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(INFO, "firmware model found: %s", nfp_fw_model);
1197646ea79cSHeinrich Kuhn 	} else {
1198646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "firmware model NOT found");
1199646ea79cSHeinrich Kuhn 		return -EIO;
1200646ea79cSHeinrich Kuhn 	}
1201646ea79cSHeinrich Kuhn 
1202646ea79cSHeinrich Kuhn 	if (nfp_eth_table->count == 0 || nfp_eth_table->count > 8) {
1203646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "NFP ethernet table reports wrong ports: %u",
1204646ea79cSHeinrich Kuhn 				nfp_eth_table->count);
1205646ea79cSHeinrich Kuhn 		return -EIO;
1206646ea79cSHeinrich Kuhn 	}
1207646ea79cSHeinrich Kuhn 
1208646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "NFP ethernet port table reports %u ports",
1209646ea79cSHeinrich Kuhn 			nfp_eth_table->count);
1210646ea79cSHeinrich Kuhn 
1211646ea79cSHeinrich Kuhn 	PMD_DRV_LOG(INFO, "Port speed: %u", nfp_eth_table->ports[0].speed);
1212646ea79cSHeinrich Kuhn 
1213646ea79cSHeinrich Kuhn 	snprintf(card_desc, sizeof(card_desc), "nic_%s_%dx%d.nffw",
1214646ea79cSHeinrich Kuhn 			nfp_fw_model, nfp_eth_table->count,
1215646ea79cSHeinrich Kuhn 			nfp_eth_table->ports[0].speed / 1000);
1216646ea79cSHeinrich Kuhn 
1217646ea79cSHeinrich Kuhn 	nsp = nfp_nsp_open(cpp);
1218a6189a67SJin Liu 	if (nsp == NULL) {
1219646ea79cSHeinrich Kuhn 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle");
1220646ea79cSHeinrich Kuhn 		return -EIO;
1221646ea79cSHeinrich Kuhn 	}
1222646ea79cSHeinrich Kuhn 
1223ebfb540eSPeng Zhang 	err = nfp_fw_get_name(dev, nsp, card_desc, fw_name, sizeof(fw_name));
1224ebfb540eSPeng Zhang 	if (err != 0) {
1225ebfb540eSPeng Zhang 		PMD_DRV_LOG(ERR, "Can't find suitable firmware.");
1226ebfb540eSPeng Zhang 		nfp_nsp_close(nsp);
1227ebfb540eSPeng Zhang 		return err;
1228ebfb540eSPeng Zhang 	}
1229ebfb540eSPeng Zhang 
12308ba461d1SPeng Zhang 	if (multi_pf->enabled)
1231ebfb540eSPeng Zhang 		err = nfp_fw_reload_for_multipf(nsp, fw_name, cpp, dev_info, multi_pf);
12328ba461d1SPeng Zhang 	else
1233ebfb540eSPeng Zhang 		err = nfp_fw_reload(nsp, fw_name);
1234646ea79cSHeinrich Kuhn 
1235646ea79cSHeinrich Kuhn 	nfp_nsp_close(nsp);
1236646ea79cSHeinrich Kuhn 	return err;
1237646ea79cSHeinrich Kuhn }
1238646ea79cSHeinrich Kuhn 
12398ad2cc8fSPeng Zhang static inline bool
1240a508fa23SPeng Zhang nfp_check_multi_pf_from_fw(uint32_t total_vnics)
1241a508fa23SPeng Zhang {
1242a508fa23SPeng Zhang 	if (total_vnics == 1)
1243a508fa23SPeng Zhang 		return true;
1244a508fa23SPeng Zhang 
1245a508fa23SPeng Zhang 	return false;
1246a508fa23SPeng Zhang }
1247a508fa23SPeng Zhang 
1248a508fa23SPeng Zhang static inline bool
12498ad2cc8fSPeng Zhang nfp_check_multi_pf_from_nsp(struct rte_pci_device *pci_dev,
12508ad2cc8fSPeng Zhang 		struct nfp_cpp *cpp)
12518ad2cc8fSPeng Zhang {
12528ad2cc8fSPeng Zhang 	bool flag;
12538ad2cc8fSPeng Zhang 	struct nfp_nsp *nsp;
12548ad2cc8fSPeng Zhang 
12558ad2cc8fSPeng Zhang 	nsp = nfp_nsp_open(cpp);
12568ad2cc8fSPeng Zhang 	if (nsp == NULL) {
12578ad2cc8fSPeng Zhang 		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle");
12588ad2cc8fSPeng Zhang 		return false;
12598ad2cc8fSPeng Zhang 	}
12608ad2cc8fSPeng Zhang 
12618ad2cc8fSPeng Zhang 	flag = (nfp_nsp_get_abi_ver_major(nsp) > 0) &&
12628ad2cc8fSPeng Zhang 			(pci_dev->id.device_id == PCI_DEVICE_ID_NFP3800_PF_NIC);
12638ad2cc8fSPeng Zhang 
12648ad2cc8fSPeng Zhang 	nfp_nsp_close(nsp);
12658ad2cc8fSPeng Zhang 	return flag;
12668ad2cc8fSPeng Zhang }
12678ad2cc8fSPeng Zhang 
1268a6189a67SJin Liu static int
126995f978efSPeng Zhang nfp_enable_multi_pf(struct nfp_pf_dev *pf_dev)
127095f978efSPeng Zhang {
127195f978efSPeng Zhang 	int err = 0;
127295f978efSPeng Zhang 	uint64_t tx_base;
127395f978efSPeng Zhang 	uint8_t *ctrl_bar;
127495f978efSPeng Zhang 	struct nfp_hw *hw;
127595f978efSPeng Zhang 	uint32_t cap_extend;
127695f978efSPeng Zhang 	struct nfp_net_hw net_hw;
127795f978efSPeng Zhang 	struct nfp_cpp_area *area;
127895f978efSPeng Zhang 	char name[RTE_ETH_NAME_MAX_LEN];
127995f978efSPeng Zhang 
128095f978efSPeng Zhang 	memset(&net_hw, 0, sizeof(struct nfp_net_hw));
128195f978efSPeng Zhang 
128295f978efSPeng Zhang 	/* Map the symbol table */
128395f978efSPeng Zhang 	snprintf(name, sizeof(name), "_pf%u_net_bar0",
128495f978efSPeng Zhang 			pf_dev->multi_pf.function_id);
128595f978efSPeng Zhang 	ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, name, NFP_NET_CFG_BAR_SZ,
128695f978efSPeng Zhang 			&area);
128795f978efSPeng Zhang 	if (ctrl_bar == NULL) {
128895f978efSPeng Zhang 		PMD_INIT_LOG(ERR, "Failed to find data vNIC memory symbol");
128995f978efSPeng Zhang 		return -ENODEV;
129095f978efSPeng Zhang 	}
129195f978efSPeng Zhang 
129295f978efSPeng Zhang 	hw = &net_hw.super;
129395f978efSPeng Zhang 	hw->ctrl_bar = ctrl_bar;
129495f978efSPeng Zhang 
129595f978efSPeng Zhang 	cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1);
129695f978efSPeng Zhang 	if ((cap_extend & NFP_NET_CFG_CTRL_MULTI_PF) == 0) {
129795f978efSPeng Zhang 		PMD_INIT_LOG(ERR, "Loaded firmware doesn't support multiple PF");
129895f978efSPeng Zhang 		err = -EINVAL;
129995f978efSPeng Zhang 		goto end;
130095f978efSPeng Zhang 	}
130195f978efSPeng Zhang 
130295f978efSPeng Zhang 	tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ);
130395f978efSPeng Zhang 	net_hw.tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ;
130495f978efSPeng Zhang 	nfp_net_cfg_queue_setup(&net_hw);
130595f978efSPeng Zhang 	rte_spinlock_init(&hw->reconfig_lock);
130695f978efSPeng Zhang 	nfp_ext_reconfig(&net_hw.super, NFP_NET_CFG_CTRL_MULTI_PF, NFP_NET_CFG_UPDATE_GEN);
130795f978efSPeng Zhang end:
130895f978efSPeng Zhang 	nfp_cpp_area_release_free(area);
130995f978efSPeng Zhang 	return err;
131095f978efSPeng Zhang }
131195f978efSPeng Zhang 
131295f978efSPeng Zhang static int
13130314a8ffSChaoyong He nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev,
13140314a8ffSChaoyong He 		const struct nfp_dev_info *dev_info)
1315646ea79cSHeinrich Kuhn {
13168ceb85c3SChaoyong He 	uint8_t i;
13173b00109dSPeng Zhang 	uint8_t id;
1318e7978635SChaoyong He 	int ret = 0;
13198ceb85c3SChaoyong He 	uint32_t total_vnics;
1320646ea79cSHeinrich Kuhn 	struct nfp_net_hw *hw;
1321968ec1c3SChaoyong He 	unsigned int numa_node;
1322646ea79cSHeinrich Kuhn 	struct rte_eth_dev *eth_dev;
1323968ec1c3SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
1324a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
13253b00109dSPeng Zhang 	char bar_name[RTE_ETH_NAME_MAX_LEN];
1326646ea79cSHeinrich Kuhn 	char port_name[RTE_ETH_NAME_MAX_LEN];
13273b00109dSPeng Zhang 	char vnic_name[RTE_ETH_NAME_MAX_LEN];
1328646ea79cSHeinrich Kuhn 
1329968ec1c3SChaoyong He 	nfp_eth_table = pf_dev->nfp_eth_table;
1330968ec1c3SChaoyong He 	PMD_INIT_LOG(INFO, "Total physical ports: %d", nfp_eth_table->count);
13313b00109dSPeng Zhang 	id = nfp_function_id_get(pf_dev, 0);
1332968ec1c3SChaoyong He 
1333968ec1c3SChaoyong He 	/* Allocate memory for the CoreNIC app */
1334968ec1c3SChaoyong He 	app_fw_nic = rte_zmalloc("nfp_app_fw_nic", sizeof(*app_fw_nic), 0);
1335968ec1c3SChaoyong He 	if (app_fw_nic == NULL)
1336968ec1c3SChaoyong He 		return -ENOMEM;
1337968ec1c3SChaoyong He 
1338968ec1c3SChaoyong He 	/* Point the app_fw_priv pointer in the PF to the coreNIC app */
1339968ec1c3SChaoyong He 	pf_dev->app_fw_priv = app_fw_nic;
1340968ec1c3SChaoyong He 
1341968ec1c3SChaoyong He 	/* Read the number of vNIC's created for the PF */
13423b00109dSPeng Zhang 	snprintf(vnic_name, sizeof(vnic_name), "nfd_cfg_pf%u_num_ports", id);
13433b00109dSPeng Zhang 	total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, vnic_name, &ret);
1344e7978635SChaoyong He 	if (ret != 0 || total_vnics == 0 || total_vnics > 8) {
13453b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "%s symbol with wrong value", vnic_name);
1346968ec1c3SChaoyong He 		ret = -ENODEV;
1347968ec1c3SChaoyong He 		goto app_cleanup;
1348968ec1c3SChaoyong He 	}
1349968ec1c3SChaoyong He 
1350a508fa23SPeng Zhang 	if (pf_dev->multi_pf.enabled) {
1351a508fa23SPeng Zhang 		if (!nfp_check_multi_pf_from_fw(total_vnics)) {
1352a508fa23SPeng Zhang 			PMD_INIT_LOG(ERR, "NSP report multipf, but FW report not multipf");
1353a508fa23SPeng Zhang 			ret = -ENODEV;
1354a508fa23SPeng Zhang 			goto app_cleanup;
1355a508fa23SPeng Zhang 		}
1356a508fa23SPeng Zhang 	} else {
1357968ec1c3SChaoyong He 		/*
1358968ec1c3SChaoyong He 		 * For coreNIC the number of vNICs exposed should be the same as the
135940688372SChaoyong He 		 * number of physical ports.
1360968ec1c3SChaoyong He 		 */
13618ceb85c3SChaoyong He 		if (total_vnics != nfp_eth_table->count) {
1362968ec1c3SChaoyong He 			PMD_INIT_LOG(ERR, "Total physical ports do not match number of vNICs");
1363968ec1c3SChaoyong He 			ret = -ENODEV;
1364968ec1c3SChaoyong He 			goto app_cleanup;
1365968ec1c3SChaoyong He 		}
1366a508fa23SPeng Zhang 	}
1367968ec1c3SChaoyong He 
1368968ec1c3SChaoyong He 	/* Populate coreNIC app properties */
1369968ec1c3SChaoyong He 	app_fw_nic->total_phyports = total_vnics;
1370968ec1c3SChaoyong He 	app_fw_nic->pf_dev = pf_dev;
1371968ec1c3SChaoyong He 	if (total_vnics > 1)
1372968ec1c3SChaoyong He 		app_fw_nic->multiport = true;
1373968ec1c3SChaoyong He 
1374968ec1c3SChaoyong He 	/* Map the symbol table */
13753b00109dSPeng Zhang 	snprintf(bar_name, sizeof(bar_name), "_pf%u_net_bar0", id);
13763b00109dSPeng Zhang 	pf_dev->ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, bar_name,
1377d5e9fc86SChaoyong He 			app_fw_nic->total_phyports * NFP_NET_CFG_BAR_SZ,
1378d5e9fc86SChaoyong He 			&pf_dev->ctrl_area);
1379968ec1c3SChaoyong He 	if (pf_dev->ctrl_bar == NULL) {
13803b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for %s", bar_name);
1381968ec1c3SChaoyong He 		ret = -EIO;
1382968ec1c3SChaoyong He 		goto app_cleanup;
1383968ec1c3SChaoyong He 	}
1384968ec1c3SChaoyong He 
1385968ec1c3SChaoyong He 	PMD_INIT_LOG(DEBUG, "ctrl bar: %p", pf_dev->ctrl_bar);
1386968ec1c3SChaoyong He 
1387968ec1c3SChaoyong He 	/* Loop through all physical ports on PF */
1388968ec1c3SChaoyong He 	numa_node = rte_socket_id();
1389968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
1390*c92c83d4SPeng Zhang 		if (pf_dev->multi_pf.enabled)
1391*c92c83d4SPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s",
1392*c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name);
1393*c92c83d4SPeng Zhang 		else
13943b00109dSPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s_port%u",
1395*c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name, i);
1396646ea79cSHeinrich Kuhn 
1397646ea79cSHeinrich Kuhn 		/* Allocate a eth_dev for this phyport */
1398646ea79cSHeinrich Kuhn 		eth_dev = rte_eth_dev_allocate(port_name);
1399a6189a67SJin Liu 		if (eth_dev == NULL) {
1400646ea79cSHeinrich Kuhn 			ret = -ENODEV;
1401646ea79cSHeinrich Kuhn 			goto port_cleanup;
1402646ea79cSHeinrich Kuhn 		}
1403646ea79cSHeinrich Kuhn 
1404646ea79cSHeinrich Kuhn 		/* Allocate memory for this phyport */
1405f4d24fe9SChaoyong He 		eth_dev->data->dev_private = rte_zmalloc_socket(port_name,
1406f4d24fe9SChaoyong He 				sizeof(struct nfp_net_hw),
1407646ea79cSHeinrich Kuhn 				RTE_CACHE_LINE_SIZE, numa_node);
1408a6189a67SJin Liu 		if (eth_dev->data->dev_private == NULL) {
1409646ea79cSHeinrich Kuhn 			ret = -ENOMEM;
1410646ea79cSHeinrich Kuhn 			rte_eth_dev_release_port(eth_dev);
1411646ea79cSHeinrich Kuhn 			goto port_cleanup;
1412646ea79cSHeinrich Kuhn 		}
1413646ea79cSHeinrich Kuhn 
14149d723baaSChaoyong He 		hw = eth_dev->data->dev_private;
1415*c92c83d4SPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
1416646ea79cSHeinrich Kuhn 
1417646ea79cSHeinrich Kuhn 		/* Add this device to the PF's array of physical ports */
14183b00109dSPeng Zhang 		app_fw_nic->ports[id] = hw;
1419646ea79cSHeinrich Kuhn 
14200314a8ffSChaoyong He 		hw->dev_info = dev_info;
1421646ea79cSHeinrich Kuhn 		hw->pf_dev = pf_dev;
1422646ea79cSHeinrich Kuhn 		hw->cpp = pf_dev->cpp;
1423646ea79cSHeinrich Kuhn 		hw->eth_dev = eth_dev;
14243b00109dSPeng Zhang 		hw->idx = id;
14253b00109dSPeng Zhang 		hw->nfp_idx = nfp_eth_table->ports[id].index;
1426646ea79cSHeinrich Kuhn 
1427646ea79cSHeinrich Kuhn 		eth_dev->device = &pf_dev->pci_dev->device;
1428646ea79cSHeinrich Kuhn 
142940688372SChaoyong He 		/*
143040688372SChaoyong He 		 * Ctrl/tx/rx BAR mappings and remaining init happens in
143140688372SChaoyong He 		 * @nfp_net_init()
1432646ea79cSHeinrich Kuhn 		 */
1433646ea79cSHeinrich Kuhn 		ret = nfp_net_init(eth_dev);
1434c01e5c0cSChaoyong He 		if (ret != 0) {
1435646ea79cSHeinrich Kuhn 			ret = -ENODEV;
1436646ea79cSHeinrich Kuhn 			goto port_cleanup;
1437646ea79cSHeinrich Kuhn 		}
1438646ea79cSHeinrich Kuhn 
1439646ea79cSHeinrich Kuhn 		rte_eth_dev_probing_finish(eth_dev);
1440646ea79cSHeinrich Kuhn 
1441646ea79cSHeinrich Kuhn 	} /* End loop, all ports on this PF */
1442968ec1c3SChaoyong He 
1443968ec1c3SChaoyong He 	return 0;
1444646ea79cSHeinrich Kuhn 
1445646ea79cSHeinrich Kuhn port_cleanup:
1446968ec1c3SChaoyong He 	for (i = 0; i < app_fw_nic->total_phyports; i++) {
14473b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
14488153bc6fSChaoyong He 		hw = app_fw_nic->ports[id];
14493b00109dSPeng Zhang 
14508153bc6fSChaoyong He 		if (hw != NULL && hw->eth_dev != NULL) {
14518153bc6fSChaoyong He 			nfp_net_uninit(hw->eth_dev);
14528153bc6fSChaoyong He 			rte_eth_dev_release_port(hw->eth_dev);
1453646ea79cSHeinrich Kuhn 		}
1454646ea79cSHeinrich Kuhn 	}
14558b8f116bSChaoyong He 	nfp_cpp_area_release_free(pf_dev->ctrl_area);
1456968ec1c3SChaoyong He app_cleanup:
1457968ec1c3SChaoyong He 	rte_free(app_fw_nic);
1458a6189a67SJin Liu 
1459646ea79cSHeinrich Kuhn 	return ret;
1460646ea79cSHeinrich Kuhn }
1461646ea79cSHeinrich Kuhn 
1462a6189a67SJin Liu static int
1463c7a6970fSZerun Fu nfp_net_hwinfo_set(uint8_t function_id,
1464c7a6970fSZerun Fu 		struct nfp_rtsym_table *sym_tbl,
1465c7a6970fSZerun Fu 		struct nfp_cpp *cpp)
1466c7a6970fSZerun Fu {
1467c7a6970fSZerun Fu 	int ret = 0;
1468c7a6970fSZerun Fu 	uint64_t app_cap;
1469c7a6970fSZerun Fu 	uint8_t sp_indiff;
1470c7a6970fSZerun Fu 	struct nfp_nsp *nsp;
1471c7a6970fSZerun Fu 	char hw_info[RTE_ETH_NAME_MAX_LEN];
1472c7a6970fSZerun Fu 	char app_cap_name[RTE_ETH_NAME_MAX_LEN];
1473c7a6970fSZerun Fu 
1474c7a6970fSZerun Fu 	/* Read the app capabilities of the firmware loaded */
1475c7a6970fSZerun Fu 	snprintf(app_cap_name, sizeof(app_cap_name), "_pf%u_net_app_cap", function_id);
1476c7a6970fSZerun Fu 	app_cap = nfp_rtsym_read_le(sym_tbl, app_cap_name, &ret);
1477c7a6970fSZerun Fu 	if (ret != 0) {
1478c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Couldn't read app_fw_cap from firmware.");
1479c7a6970fSZerun Fu 		return ret;
1480c7a6970fSZerun Fu 	}
1481c7a6970fSZerun Fu 
1482c7a6970fSZerun Fu 	/* Calculate the value of sp_indiff and write to hw_info */
1483c7a6970fSZerun Fu 	sp_indiff = app_cap & NFP_NET_APP_CAP_SP_INDIFF;
1484c7a6970fSZerun Fu 	snprintf(hw_info, sizeof(hw_info), "sp_indiff=%u", sp_indiff);
1485c7a6970fSZerun Fu 
1486c7a6970fSZerun Fu 	nsp = nfp_nsp_open(cpp);
1487c7a6970fSZerun Fu 	if (nsp == NULL) {
1488c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Couldn't get NSP.");
1489c7a6970fSZerun Fu 		return -EIO;
1490c7a6970fSZerun Fu 	}
1491c7a6970fSZerun Fu 
1492c7a6970fSZerun Fu 	ret = nfp_nsp_hwinfo_set(nsp, hw_info, sizeof(hw_info));
1493c7a6970fSZerun Fu 	nfp_nsp_close(nsp);
1494c7a6970fSZerun Fu 	if (ret != 0) {
1495c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set parameter to hwinfo.");
1496c7a6970fSZerun Fu 		return ret;
1497c7a6970fSZerun Fu 	}
1498c7a6970fSZerun Fu 
1499c7a6970fSZerun Fu 	return 0;
1500c7a6970fSZerun Fu }
1501c7a6970fSZerun Fu 
15023110ab73SZerun Fu const uint32_t nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
15033110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M]     = RTE_ETH_LINK_SPEED_10M,
15043110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10M_HD]  = RTE_ETH_LINK_SPEED_10M_HD,
15053110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M]    = RTE_ETH_LINK_SPEED_100M,
15063110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_100M_HD] = RTE_ETH_LINK_SPEED_100M_HD,
15073110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_1G]      = RTE_ETH_LINK_SPEED_1G,
15083110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_2P5G]    = RTE_ETH_LINK_SPEED_2_5G,
15093110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_5G]      = RTE_ETH_LINK_SPEED_5G,
15103110ab73SZerun Fu 	[NFP_MEDIA_W0_RJ45_10G]     = RTE_ETH_LINK_SPEED_10G,
15113110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_CX]     = RTE_ETH_LINK_SPEED_1G,
15123110ab73SZerun Fu 	[NFP_MEDIA_1000BASE_KX]     = RTE_ETH_LINK_SPEED_1G,
15133110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KX4]     = RTE_ETH_LINK_SPEED_10G,
15143110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_KR]      = RTE_ETH_LINK_SPEED_10G,
15153110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CX4]     = RTE_ETH_LINK_SPEED_10G,
15163110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_CR]      = RTE_ETH_LINK_SPEED_10G,
15173110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_SR]      = RTE_ETH_LINK_SPEED_10G,
15183110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_ER]      = RTE_ETH_LINK_SPEED_10G,
15193110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR]      = RTE_ETH_LINK_SPEED_25G,
15203110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_KR_S]    = RTE_ETH_LINK_SPEED_25G,
15213110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR]      = RTE_ETH_LINK_SPEED_25G,
15223110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_CR_S]    = RTE_ETH_LINK_SPEED_25G,
15233110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_SR]      = RTE_ETH_LINK_SPEED_25G,
15243110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_CR4]     = RTE_ETH_LINK_SPEED_40G,
15253110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_KR4]     = RTE_ETH_LINK_SPEED_40G,
15263110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_SR4]     = RTE_ETH_LINK_SPEED_40G,
15273110ab73SZerun Fu 	[NFP_MEDIA_40GBASE_LR4]     = RTE_ETH_LINK_SPEED_40G,
15283110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_KR]      = RTE_ETH_LINK_SPEED_50G,
15293110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_SR]      = RTE_ETH_LINK_SPEED_50G,
15303110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_CR]      = RTE_ETH_LINK_SPEED_50G,
15313110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_LR]      = RTE_ETH_LINK_SPEED_50G,
15323110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_ER]      = RTE_ETH_LINK_SPEED_50G,
15333110ab73SZerun Fu 	[NFP_MEDIA_50GBASE_FR]      = RTE_ETH_LINK_SPEED_50G,
15343110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KR4]    = RTE_ETH_LINK_SPEED_100G,
15353110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_SR4]    = RTE_ETH_LINK_SPEED_100G,
15363110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR4]    = RTE_ETH_LINK_SPEED_100G,
15373110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_KP4]    = RTE_ETH_LINK_SPEED_100G,
15383110ab73SZerun Fu 	[NFP_MEDIA_100GBASE_CR10]   = RTE_ETH_LINK_SPEED_100G,
15393110ab73SZerun Fu 	[NFP_MEDIA_10GBASE_LR]      = RTE_ETH_LINK_SPEED_10G,
15403110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_LR]      = RTE_ETH_LINK_SPEED_25G,
15413110ab73SZerun Fu 	[NFP_MEDIA_25GBASE_ER]      = RTE_ETH_LINK_SPEED_25G
15423110ab73SZerun Fu };
15433110ab73SZerun Fu 
15443110ab73SZerun Fu static int
15453110ab73SZerun Fu nfp_net_speed_capa_get_real(struct nfp_eth_media_buf *media_buf,
15463110ab73SZerun Fu 		struct nfp_pf_dev *pf_dev)
15473110ab73SZerun Fu {
15483110ab73SZerun Fu 	uint32_t i;
15493110ab73SZerun Fu 	uint32_t j;
15503110ab73SZerun Fu 	uint32_t offset;
15513110ab73SZerun Fu 	uint32_t speed_capa = 0;
15523110ab73SZerun Fu 	uint64_t supported_modes;
15533110ab73SZerun Fu 
15543110ab73SZerun Fu 	for (i = 0; i < RTE_DIM(media_buf->supported_modes); i++) {
15553110ab73SZerun Fu 		supported_modes = media_buf->supported_modes[i];
15563110ab73SZerun Fu 		offset = i * UINT64_BIT;
15573110ab73SZerun Fu 		for (j = 0; j < UINT64_BIT; j++) {
15583110ab73SZerun Fu 			if (supported_modes == 0)
15593110ab73SZerun Fu 				break;
15603110ab73SZerun Fu 
15613110ab73SZerun Fu 			if ((supported_modes & 1) != 0) {
15623110ab73SZerun Fu 				if ((j + offset) >= NFP_MEDIA_LINK_MODES_NUMBER) {
15633110ab73SZerun Fu 					PMD_DRV_LOG(ERR, "Invalid offset of media table.");
15643110ab73SZerun Fu 					return -EINVAL;
15653110ab73SZerun Fu 				}
15663110ab73SZerun Fu 
15673110ab73SZerun Fu 				speed_capa |= nfp_eth_media_table[j + offset];
15683110ab73SZerun Fu 			}
15693110ab73SZerun Fu 
15703110ab73SZerun Fu 			supported_modes = supported_modes >> 1;
15713110ab73SZerun Fu 		}
15723110ab73SZerun Fu 	}
15733110ab73SZerun Fu 
15743110ab73SZerun Fu 	pf_dev->speed_capa = speed_capa;
15753110ab73SZerun Fu 
15763110ab73SZerun Fu 	return pf_dev->speed_capa == 0 ? -EINVAL : 0;
15773110ab73SZerun Fu }
15783110ab73SZerun Fu 
15793110ab73SZerun Fu static int
15803110ab73SZerun Fu nfp_net_speed_capa_get(struct nfp_pf_dev *pf_dev,
15813110ab73SZerun Fu 		uint32_t port_id)
15823110ab73SZerun Fu {
15833110ab73SZerun Fu 	int ret;
15843110ab73SZerun Fu 	struct nfp_nsp *nsp;
15853110ab73SZerun Fu 	struct nfp_eth_media_buf media_buf;
15863110ab73SZerun Fu 
15873110ab73SZerun Fu 	media_buf.eth_index = pf_dev->nfp_eth_table->ports[port_id].eth_index;
15883110ab73SZerun Fu 	pf_dev->speed_capa = 0;
15893110ab73SZerun Fu 
15903110ab73SZerun Fu 	nsp = nfp_nsp_open(pf_dev->cpp);
15913110ab73SZerun Fu 	if (nsp == NULL) {
15923110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Couldn't get NSP.");
15933110ab73SZerun Fu 		return -EIO;
15943110ab73SZerun Fu 	}
15953110ab73SZerun Fu 
15963110ab73SZerun Fu 	ret = nfp_nsp_read_media(nsp, &media_buf, sizeof(media_buf));
15973110ab73SZerun Fu 	nfp_nsp_close(nsp);
15983110ab73SZerun Fu 	if (ret != 0) {
15993110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Failed to read media.");
16003110ab73SZerun Fu 		return ret;
16013110ab73SZerun Fu 	}
16023110ab73SZerun Fu 
16033110ab73SZerun Fu 	ret = nfp_net_speed_capa_get_real(&media_buf, pf_dev);
16043110ab73SZerun Fu 	if (ret < 0) {
16053110ab73SZerun Fu 		PMD_DRV_LOG(ERR, "Speed capability is invalid.");
16063110ab73SZerun Fu 		return ret;
16073110ab73SZerun Fu 	}
16083110ab73SZerun Fu 
16093110ab73SZerun Fu 	return 0;
16103110ab73SZerun Fu }
16113110ab73SZerun Fu 
1612c7a6970fSZerun Fu static int
1613a6189a67SJin Liu nfp_pf_init(struct rte_pci_device *pci_dev)
1614646ea79cSHeinrich Kuhn {
16159e442599SShihong Wang 	uint32_t i;
16163b00109dSPeng Zhang 	uint32_t id;
1617e7978635SChaoyong He 	int ret = 0;
16185c464d6aSJin Liu 	uint64_t addr;
16193b00109dSPeng Zhang 	uint32_t index;
1620925c27ecSChaoyong He 	uint32_t cpp_id;
16213b00109dSPeng Zhang 	uint8_t function_id;
1622a6189a67SJin Liu 	struct nfp_cpp *cpp;
1623a6189a67SJin Liu 	struct nfp_pf_dev *pf_dev;
1624a6189a67SJin Liu 	struct nfp_hwinfo *hwinfo;
162549952141SChaoyong He 	enum nfp_app_fw_id app_fw_id;
1626a6189a67SJin Liu 	char name[RTE_ETH_NAME_MAX_LEN];
1627a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
16283b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
1629a6189a67SJin Liu 	struct nfp_eth_table *nfp_eth_table;
16300314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
1631646ea79cSHeinrich Kuhn 
1632a6189a67SJin Liu 	if (pci_dev == NULL)
1633a6189a67SJin Liu 		return -ENODEV;
1634646ea79cSHeinrich Kuhn 
163584aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
163684aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
163784aaba5aSChaoyong He 		return -ENODEV;
163884aaba5aSChaoyong He 	}
163984aaba5aSChaoyong He 
16400314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
16410314a8ffSChaoyong He 	if (dev_info == NULL) {
16420314a8ffSChaoyong He 		PMD_INIT_LOG(ERR, "Not supported device ID");
16430314a8ffSChaoyong He 		return -ENODEV;
16440314a8ffSChaoyong He 	}
16450314a8ffSChaoyong He 
16468ad2cc8fSPeng Zhang 	/* Allocate memory for the PF "device" */
16473b00109dSPeng Zhang 	function_id = (pci_dev->addr.function) & 0x07;
16483b00109dSPeng Zhang 	snprintf(name, sizeof(name), "nfp_pf%u", function_id);
16498ad2cc8fSPeng Zhang 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
16508ad2cc8fSPeng Zhang 	if (pf_dev == NULL) {
16518ad2cc8fSPeng Zhang 		PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device");
16528ad2cc8fSPeng Zhang 		return -ENOMEM;
16538ad2cc8fSPeng Zhang 	}
16548ad2cc8fSPeng Zhang 
1655646ea79cSHeinrich Kuhn 	/*
1656646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
1657646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
1658646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
1659646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
1660646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
1661646ea79cSHeinrich Kuhn 	 */
1662646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
16631fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
1664646ea79cSHeinrich Kuhn 	else
16651fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
1666646ea79cSHeinrich Kuhn 
1667a6189a67SJin Liu 	if (cpp == NULL) {
1668646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
16698ad2cc8fSPeng Zhang 		ret = -EIO;
16708ad2cc8fSPeng Zhang 		goto pf_cleanup;
1671646ea79cSHeinrich Kuhn 	}
1672646ea79cSHeinrich Kuhn 
1673646ea79cSHeinrich Kuhn 	hwinfo = nfp_hwinfo_read(cpp);
1674a6189a67SJin Liu 	if (hwinfo == NULL) {
1675646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error reading hwinfo table");
1676646ea79cSHeinrich Kuhn 		ret = -EIO;
1677968ec1c3SChaoyong He 		goto cpp_cleanup;
1678646ea79cSHeinrich Kuhn 	}
1679646ea79cSHeinrich Kuhn 
1680968ec1c3SChaoyong He 	/* Read the number of physical ports from hardware */
1681646ea79cSHeinrich Kuhn 	nfp_eth_table = nfp_eth_read_ports(cpp);
1682a6189a67SJin Liu 	if (nfp_eth_table == NULL) {
1683646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error reading NFP ethernet table");
1684646ea79cSHeinrich Kuhn 		ret = -EIO;
1685646ea79cSHeinrich Kuhn 		goto hwinfo_cleanup;
1686646ea79cSHeinrich Kuhn 	}
1687646ea79cSHeinrich Kuhn 
16888ad2cc8fSPeng Zhang 	pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_nsp(pci_dev, cpp);
16893b00109dSPeng Zhang 	pf_dev->multi_pf.function_id = function_id;
16908ad2cc8fSPeng Zhang 
16919e442599SShihong Wang 	/* Force the physical port down to clear the possible DMA error */
16923b00109dSPeng Zhang 	for (i = 0; i < nfp_eth_table->count; i++) {
16933b00109dSPeng Zhang 		id = nfp_function_id_get(pf_dev, i);
16943b00109dSPeng Zhang 		index = nfp_eth_table->ports[id].index;
16953b00109dSPeng Zhang 		nfp_eth_set_configured(cpp, index, 0);
16963b00109dSPeng Zhang 	}
16979e442599SShihong Wang 
16988ba461d1SPeng Zhang 	if (nfp_fw_setup(pci_dev, cpp, nfp_eth_table, hwinfo,
16998ba461d1SPeng Zhang 			dev_info, &pf_dev->multi_pf) != 0) {
1700646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "Error when uploading firmware");
1701646ea79cSHeinrich Kuhn 		ret = -EIO;
1702646ea79cSHeinrich Kuhn 		goto eth_table_cleanup;
1703646ea79cSHeinrich Kuhn 	}
1704646ea79cSHeinrich Kuhn 
1705646ea79cSHeinrich Kuhn 	/* Now the symbol table should be there */
1706646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
1707a6189a67SJin Liu 	if (sym_tbl == NULL) {
1708f4d24fe9SChaoyong He 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table");
1709646ea79cSHeinrich Kuhn 		ret = -EIO;
17103b00109dSPeng Zhang 		goto fw_cleanup;
1711646ea79cSHeinrich Kuhn 	}
1712646ea79cSHeinrich Kuhn 
1713968ec1c3SChaoyong He 	/* Read the app ID of the firmware loaded */
17143b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
17153b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
1716e7978635SChaoyong He 	if (ret != 0) {
17173b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "Couldn't read %s from firmware", app_name);
1718646ea79cSHeinrich Kuhn 		ret = -EIO;
1719646ea79cSHeinrich Kuhn 		goto sym_tbl_cleanup;
1720646ea79cSHeinrich Kuhn 	}
1721646ea79cSHeinrich Kuhn 
1722c7a6970fSZerun Fu 	/* Write sp_indiff to hw_info */
1723c7a6970fSZerun Fu 	ret = nfp_net_hwinfo_set(function_id, sym_tbl, cpp);
1724c7a6970fSZerun Fu 	if (ret != 0) {
1725c7a6970fSZerun Fu 		PMD_INIT_LOG(ERR, "Failed to set hwinfo.");
1726c7a6970fSZerun Fu 		ret = -EIO;
1727c7a6970fSZerun Fu 		goto sym_tbl_cleanup;
1728c7a6970fSZerun Fu 	}
1729c7a6970fSZerun Fu 
1730646ea79cSHeinrich Kuhn 	/* Populate the newly created PF device */
1731968ec1c3SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
1732646ea79cSHeinrich Kuhn 	pf_dev->cpp = cpp;
1733646ea79cSHeinrich Kuhn 	pf_dev->hwinfo = hwinfo;
1734646ea79cSHeinrich Kuhn 	pf_dev->sym_tbl = sym_tbl;
1735646ea79cSHeinrich Kuhn 	pf_dev->pci_dev = pci_dev;
1736968ec1c3SChaoyong He 	pf_dev->nfp_eth_table = nfp_eth_table;
1737646ea79cSHeinrich Kuhn 
17383110ab73SZerun Fu 	/* Get the speed capability */
17393110ab73SZerun Fu 	for (i = 0; i < nfp_eth_table->count; i++) {
17403110ab73SZerun Fu 		id = nfp_function_id_get(pf_dev, i);
17413110ab73SZerun Fu 		ret = nfp_net_speed_capa_get(pf_dev, id);
17423110ab73SZerun Fu 		if (ret != 0) {
17433110ab73SZerun Fu 			PMD_INIT_LOG(ERR, "Failed to get speed capability.");
17443110ab73SZerun Fu 			ret = -EIO;
17453110ab73SZerun Fu 			goto sym_tbl_cleanup;
17463110ab73SZerun Fu 		}
17473110ab73SZerun Fu 	}
17483110ab73SZerun Fu 
174940688372SChaoyong He 	/* Configure access to tx/rx vNIC BARs */
17500314a8ffSChaoyong He 	addr = nfp_qcp_queue_offset(dev_info, 0);
1751925c27ecSChaoyong He 	cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0);
17520314a8ffSChaoyong He 
1753711e4559SChaoyong He 	pf_dev->qc_bar = nfp_cpp_map_area(pf_dev->cpp, cpp_id,
17540314a8ffSChaoyong He 			addr, dev_info->qc_area_sz, &pf_dev->qc_area);
1755711e4559SChaoyong He 	if (pf_dev->qc_bar == NULL) {
1756646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for net.qc");
1757646ea79cSHeinrich Kuhn 		ret = -EIO;
17588ad2cc8fSPeng Zhang 		goto sym_tbl_cleanup;
1759646ea79cSHeinrich Kuhn 	}
1760646ea79cSHeinrich Kuhn 
1761030b2b19SChaoyong He 	PMD_INIT_LOG(DEBUG, "qc_bar address: %p", pf_dev->qc_bar);
1762646ea79cSHeinrich Kuhn 
1763a6189a67SJin Liu 	/*
1764968ec1c3SChaoyong He 	 * PF initialization has been done at this point. Call app specific
176540688372SChaoyong He 	 * init code now.
1766646ea79cSHeinrich Kuhn 	 */
1767968ec1c3SChaoyong He 	switch (pf_dev->app_fw_id) {
1768968ec1c3SChaoyong He 	case NFP_APP_FW_CORE_NIC:
176995f978efSPeng Zhang 		if (pf_dev->multi_pf.enabled) {
177095f978efSPeng Zhang 			ret = nfp_enable_multi_pf(pf_dev);
177195f978efSPeng Zhang 			if (ret != 0)
177295f978efSPeng Zhang 				goto hwqueues_cleanup;
177395f978efSPeng Zhang 		}
177495f978efSPeng Zhang 
1775968ec1c3SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing coreNIC");
17760314a8ffSChaoyong He 		ret = nfp_init_app_fw_nic(pf_dev, dev_info);
1777968ec1c3SChaoyong He 		if (ret != 0) {
1778968ec1c3SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
1779968ec1c3SChaoyong He 			goto hwqueues_cleanup;
1780968ec1c3SChaoyong He 		}
1781968ec1c3SChaoyong He 		break;
1782b1880421SChaoyong He 	case NFP_APP_FW_FLOWER_NIC:
1783b1880421SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing Flower");
17840314a8ffSChaoyong He 		ret = nfp_init_app_fw_flower(pf_dev, dev_info);
1785b1880421SChaoyong He 		if (ret != 0) {
1786b1880421SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
1787b1880421SChaoyong He 			goto hwqueues_cleanup;
1788b1880421SChaoyong He 		}
1789b1880421SChaoyong He 		break;
1790968ec1c3SChaoyong He 	default:
1791968ec1c3SChaoyong He 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded");
1792968ec1c3SChaoyong He 		ret = -EINVAL;
1793646ea79cSHeinrich Kuhn 		goto hwqueues_cleanup;
1794646ea79cSHeinrich Kuhn 	}
1795646ea79cSHeinrich Kuhn 
179640688372SChaoyong He 	/* Register the CPP bridge service here for primary use */
1797bab0e6f4SChaoyong He 	ret = nfp_enable_cpp_service(pf_dev);
1798dee23e6cSChaoyong He 	if (ret != 0)
1799dee23e6cSChaoyong He 		PMD_INIT_LOG(INFO, "Enable cpp service failed.");
1800646ea79cSHeinrich Kuhn 
1801646ea79cSHeinrich Kuhn 	return 0;
1802646ea79cSHeinrich Kuhn 
1803646ea79cSHeinrich Kuhn hwqueues_cleanup:
1804528812a6SChaoyong He 	nfp_cpp_area_release_free(pf_dev->qc_area);
1805646ea79cSHeinrich Kuhn sym_tbl_cleanup:
1806646ea79cSHeinrich Kuhn 	free(sym_tbl);
18073b00109dSPeng Zhang fw_cleanup:
18083b00109dSPeng Zhang 	nfp_fw_unload(cpp);
18098ba461d1SPeng Zhang 	nfp_net_keepalive_stop(&pf_dev->multi_pf);
1810b67a7b40SPeng Zhang 	nfp_net_keepalive_clear(pf_dev->multi_pf.beat_addr, pf_dev->multi_pf.function_id);
1811528812a6SChaoyong He 	nfp_net_keepalive_uninit(&pf_dev->multi_pf);
1812646ea79cSHeinrich Kuhn eth_table_cleanup:
1813646ea79cSHeinrich Kuhn 	free(nfp_eth_table);
1814646ea79cSHeinrich Kuhn hwinfo_cleanup:
1815646ea79cSHeinrich Kuhn 	free(hwinfo);
1816968ec1c3SChaoyong He cpp_cleanup:
1817968ec1c3SChaoyong He 	nfp_cpp_free(cpp);
18188ad2cc8fSPeng Zhang pf_cleanup:
18198ad2cc8fSPeng Zhang 	rte_free(pf_dev);
18207feb8909SChaoyong He 
1821646ea79cSHeinrich Kuhn 	return ret;
1822646ea79cSHeinrich Kuhn }
1823646ea79cSHeinrich Kuhn 
1824d5f39e07SChaoyong He static int
1825016141b1SChaoyong He nfp_secondary_init_app_fw_nic(struct nfp_pf_dev *pf_dev)
1826d5f39e07SChaoyong He {
18278ceb85c3SChaoyong He 	uint32_t i;
1828d5f39e07SChaoyong He 	int err = 0;
1829d5f39e07SChaoyong He 	int ret = 0;
18303b00109dSPeng Zhang 	uint8_t function_id;
18318ceb85c3SChaoyong He 	uint32_t total_vnics;
1832d5f39e07SChaoyong He 	struct nfp_net_hw *hw;
18333b00109dSPeng Zhang 	char pf_name[RTE_ETH_NAME_MAX_LEN];
1834d5f39e07SChaoyong He 
1835d5f39e07SChaoyong He 	/* Read the number of vNIC's created for the PF */
18363b00109dSPeng Zhang 	function_id = (pf_dev->pci_dev->addr.function) & 0x07;
18373b00109dSPeng Zhang 	snprintf(pf_name, sizeof(pf_name), "nfd_cfg_pf%u_num_ports", function_id);
18383b00109dSPeng Zhang 	total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, pf_name, &err);
18398ceb85c3SChaoyong He 	if (err != 0 || total_vnics == 0 || total_vnics > 8) {
18403b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "%s symbol with wrong value", pf_name);
1841d5f39e07SChaoyong He 		return -ENODEV;
1842d5f39e07SChaoyong He 	}
1843d5f39e07SChaoyong He 
1844d5f39e07SChaoyong He 	for (i = 0; i < total_vnics; i++) {
1845d5f39e07SChaoyong He 		struct rte_eth_dev *eth_dev;
1846d5f39e07SChaoyong He 		char port_name[RTE_ETH_NAME_MAX_LEN];
18473b00109dSPeng Zhang 
18483b00109dSPeng Zhang 		if (nfp_check_multi_pf_from_fw(total_vnics))
1849*c92c83d4SPeng Zhang 			snprintf(port_name, sizeof(port_name), "%s",
1850*c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name);
1851*c92c83d4SPeng Zhang 		else
18528ceb85c3SChaoyong He 			snprintf(port_name, sizeof(port_name), "%s_port%u",
1853*c92c83d4SPeng Zhang 					pf_dev->pci_dev->device.name, i);
1854d5f39e07SChaoyong He 
1855d5f39e07SChaoyong He 		PMD_INIT_LOG(DEBUG, "Secondary attaching to port %s", port_name);
1856d5f39e07SChaoyong He 		eth_dev = rte_eth_dev_attach_secondary(port_name);
1857d5f39e07SChaoyong He 		if (eth_dev == NULL) {
1858d5f39e07SChaoyong He 			PMD_INIT_LOG(ERR, "Secondary process attach to port %s failed", port_name);
1859d5f39e07SChaoyong He 			ret = -ENODEV;
1860d5f39e07SChaoyong He 			break;
1861d5f39e07SChaoyong He 		}
1862d5f39e07SChaoyong He 
1863acb6bebfSChaoyong He 		eth_dev->process_private = pf_dev;
18649d723baaSChaoyong He 		hw = eth_dev->data->dev_private;
1865ee8ca64eSChaoyong He 		nfp_net_ethdev_ops_mount(hw, eth_dev);
1866d5f39e07SChaoyong He 
1867d5f39e07SChaoyong He 		rte_eth_dev_probing_finish(eth_dev);
1868d5f39e07SChaoyong He 	}
1869d5f39e07SChaoyong He 
1870d5f39e07SChaoyong He 	return ret;
1871d5f39e07SChaoyong He }
1872d5f39e07SChaoyong He 
1873646ea79cSHeinrich Kuhn /*
1874646ea79cSHeinrich Kuhn  * When attaching to the NFP4000/6000 PF on a secondary process there
1875646ea79cSHeinrich Kuhn  * is no need to initialise the PF again. Only minimal work is required
187640688372SChaoyong He  * here.
1877646ea79cSHeinrich Kuhn  */
1878a6189a67SJin Liu static int
1879a6189a67SJin Liu nfp_pf_secondary_init(struct rte_pci_device *pci_dev)
1880646ea79cSHeinrich Kuhn {
1881968ec1c3SChaoyong He 	int ret = 0;
1882a6189a67SJin Liu 	struct nfp_cpp *cpp;
18833b00109dSPeng Zhang 	uint8_t function_id;
1884016141b1SChaoyong He 	struct nfp_pf_dev *pf_dev;
1885d5f39e07SChaoyong He 	enum nfp_app_fw_id app_fw_id;
1886016141b1SChaoyong He 	char name[RTE_ETH_NAME_MAX_LEN];
1887a6189a67SJin Liu 	struct nfp_rtsym_table *sym_tbl;
18880314a8ffSChaoyong He 	const struct nfp_dev_info *dev_info;
18893b00109dSPeng Zhang 	char app_name[RTE_ETH_NAME_MAX_LEN];
1890646ea79cSHeinrich Kuhn 
1891a6189a67SJin Liu 	if (pci_dev == NULL)
1892646ea79cSHeinrich Kuhn 		return -ENODEV;
1893646ea79cSHeinrich Kuhn 
189484aaba5aSChaoyong He 	if (pci_dev->mem_resource[0].addr == NULL) {
189584aaba5aSChaoyong He 		PMD_INIT_LOG(ERR, "The address of BAR0 is NULL.");
189684aaba5aSChaoyong He 		return -ENODEV;
189784aaba5aSChaoyong He 	}
189884aaba5aSChaoyong He 
18990314a8ffSChaoyong He 	dev_info = nfp_dev_info_get(pci_dev->id.device_id);
19000314a8ffSChaoyong He 	if (dev_info == NULL) {
19010314a8ffSChaoyong He 		PMD_INIT_LOG(ERR, "Not supported device ID");
19020314a8ffSChaoyong He 		return -ENODEV;
19030314a8ffSChaoyong He 	}
19040314a8ffSChaoyong He 
1905016141b1SChaoyong He 	/* Allocate memory for the PF "device" */
1906016141b1SChaoyong He 	snprintf(name, sizeof(name), "nfp_pf%d", 0);
1907016141b1SChaoyong He 	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
1908016141b1SChaoyong He 	if (pf_dev == NULL) {
1909016141b1SChaoyong He 		PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device");
1910016141b1SChaoyong He 		return -ENOMEM;
1911016141b1SChaoyong He 	}
1912016141b1SChaoyong He 
1913646ea79cSHeinrich Kuhn 	/*
1914646ea79cSHeinrich Kuhn 	 * When device bound to UIO, the device could be used, by mistake,
1915646ea79cSHeinrich Kuhn 	 * by two DPDK apps, and the UIO driver does not avoid it. This
1916646ea79cSHeinrich Kuhn 	 * could lead to a serious problem when configuring the NFP CPP
1917646ea79cSHeinrich Kuhn 	 * interface. Here we avoid this telling to the CPP init code to
1918646ea79cSHeinrich Kuhn 	 * use a lock file if UIO is being used.
1919646ea79cSHeinrich Kuhn 	 */
1920646ea79cSHeinrich Kuhn 	if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO)
19211fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false);
1922646ea79cSHeinrich Kuhn 	else
19231fbe51cdSChaoyong He 		cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true);
1924646ea79cSHeinrich Kuhn 
1925a6189a67SJin Liu 	if (cpp == NULL) {
1926646ea79cSHeinrich Kuhn 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
1927016141b1SChaoyong He 		ret = -EIO;
1928016141b1SChaoyong He 		goto pf_cleanup;
1929646ea79cSHeinrich Kuhn 	}
1930646ea79cSHeinrich Kuhn 
1931646ea79cSHeinrich Kuhn 	/*
1932646ea79cSHeinrich Kuhn 	 * We don't have access to the PF created in the primary process
193340688372SChaoyong He 	 * here so we have to read the number of ports from firmware.
1934646ea79cSHeinrich Kuhn 	 */
1935646ea79cSHeinrich Kuhn 	sym_tbl = nfp_rtsym_table_read(cpp);
1936a6189a67SJin Liu 	if (sym_tbl == NULL) {
1937f4d24fe9SChaoyong He 		PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table");
1938016141b1SChaoyong He 		ret = -EIO;
1939016141b1SChaoyong He 		goto pf_cleanup;
1940646ea79cSHeinrich Kuhn 	}
1941646ea79cSHeinrich Kuhn 
1942d5f39e07SChaoyong He 	/* Read the app ID of the firmware loaded */
19433b00109dSPeng Zhang 	function_id = pci_dev->addr.function & 0x7;
19443b00109dSPeng Zhang 	snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id);
19453b00109dSPeng Zhang 	app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret);
1946e7978635SChaoyong He 	if (ret != 0) {
19473b00109dSPeng Zhang 		PMD_INIT_LOG(ERR, "Couldn't read %s from fw", app_name);
1948016141b1SChaoyong He 		ret = -EIO;
1949968ec1c3SChaoyong He 		goto sym_tbl_cleanup;
1950968ec1c3SChaoyong He 	}
1951646ea79cSHeinrich Kuhn 
1952016141b1SChaoyong He 	/* Populate the newly created PF device */
1953016141b1SChaoyong He 	pf_dev->app_fw_id = app_fw_id;
1954016141b1SChaoyong He 	pf_dev->cpp = cpp;
1955016141b1SChaoyong He 	pf_dev->sym_tbl = sym_tbl;
1956016141b1SChaoyong He 	pf_dev->pci_dev = pci_dev;
1957016141b1SChaoyong He 
1958016141b1SChaoyong He 	/* Call app specific init code now */
1959d5f39e07SChaoyong He 	switch (app_fw_id) {
1960d5f39e07SChaoyong He 	case NFP_APP_FW_CORE_NIC:
1961d5f39e07SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing coreNIC");
1962016141b1SChaoyong He 		ret = nfp_secondary_init_app_fw_nic(pf_dev);
1963d5f39e07SChaoyong He 		if (ret != 0) {
1964d5f39e07SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize coreNIC!");
1965d5f39e07SChaoyong He 			goto sym_tbl_cleanup;
1966646ea79cSHeinrich Kuhn 		}
1967d5f39e07SChaoyong He 		break;
1968b1880421SChaoyong He 	case NFP_APP_FW_FLOWER_NIC:
1969b1880421SChaoyong He 		PMD_INIT_LOG(INFO, "Initializing Flower");
1970016141b1SChaoyong He 		ret = nfp_secondary_init_app_fw_flower(pf_dev);
1971b1880421SChaoyong He 		if (ret != 0) {
1972b1880421SChaoyong He 			PMD_INIT_LOG(ERR, "Could not initialize Flower!");
1973b1880421SChaoyong He 			goto sym_tbl_cleanup;
1974b1880421SChaoyong He 		}
1975b1880421SChaoyong He 		break;
1976d5f39e07SChaoyong He 	default:
1977d5f39e07SChaoyong He 		PMD_INIT_LOG(ERR, "Unsupported Firmware loaded");
1978d5f39e07SChaoyong He 		ret = -EINVAL;
1979d5f39e07SChaoyong He 		goto sym_tbl_cleanup;
1980646ea79cSHeinrich Kuhn 	}
1981646ea79cSHeinrich Kuhn 
1982016141b1SChaoyong He 	return 0;
1983016141b1SChaoyong He 
1984968ec1c3SChaoyong He sym_tbl_cleanup:
1985968ec1c3SChaoyong He 	free(sym_tbl);
1986016141b1SChaoyong He pf_cleanup:
1987016141b1SChaoyong He 	rte_free(pf_dev);
1988968ec1c3SChaoyong He 
1989968ec1c3SChaoyong He 	return ret;
1990646ea79cSHeinrich Kuhn }
1991646ea79cSHeinrich Kuhn 
1992a6189a67SJin Liu static int
1993a6189a67SJin Liu nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
1994646ea79cSHeinrich Kuhn 		struct rte_pci_device *dev)
1995646ea79cSHeinrich Kuhn {
1996646ea79cSHeinrich Kuhn 	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
1997646ea79cSHeinrich Kuhn 		return nfp_pf_init(dev);
1998646ea79cSHeinrich Kuhn 	else
1999646ea79cSHeinrich Kuhn 		return nfp_pf_secondary_init(dev);
2000646ea79cSHeinrich Kuhn }
2001646ea79cSHeinrich Kuhn 
2002646ea79cSHeinrich Kuhn static const struct rte_pci_id pci_id_nfp_pf_net_map[] = {
2003646ea79cSHeinrich Kuhn 	{
2004646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
20055c464d6aSJin Liu 				PCI_DEVICE_ID_NFP3800_PF_NIC)
20065c464d6aSJin Liu 	},
20075c464d6aSJin Liu 	{
20085c464d6aSJin Liu 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2009646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP4000_PF_NIC)
2010646ea79cSHeinrich Kuhn 	},
2011646ea79cSHeinrich Kuhn 	{
2012646ea79cSHeinrich Kuhn 		RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
2013646ea79cSHeinrich Kuhn 				PCI_DEVICE_ID_NFP6000_PF_NIC)
2014646ea79cSHeinrich Kuhn 	},
2015646ea79cSHeinrich Kuhn 	{
20165aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
20175aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP3800_PF_NIC)
20185aedd4c3SJames Hershaw 	},
20195aedd4c3SJames Hershaw 	{
20205aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
20215aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP4000_PF_NIC)
20225aedd4c3SJames Hershaw 	},
20235aedd4c3SJames Hershaw 	{
20245aedd4c3SJames Hershaw 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE,
20255aedd4c3SJames Hershaw 				PCI_DEVICE_ID_NFP6000_PF_NIC)
20265aedd4c3SJames Hershaw 	},
20275aedd4c3SJames Hershaw 	{
2028646ea79cSHeinrich Kuhn 		.vendor_id = 0,
2029646ea79cSHeinrich Kuhn 	},
2030646ea79cSHeinrich Kuhn };
2031646ea79cSHeinrich Kuhn 
2032a6189a67SJin Liu static int
2033a6189a67SJin Liu nfp_pci_uninit(struct rte_eth_dev *eth_dev)
2034646ea79cSHeinrich Kuhn {
2035646ea79cSHeinrich Kuhn 	uint16_t port_id;
203649952141SChaoyong He 	struct rte_pci_device *pci_dev;
2037646ea79cSHeinrich Kuhn 
2038646ea79cSHeinrich Kuhn 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
2039646ea79cSHeinrich Kuhn 
2040646ea79cSHeinrich Kuhn 	/* Free up all physical ports under PF */
2041646ea79cSHeinrich Kuhn 	RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device)
2042646ea79cSHeinrich Kuhn 		rte_eth_dev_close(port_id);
2043646ea79cSHeinrich Kuhn 	/*
2044646ea79cSHeinrich Kuhn 	 * Ports can be closed and freed but hotplugging is not
204540688372SChaoyong He 	 * currently supported.
2046646ea79cSHeinrich Kuhn 	 */
2047646ea79cSHeinrich Kuhn 	return -ENOTSUP;
2048646ea79cSHeinrich Kuhn }
2049646ea79cSHeinrich Kuhn 
2050a6189a67SJin Liu static int
2051a6189a67SJin Liu eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
2052646ea79cSHeinrich Kuhn {
2053646ea79cSHeinrich Kuhn 	return rte_eth_dev_pci_generic_remove(pci_dev, nfp_pci_uninit);
2054646ea79cSHeinrich Kuhn }
2055646ea79cSHeinrich Kuhn 
2056646ea79cSHeinrich Kuhn static struct rte_pci_driver rte_nfp_net_pf_pmd = {
2057646ea79cSHeinrich Kuhn 	.id_table = pci_id_nfp_pf_net_map,
2058646ea79cSHeinrich Kuhn 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
2059646ea79cSHeinrich Kuhn 	.probe = nfp_pf_pci_probe,
2060646ea79cSHeinrich Kuhn 	.remove = eth_nfp_pci_remove,
2061646ea79cSHeinrich Kuhn };
2062646ea79cSHeinrich Kuhn 
2063d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI(NFP_PF_DRIVER_NAME, rte_nfp_net_pf_pmd);
2064d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI_TABLE(NFP_PF_DRIVER_NAME, pci_id_nfp_pf_net_map);
2065d505ee1dSChaoyong He RTE_PMD_REGISTER_KMOD_DEP(NFP_PF_DRIVER_NAME, "* igb_uio | uio_pci_generic | vfio");
2066