xref: /dpdk/drivers/net/failsafe/failsafe_ether.c (revision 0545c580fc377d33711786eaed665ee60e801bbd)
1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
2ebea83f8SGaetan Rivet  * Copyright 2017 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2017 Mellanox Technologies, Ltd
4ebea83f8SGaetan Rivet  */
5ebea83f8SGaetan Rivet 
6ebea83f8SGaetan Rivet #include <unistd.h>
7ebea83f8SGaetan Rivet 
8b737a1eeSGaetan Rivet #include <rte_flow.h>
9b737a1eeSGaetan Rivet #include <rte_flow_driver.h>
109dda3e33SMatan Azrad #include <rte_cycles.h>
11b737a1eeSGaetan Rivet 
12ebea83f8SGaetan Rivet #include "failsafe_private.h"
13ebea83f8SGaetan Rivet 
14b737a1eeSGaetan Rivet /** Print a message out of a flow error. */
15b737a1eeSGaetan Rivet static int
16b737a1eeSGaetan Rivet fs_flow_complain(struct rte_flow_error *error)
17b737a1eeSGaetan Rivet {
18b737a1eeSGaetan Rivet 	static const char *const errstrlist[] = {
19b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_NONE] = "no error",
20b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
21b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
22b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
23b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
24b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
25b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
26b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
27b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
28b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
29b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
30b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
31b737a1eeSGaetan Rivet 	};
32b737a1eeSGaetan Rivet 	const char *errstr;
33b737a1eeSGaetan Rivet 	char buf[32];
34b737a1eeSGaetan Rivet 	int err = rte_errno;
35b737a1eeSGaetan Rivet 
36b737a1eeSGaetan Rivet 	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
37b737a1eeSGaetan Rivet 			!errstrlist[error->type])
38b737a1eeSGaetan Rivet 		errstr = "unknown type";
39b737a1eeSGaetan Rivet 	else
40b737a1eeSGaetan Rivet 		errstr = errstrlist[error->type];
41b737a1eeSGaetan Rivet 	ERROR("Caught error type %d (%s): %s%s\n",
42b737a1eeSGaetan Rivet 		error->type, errstr,
43b737a1eeSGaetan Rivet 		error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
44b737a1eeSGaetan Rivet 				error->cause), buf) : "",
45b737a1eeSGaetan Rivet 		error->message ? error->message : "(no stated reason)");
46b737a1eeSGaetan Rivet 	return -err;
47b737a1eeSGaetan Rivet }
48b737a1eeSGaetan Rivet 
49ebea83f8SGaetan Rivet static int
502cc52cd7SGaetan Rivet eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
512cc52cd7SGaetan Rivet 			 struct sub_device *sdev)
522cc52cd7SGaetan Rivet {
532cc52cd7SGaetan Rivet 	struct rte_flow_error ferror;
542cc52cd7SGaetan Rivet 	int ret;
552cc52cd7SGaetan Rivet 
562cc52cd7SGaetan Rivet 	if (!PRIV(dev)->flow_isolated) {
572cc52cd7SGaetan Rivet 		DEBUG("Flow isolation already disabled");
582cc52cd7SGaetan Rivet 	} else {
592cc52cd7SGaetan Rivet 		DEBUG("Enabling flow isolation");
602cc52cd7SGaetan Rivet 		ret = rte_flow_isolate(PORT_ID(sdev),
612cc52cd7SGaetan Rivet 				       PRIV(dev)->flow_isolated,
622cc52cd7SGaetan Rivet 				       &ferror);
632cc52cd7SGaetan Rivet 		if (ret) {
642cc52cd7SGaetan Rivet 			fs_flow_complain(&ferror);
652cc52cd7SGaetan Rivet 			return ret;
662cc52cd7SGaetan Rivet 		}
672cc52cd7SGaetan Rivet 	}
682cc52cd7SGaetan Rivet 	return 0;
692cc52cd7SGaetan Rivet }
702cc52cd7SGaetan Rivet 
712cc52cd7SGaetan Rivet static int
72ebea83f8SGaetan Rivet fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
73ebea83f8SGaetan Rivet 		struct sub_device *sdev)
74ebea83f8SGaetan Rivet {
75ebea83f8SGaetan Rivet 	struct rte_eth_dev *edev;
76ebea83f8SGaetan Rivet 	struct rte_vlan_filter_conf *vfc1;
77ebea83f8SGaetan Rivet 	struct rte_vlan_filter_conf *vfc2;
78b737a1eeSGaetan Rivet 	struct rte_flow *flow;
79b737a1eeSGaetan Rivet 	struct rte_flow_error ferror;
80ebea83f8SGaetan Rivet 	uint32_t i;
81ebea83f8SGaetan Rivet 	int ret;
82ebea83f8SGaetan Rivet 
83ebea83f8SGaetan Rivet 	edev = ETH(sdev);
84ebea83f8SGaetan Rivet 	/* RX queue setup */
85ebea83f8SGaetan Rivet 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
86ebea83f8SGaetan Rivet 		struct rxq *rxq;
87ebea83f8SGaetan Rivet 
88ebea83f8SGaetan Rivet 		rxq = dev->data->rx_queues[i];
89ebea83f8SGaetan Rivet 		ret = rte_eth_rx_queue_setup(PORT_ID(sdev), i,
90ebea83f8SGaetan Rivet 				rxq->info.nb_desc, rxq->socket_id,
91ebea83f8SGaetan Rivet 				&rxq->info.conf, rxq->info.mp);
92ebea83f8SGaetan Rivet 		if (ret) {
93ebea83f8SGaetan Rivet 			ERROR("rx_queue_setup failed");
94ebea83f8SGaetan Rivet 			return ret;
95ebea83f8SGaetan Rivet 		}
96ebea83f8SGaetan Rivet 	}
97ebea83f8SGaetan Rivet 	/* TX queue setup */
98ebea83f8SGaetan Rivet 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
99ebea83f8SGaetan Rivet 		struct txq *txq;
100ebea83f8SGaetan Rivet 
101ebea83f8SGaetan Rivet 		txq = dev->data->tx_queues[i];
102ebea83f8SGaetan Rivet 		ret = rte_eth_tx_queue_setup(PORT_ID(sdev), i,
103ebea83f8SGaetan Rivet 				txq->info.nb_desc, txq->socket_id,
104ebea83f8SGaetan Rivet 				&txq->info.conf);
105ebea83f8SGaetan Rivet 		if (ret) {
106ebea83f8SGaetan Rivet 			ERROR("tx_queue_setup failed");
107ebea83f8SGaetan Rivet 			return ret;
108ebea83f8SGaetan Rivet 		}
109ebea83f8SGaetan Rivet 	}
110ebea83f8SGaetan Rivet 	/* dev_link.link_status */
111ebea83f8SGaetan Rivet 	if (dev->data->dev_link.link_status !=
112ebea83f8SGaetan Rivet 	    edev->data->dev_link.link_status) {
113ebea83f8SGaetan Rivet 		DEBUG("Configuring link_status");
114ebea83f8SGaetan Rivet 		if (dev->data->dev_link.link_status)
115ebea83f8SGaetan Rivet 			ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
116ebea83f8SGaetan Rivet 		else
117ebea83f8SGaetan Rivet 			ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
118ebea83f8SGaetan Rivet 		if (ret) {
119ebea83f8SGaetan Rivet 			ERROR("Failed to apply link_status");
120ebea83f8SGaetan Rivet 			return ret;
121ebea83f8SGaetan Rivet 		}
122ebea83f8SGaetan Rivet 	} else {
123ebea83f8SGaetan Rivet 		DEBUG("link_status already set");
124ebea83f8SGaetan Rivet 	}
125ebea83f8SGaetan Rivet 	/* promiscuous */
126ebea83f8SGaetan Rivet 	if (dev->data->promiscuous != edev->data->promiscuous) {
127ebea83f8SGaetan Rivet 		DEBUG("Configuring promiscuous");
128ebea83f8SGaetan Rivet 		if (dev->data->promiscuous)
129ebea83f8SGaetan Rivet 			rte_eth_promiscuous_enable(PORT_ID(sdev));
130ebea83f8SGaetan Rivet 		else
131ebea83f8SGaetan Rivet 			rte_eth_promiscuous_disable(PORT_ID(sdev));
132ebea83f8SGaetan Rivet 	} else {
133ebea83f8SGaetan Rivet 		DEBUG("promiscuous already set");
134ebea83f8SGaetan Rivet 	}
135ebea83f8SGaetan Rivet 	/* all_multicast */
136ebea83f8SGaetan Rivet 	if (dev->data->all_multicast != edev->data->all_multicast) {
137ebea83f8SGaetan Rivet 		DEBUG("Configuring all_multicast");
138ebea83f8SGaetan Rivet 		if (dev->data->all_multicast)
139ebea83f8SGaetan Rivet 			rte_eth_allmulticast_enable(PORT_ID(sdev));
140ebea83f8SGaetan Rivet 		else
141ebea83f8SGaetan Rivet 			rte_eth_allmulticast_disable(PORT_ID(sdev));
142ebea83f8SGaetan Rivet 	} else {
143ebea83f8SGaetan Rivet 		DEBUG("all_multicast already set");
144ebea83f8SGaetan Rivet 	}
145ebea83f8SGaetan Rivet 	/* MTU */
146ebea83f8SGaetan Rivet 	if (dev->data->mtu != edev->data->mtu) {
147ebea83f8SGaetan Rivet 		DEBUG("Configuring MTU");
148ebea83f8SGaetan Rivet 		ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu);
149ebea83f8SGaetan Rivet 		if (ret) {
150ebea83f8SGaetan Rivet 			ERROR("Failed to apply MTU");
151ebea83f8SGaetan Rivet 			return ret;
152ebea83f8SGaetan Rivet 		}
153ebea83f8SGaetan Rivet 	} else {
154ebea83f8SGaetan Rivet 		DEBUG("MTU already set");
155ebea83f8SGaetan Rivet 	}
156ebea83f8SGaetan Rivet 	/* default MAC */
157ebea83f8SGaetan Rivet 	DEBUG("Configuring default MAC address");
158ebea83f8SGaetan Rivet 	ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
159ebea83f8SGaetan Rivet 			&dev->data->mac_addrs[0]);
160ebea83f8SGaetan Rivet 	if (ret) {
161ebea83f8SGaetan Rivet 		ERROR("Setting default MAC address failed");
162ebea83f8SGaetan Rivet 		return ret;
163ebea83f8SGaetan Rivet 	}
164ebea83f8SGaetan Rivet 	/* additional MAC */
165ebea83f8SGaetan Rivet 	if (PRIV(dev)->nb_mac_addr > 1)
166ebea83f8SGaetan Rivet 		DEBUG("Configure additional MAC address%s",
167ebea83f8SGaetan Rivet 			(PRIV(dev)->nb_mac_addr > 2 ? "es" : ""));
168ebea83f8SGaetan Rivet 	for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) {
169ebea83f8SGaetan Rivet 		struct ether_addr *ea;
170ebea83f8SGaetan Rivet 
171ebea83f8SGaetan Rivet 		ea = &dev->data->mac_addrs[i];
172ebea83f8SGaetan Rivet 		ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
173ebea83f8SGaetan Rivet 				PRIV(dev)->mac_addr_pool[i]);
174ebea83f8SGaetan Rivet 		if (ret) {
175ebea83f8SGaetan Rivet 			char ea_fmt[ETHER_ADDR_FMT_SIZE];
176ebea83f8SGaetan Rivet 
177ebea83f8SGaetan Rivet 			ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea);
178ebea83f8SGaetan Rivet 			ERROR("Adding MAC address %s failed", ea_fmt);
179ae7cb246SMatan Azrad 			return ret;
180ebea83f8SGaetan Rivet 		}
181ebea83f8SGaetan Rivet 	}
182ebea83f8SGaetan Rivet 	/* VLAN filter */
183ebea83f8SGaetan Rivet 	vfc1 = &dev->data->vlan_filter_conf;
184ebea83f8SGaetan Rivet 	vfc2 = &edev->data->vlan_filter_conf;
185ebea83f8SGaetan Rivet 	if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) {
186ebea83f8SGaetan Rivet 		uint64_t vbit;
187ebea83f8SGaetan Rivet 		uint64_t ids;
188ebea83f8SGaetan Rivet 		size_t i;
189ebea83f8SGaetan Rivet 		uint16_t vlan_id;
190ebea83f8SGaetan Rivet 
191ebea83f8SGaetan Rivet 		DEBUG("Configuring VLAN filter");
192ebea83f8SGaetan Rivet 		for (i = 0; i < RTE_DIM(vfc1->ids); i++) {
193ebea83f8SGaetan Rivet 			if (vfc1->ids[i] == 0)
194ebea83f8SGaetan Rivet 				continue;
195ebea83f8SGaetan Rivet 			ids = vfc1->ids[i];
196ebea83f8SGaetan Rivet 			while (ids) {
197ebea83f8SGaetan Rivet 				vlan_id = 64 * i;
198ebea83f8SGaetan Rivet 				/* count trailing zeroes */
199ebea83f8SGaetan Rivet 				vbit = ~ids & (ids - 1);
200ebea83f8SGaetan Rivet 				/* clear least significant bit set */
201ebea83f8SGaetan Rivet 				ids ^= (ids ^ (ids - 1)) ^ vbit;
202ebea83f8SGaetan Rivet 				for (; vbit; vlan_id++)
203ebea83f8SGaetan Rivet 					vbit >>= 1;
204ebea83f8SGaetan Rivet 				ret = rte_eth_dev_vlan_filter(
205ebea83f8SGaetan Rivet 					PORT_ID(sdev), vlan_id, 1);
206ebea83f8SGaetan Rivet 				if (ret) {
207ebea83f8SGaetan Rivet 					ERROR("Failed to apply VLAN filter %hu",
208ebea83f8SGaetan Rivet 						vlan_id);
209ebea83f8SGaetan Rivet 					return ret;
210ebea83f8SGaetan Rivet 				}
211ebea83f8SGaetan Rivet 			}
212ebea83f8SGaetan Rivet 		}
213ebea83f8SGaetan Rivet 	} else {
214ebea83f8SGaetan Rivet 		DEBUG("VLAN filter already set");
215ebea83f8SGaetan Rivet 	}
216b737a1eeSGaetan Rivet 	/* rte_flow */
217b737a1eeSGaetan Rivet 	if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) {
218b737a1eeSGaetan Rivet 		DEBUG("rte_flow already set");
219b737a1eeSGaetan Rivet 	} else {
220b737a1eeSGaetan Rivet 		DEBUG("Resetting rte_flow configuration");
221b737a1eeSGaetan Rivet 		ret = rte_flow_flush(PORT_ID(sdev), &ferror);
222b737a1eeSGaetan Rivet 		if (ret) {
223b737a1eeSGaetan Rivet 			fs_flow_complain(&ferror);
224b737a1eeSGaetan Rivet 			return ret;
225b737a1eeSGaetan Rivet 		}
226b737a1eeSGaetan Rivet 		i = 0;
227b737a1eeSGaetan Rivet 		rte_errno = 0;
228b737a1eeSGaetan Rivet 		DEBUG("Configuring rte_flow");
229b737a1eeSGaetan Rivet 		TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) {
230b737a1eeSGaetan Rivet 			DEBUG("Creating flow #%" PRIu32, i++);
231b737a1eeSGaetan Rivet 			flow->flows[SUB_ID(sdev)] =
232b737a1eeSGaetan Rivet 				rte_flow_create(PORT_ID(sdev),
233b737a1eeSGaetan Rivet 						&flow->fd->attr,
234b737a1eeSGaetan Rivet 						flow->fd->items,
235b737a1eeSGaetan Rivet 						flow->fd->actions,
236b737a1eeSGaetan Rivet 						&ferror);
237b737a1eeSGaetan Rivet 			ret = rte_errno;
238b737a1eeSGaetan Rivet 			if (ret)
239b737a1eeSGaetan Rivet 				break;
240b737a1eeSGaetan Rivet 		}
241b737a1eeSGaetan Rivet 		if (ret) {
242b737a1eeSGaetan Rivet 			fs_flow_complain(&ferror);
243b737a1eeSGaetan Rivet 			return ret;
244b737a1eeSGaetan Rivet 		}
245b737a1eeSGaetan Rivet 	}
246ebea83f8SGaetan Rivet 	return 0;
247ebea83f8SGaetan Rivet }
248ebea83f8SGaetan Rivet 
249598fb8aeSGaetan Rivet static void
250598fb8aeSGaetan Rivet fs_dev_remove(struct sub_device *sdev)
251598fb8aeSGaetan Rivet {
252598fb8aeSGaetan Rivet 	int ret;
253598fb8aeSGaetan Rivet 
254598fb8aeSGaetan Rivet 	if (sdev == NULL)
255598fb8aeSGaetan Rivet 		return;
256598fb8aeSGaetan Rivet 	switch (sdev->state) {
257598fb8aeSGaetan Rivet 	case DEV_STARTED:
258f234e5bdSMoti Haimovsky 		failsafe_rx_intr_uninstall_subdevice(sdev);
259598fb8aeSGaetan Rivet 		rte_eth_dev_stop(PORT_ID(sdev));
260598fb8aeSGaetan Rivet 		sdev->state = DEV_ACTIVE;
261598fb8aeSGaetan Rivet 		/* fallthrough */
262598fb8aeSGaetan Rivet 	case DEV_ACTIVE:
263*0545c580SMatan Azrad 		failsafe_eth_dev_unregister_callbacks(sdev);
264598fb8aeSGaetan Rivet 		rte_eth_dev_close(PORT_ID(sdev));
265598fb8aeSGaetan Rivet 		sdev->state = DEV_PROBED;
266598fb8aeSGaetan Rivet 		/* fallthrough */
267598fb8aeSGaetan Rivet 	case DEV_PROBED:
268598fb8aeSGaetan Rivet 		ret = rte_eal_hotplug_remove(sdev->bus->name,
269598fb8aeSGaetan Rivet 					     sdev->dev->name);
270598fb8aeSGaetan Rivet 		if (ret) {
271598fb8aeSGaetan Rivet 			ERROR("Bus detach failed for sub_device %u",
272598fb8aeSGaetan Rivet 			      SUB_ID(sdev));
273598fb8aeSGaetan Rivet 		} else {
274fac0ae54SMatan Azrad 			rte_eth_dev_release_port(ETH(sdev));
275598fb8aeSGaetan Rivet 		}
276598fb8aeSGaetan Rivet 		sdev->state = DEV_PARSED;
277598fb8aeSGaetan Rivet 		/* fallthrough */
278598fb8aeSGaetan Rivet 	case DEV_PARSED:
279598fb8aeSGaetan Rivet 	case DEV_UNDEFINED:
280598fb8aeSGaetan Rivet 		sdev->state = DEV_UNDEFINED;
281598fb8aeSGaetan Rivet 		/* the end */
282598fb8aeSGaetan Rivet 		break;
283598fb8aeSGaetan Rivet 	}
28482bae1eaSMatan Azrad 	sdev->remove = 0;
285598fb8aeSGaetan Rivet 	failsafe_hotplug_alarm_install(sdev->fs_dev);
286598fb8aeSGaetan Rivet }
287598fb8aeSGaetan Rivet 
2886265ab51SMatan Azrad static void
2896265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev)
2906265ab51SMatan Azrad {
291321809bbSMatan Azrad 	struct rte_eth_stats stats;
292321809bbSMatan Azrad 	int err;
293321809bbSMatan Azrad 
294321809bbSMatan Azrad 	/* Attempt to read current stats. */
295321809bbSMatan Azrad 	err = rte_eth_stats_get(PORT_ID(sdev), &stats);
2969dda3e33SMatan Azrad 	if (err) {
2979dda3e33SMatan Azrad 		uint64_t timestamp = sdev->stats_snapshot.timestamp;
2989dda3e33SMatan Azrad 
2999dda3e33SMatan Azrad 		WARN("Could not access latest statistics from sub-device %d.\n",
3009dda3e33SMatan Azrad 			 SUB_ID(sdev));
3019dda3e33SMatan Azrad 		if (timestamp != 0)
3029dda3e33SMatan Azrad 			WARN("Using latest snapshot taken before %"PRIu64" seconds.\n",
3039dda3e33SMatan Azrad 				 (rte_rdtsc() - timestamp) / rte_get_tsc_hz());
3049dda3e33SMatan Azrad 	}
3056265ab51SMatan Azrad 	failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator,
3069dda3e33SMatan Azrad 			err ? &sdev->stats_snapshot.stats : &stats);
3079dda3e33SMatan Azrad 	memset(&sdev->stats_snapshot, 0, sizeof(sdev->stats_snapshot));
3086265ab51SMatan Azrad }
3096265ab51SMatan Azrad 
310598fb8aeSGaetan Rivet static inline int
311598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev)
312598fb8aeSGaetan Rivet {
313598fb8aeSGaetan Rivet 	uint16_t i;
314598fb8aeSGaetan Rivet 
315598fb8aeSGaetan Rivet 	for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++)
316598fb8aeSGaetan Rivet 		if (FS_ATOMIC_RX(sdev, i))
317598fb8aeSGaetan Rivet 			return 0;
318598fb8aeSGaetan Rivet 	for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++)
319598fb8aeSGaetan Rivet 		if (FS_ATOMIC_TX(sdev, i))
320598fb8aeSGaetan Rivet 			return 0;
321598fb8aeSGaetan Rivet 	return 1;
322598fb8aeSGaetan Rivet }
323598fb8aeSGaetan Rivet 
324598fb8aeSGaetan Rivet void
325*0545c580SMatan Azrad failsafe_eth_dev_unregister_callbacks(struct sub_device *sdev)
326*0545c580SMatan Azrad {
327*0545c580SMatan Azrad 	int ret;
328*0545c580SMatan Azrad 
329*0545c580SMatan Azrad 	if (sdev == NULL)
330*0545c580SMatan Azrad 		return;
331*0545c580SMatan Azrad 	if (sdev->rmv_callback) {
332*0545c580SMatan Azrad 		ret = rte_eth_dev_callback_unregister(PORT_ID(sdev),
333*0545c580SMatan Azrad 						RTE_ETH_EVENT_INTR_RMV,
334*0545c580SMatan Azrad 						failsafe_eth_rmv_event_callback,
335*0545c580SMatan Azrad 						sdev);
336*0545c580SMatan Azrad 		if (ret)
337*0545c580SMatan Azrad 			WARN("Failed to unregister RMV callback for sub_device"
338*0545c580SMatan Azrad 			     " %d", SUB_ID(sdev));
339*0545c580SMatan Azrad 		sdev->rmv_callback = 0;
340*0545c580SMatan Azrad 	}
341*0545c580SMatan Azrad 	if (sdev->lsc_callback) {
342*0545c580SMatan Azrad 		ret = rte_eth_dev_callback_unregister(PORT_ID(sdev),
343*0545c580SMatan Azrad 						RTE_ETH_EVENT_INTR_LSC,
344*0545c580SMatan Azrad 						failsafe_eth_lsc_event_callback,
345*0545c580SMatan Azrad 						sdev);
346*0545c580SMatan Azrad 		if (ret)
347*0545c580SMatan Azrad 			WARN("Failed to unregister LSC callback for sub_device"
348*0545c580SMatan Azrad 			     " %d", SUB_ID(sdev));
349*0545c580SMatan Azrad 		sdev->lsc_callback = 0;
350*0545c580SMatan Azrad 	}
351*0545c580SMatan Azrad }
352*0545c580SMatan Azrad 
353*0545c580SMatan Azrad void
354598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev)
355598fb8aeSGaetan Rivet {
356598fb8aeSGaetan Rivet 	struct sub_device *sdev;
357598fb8aeSGaetan Rivet 	uint8_t i;
358598fb8aeSGaetan Rivet 
359598fb8aeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
3606265ab51SMatan Azrad 		if (sdev->remove && fs_rxtx_clean(sdev)) {
361655fcd68SMatan Azrad 			if (fs_lock(dev, 1) != 0)
362655fcd68SMatan Azrad 				return;
3636265ab51SMatan Azrad 			fs_dev_stats_save(sdev);
364598fb8aeSGaetan Rivet 			fs_dev_remove(sdev);
365655fcd68SMatan Azrad 			fs_unlock(dev, 1);
366598fb8aeSGaetan Rivet 		}
3676265ab51SMatan Azrad }
368598fb8aeSGaetan Rivet 
369ebea83f8SGaetan Rivet int
370ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
371ebea83f8SGaetan Rivet {
372ebea83f8SGaetan Rivet 	struct sub_device *sdev;
373ebea83f8SGaetan Rivet 	uint32_t inactive;
374ebea83f8SGaetan Rivet 	int ret;
375ebea83f8SGaetan Rivet 	uint8_t i;
376ebea83f8SGaetan Rivet 
377a0194d82SGaetan Rivet 	if (PRIV(dev)->state < DEV_PARSED)
378a0194d82SGaetan Rivet 		return 0;
379a0194d82SGaetan Rivet 
380a0194d82SGaetan Rivet 	ret = failsafe_args_parse_subs(dev);
381a0194d82SGaetan Rivet 	if (ret)
382598fb8aeSGaetan Rivet 		goto err_remove;
383a0194d82SGaetan Rivet 
384ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_PROBED)
385ebea83f8SGaetan Rivet 		return 0;
386ebea83f8SGaetan Rivet 	ret = failsafe_eal_init(dev);
387ebea83f8SGaetan Rivet 	if (ret)
388598fb8aeSGaetan Rivet 		goto err_remove;
389ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_ACTIVE)
390ebea83f8SGaetan Rivet 		return 0;
391ebea83f8SGaetan Rivet 	inactive = 0;
3922cc52cd7SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
3932cc52cd7SGaetan Rivet 		if (sdev->state == DEV_PROBED) {
394ebea83f8SGaetan Rivet 			inactive |= UINT32_C(1) << i;
3952cc52cd7SGaetan Rivet 			ret = eth_dev_flow_isolate_set(dev, sdev);
3962cc52cd7SGaetan Rivet 			if (ret) {
3972cc52cd7SGaetan Rivet 				ERROR("Could not apply configuration to sub_device %d",
3982cc52cd7SGaetan Rivet 				      i);
3992cc52cd7SGaetan Rivet 				goto err_remove;
4002cc52cd7SGaetan Rivet 			}
4012cc52cd7SGaetan Rivet 		}
4022cc52cd7SGaetan Rivet 	}
403ebea83f8SGaetan Rivet 	ret = dev->dev_ops->dev_configure(dev);
404ebea83f8SGaetan Rivet 	if (ret)
405598fb8aeSGaetan Rivet 		goto err_remove;
406ebea83f8SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
407ebea83f8SGaetan Rivet 		if (inactive & (UINT32_C(1) << i)) {
408ebea83f8SGaetan Rivet 			ret = fs_eth_dev_conf_apply(dev, sdev);
409ebea83f8SGaetan Rivet 			if (ret) {
410ebea83f8SGaetan Rivet 				ERROR("Could not apply configuration to sub_device %d",
411ebea83f8SGaetan Rivet 				      i);
412598fb8aeSGaetan Rivet 				goto err_remove;
413ebea83f8SGaetan Rivet 			}
414ebea83f8SGaetan Rivet 		}
415ebea83f8SGaetan Rivet 	}
416ebea83f8SGaetan Rivet 	/*
417ebea83f8SGaetan Rivet 	 * If new devices have been configured, check if
418ebea83f8SGaetan Rivet 	 * the link state has changed.
419ebea83f8SGaetan Rivet 	 */
420ebea83f8SGaetan Rivet 	if (inactive)
421ebea83f8SGaetan Rivet 		dev->dev_ops->link_update(dev, 1);
422ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_STARTED)
423ebea83f8SGaetan Rivet 		return 0;
424ebea83f8SGaetan Rivet 	ret = dev->dev_ops->dev_start(dev);
425ebea83f8SGaetan Rivet 	if (ret)
426598fb8aeSGaetan Rivet 		goto err_remove;
427598fb8aeSGaetan Rivet 	return 0;
428598fb8aeSGaetan Rivet err_remove:
429598fb8aeSGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev)
430598fb8aeSGaetan Rivet 		if (sdev->state != PRIV(dev)->state)
431598fb8aeSGaetan Rivet 			sdev->remove = 1;
432ebea83f8SGaetan Rivet 	return ret;
433598fb8aeSGaetan Rivet }
434598fb8aeSGaetan Rivet 
4356265ab51SMatan Azrad void
4366265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from)
4376265ab51SMatan Azrad {
4386265ab51SMatan Azrad 	uint32_t i;
4396265ab51SMatan Azrad 
4406265ab51SMatan Azrad 	RTE_ASSERT(to != NULL && from != NULL);
4416265ab51SMatan Azrad 	to->ipackets += from->ipackets;
4426265ab51SMatan Azrad 	to->opackets += from->opackets;
4436265ab51SMatan Azrad 	to->ibytes += from->ibytes;
4446265ab51SMatan Azrad 	to->obytes += from->obytes;
4456265ab51SMatan Azrad 	to->imissed += from->imissed;
4466265ab51SMatan Azrad 	to->ierrors += from->ierrors;
4476265ab51SMatan Azrad 	to->oerrors += from->oerrors;
4486265ab51SMatan Azrad 	to->rx_nombuf += from->rx_nombuf;
4496265ab51SMatan Azrad 	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
4506265ab51SMatan Azrad 		to->q_ipackets[i] += from->q_ipackets[i];
4516265ab51SMatan Azrad 		to->q_opackets[i] += from->q_opackets[i];
4526265ab51SMatan Azrad 		to->q_ibytes[i] += from->q_ibytes[i];
4536265ab51SMatan Azrad 		to->q_obytes[i] += from->q_obytes[i];
4546265ab51SMatan Azrad 		to->q_errors[i] += from->q_errors[i];
4556265ab51SMatan Azrad 	}
4566265ab51SMatan Azrad }
4576265ab51SMatan Azrad 
458598fb8aeSGaetan Rivet int
459f8244c63SZhiyong Yang failsafe_eth_rmv_event_callback(uint16_t port_id __rte_unused,
460598fb8aeSGaetan Rivet 				enum rte_eth_event_type event __rte_unused,
461598fb8aeSGaetan Rivet 				void *cb_arg, void *out __rte_unused)
462598fb8aeSGaetan Rivet {
463598fb8aeSGaetan Rivet 	struct sub_device *sdev = cb_arg;
464598fb8aeSGaetan Rivet 
465655fcd68SMatan Azrad 	fs_lock(sdev->fs_dev, 0);
466598fb8aeSGaetan Rivet 	/* Switch as soon as possible tx_dev. */
467598fb8aeSGaetan Rivet 	fs_switch_dev(sdev->fs_dev, sdev);
468598fb8aeSGaetan Rivet 	/* Use safe bursts in any case. */
469598fb8aeSGaetan Rivet 	set_burst_fn(sdev->fs_dev, 1);
470598fb8aeSGaetan Rivet 	/*
471598fb8aeSGaetan Rivet 	 * Async removal, the sub-PMD will try to unregister
472598fb8aeSGaetan Rivet 	 * the callback at the source of the current thread context.
473598fb8aeSGaetan Rivet 	 */
474598fb8aeSGaetan Rivet 	sdev->remove = 1;
475655fcd68SMatan Azrad 	fs_unlock(sdev->fs_dev, 0);
476ebea83f8SGaetan Rivet 	return 0;
477ebea83f8SGaetan Rivet }
478ad7d6a35SGaetan Rivet 
479ad7d6a35SGaetan Rivet int
480f8244c63SZhiyong Yang failsafe_eth_lsc_event_callback(uint16_t port_id __rte_unused,
481ad7d6a35SGaetan Rivet 				enum rte_eth_event_type event __rte_unused,
482ad7d6a35SGaetan Rivet 				void *cb_arg, void *out __rte_unused)
483ad7d6a35SGaetan Rivet {
484ad7d6a35SGaetan Rivet 	struct rte_eth_dev *dev = cb_arg;
485ad7d6a35SGaetan Rivet 	int ret;
486ad7d6a35SGaetan Rivet 
487ad7d6a35SGaetan Rivet 	ret = dev->dev_ops->link_update(dev, 0);
488ad7d6a35SGaetan Rivet 	/* We must pass on the LSC event */
489ad7d6a35SGaetan Rivet 	if (ret)
490ad7d6a35SGaetan Rivet 		return _rte_eth_dev_callback_process(dev,
491ad7d6a35SGaetan Rivet 						     RTE_ETH_EVENT_INTR_LSC,
492cebe3d7bSThomas Monjalon 						     NULL);
493ad7d6a35SGaetan Rivet 	else
494ad7d6a35SGaetan Rivet 		return 0;
495ad7d6a35SGaetan Rivet }
4967fda13d3SMatan Azrad 
4977fda13d3SMatan Azrad /* Take sub-device ownership before it becomes exposed to the application. */
4987fda13d3SMatan Azrad int
4997fda13d3SMatan Azrad failsafe_eth_new_event_callback(uint16_t port_id,
5007fda13d3SMatan Azrad 				enum rte_eth_event_type event __rte_unused,
5017fda13d3SMatan Azrad 				void *cb_arg, void *out __rte_unused)
5027fda13d3SMatan Azrad {
5037fda13d3SMatan Azrad 	struct rte_eth_dev *fs_dev = cb_arg;
5047fda13d3SMatan Azrad 	struct sub_device *sdev;
5057fda13d3SMatan Azrad 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
5067fda13d3SMatan Azrad 	uint8_t i;
5077fda13d3SMatan Azrad 
5087fda13d3SMatan Azrad 	FOREACH_SUBDEV_STATE(sdev, i, fs_dev, DEV_PARSED) {
5097fda13d3SMatan Azrad 		if (sdev->state >= DEV_PROBED)
5107fda13d3SMatan Azrad 			continue;
5117fda13d3SMatan Azrad 		if (strcmp(sdev->devargs.name, dev->device->name) != 0)
5127fda13d3SMatan Azrad 			continue;
5137fda13d3SMatan Azrad 		rte_eth_dev_owner_set(port_id, &PRIV(fs_dev)->my_owner);
5147fda13d3SMatan Azrad 		/* The actual owner will be checked after the port probing. */
5157fda13d3SMatan Azrad 		break;
5167fda13d3SMatan Azrad 	}
5177fda13d3SMatan Azrad 	return 0;
5187fda13d3SMatan Azrad }
519