xref: /dpdk/drivers/net/failsafe/failsafe_ether.c (revision 6265ab51b827e6c33d5c01fe7dd13057b642c88e)
1ebea83f8SGaetan Rivet /*-
2ebea83f8SGaetan Rivet  *   BSD LICENSE
3ebea83f8SGaetan Rivet  *
4ebea83f8SGaetan Rivet  *   Copyright 2017 6WIND S.A.
5ebea83f8SGaetan Rivet  *   Copyright 2017 Mellanox.
6ebea83f8SGaetan Rivet  *
7ebea83f8SGaetan Rivet  *   Redistribution and use in source and binary forms, with or without
8ebea83f8SGaetan Rivet  *   modification, are permitted provided that the following conditions
9ebea83f8SGaetan Rivet  *   are met:
10ebea83f8SGaetan Rivet  *
11ebea83f8SGaetan Rivet  *     * Redistributions of source code must retain the above copyright
12ebea83f8SGaetan Rivet  *       notice, this list of conditions and the following disclaimer.
13ebea83f8SGaetan Rivet  *     * Redistributions in binary form must reproduce the above copyright
14ebea83f8SGaetan Rivet  *       notice, this list of conditions and the following disclaimer in
15ebea83f8SGaetan Rivet  *       the documentation and/or other materials provided with the
16ebea83f8SGaetan Rivet  *       distribution.
17ebea83f8SGaetan Rivet  *     * Neither the name of 6WIND S.A. nor the names of its
18ebea83f8SGaetan Rivet  *       contributors may be used to endorse or promote products derived
19ebea83f8SGaetan Rivet  *       from this software without specific prior written permission.
20ebea83f8SGaetan Rivet  *
21ebea83f8SGaetan Rivet  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22ebea83f8SGaetan Rivet  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23ebea83f8SGaetan Rivet  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24ebea83f8SGaetan Rivet  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25ebea83f8SGaetan Rivet  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26ebea83f8SGaetan Rivet  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27ebea83f8SGaetan Rivet  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28ebea83f8SGaetan Rivet  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29ebea83f8SGaetan Rivet  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30ebea83f8SGaetan Rivet  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31ebea83f8SGaetan Rivet  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32ebea83f8SGaetan Rivet  */
33ebea83f8SGaetan Rivet 
34ebea83f8SGaetan Rivet #include <unistd.h>
35ebea83f8SGaetan Rivet 
36b737a1eeSGaetan Rivet #include <rte_flow.h>
37b737a1eeSGaetan Rivet #include <rte_flow_driver.h>
38b737a1eeSGaetan Rivet 
39ebea83f8SGaetan Rivet #include "failsafe_private.h"
40ebea83f8SGaetan Rivet 
41b737a1eeSGaetan Rivet /** Print a message out of a flow error. */
42b737a1eeSGaetan Rivet static int
43b737a1eeSGaetan Rivet fs_flow_complain(struct rte_flow_error *error)
44b737a1eeSGaetan Rivet {
45b737a1eeSGaetan Rivet 	static const char *const errstrlist[] = {
46b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_NONE] = "no error",
47b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
48b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
49b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
50b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
51b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
52b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
53b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
54b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
55b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
56b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
57b737a1eeSGaetan Rivet 		[RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
58b737a1eeSGaetan Rivet 	};
59b737a1eeSGaetan Rivet 	const char *errstr;
60b737a1eeSGaetan Rivet 	char buf[32];
61b737a1eeSGaetan Rivet 	int err = rte_errno;
62b737a1eeSGaetan Rivet 
63b737a1eeSGaetan Rivet 	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
64b737a1eeSGaetan Rivet 			!errstrlist[error->type])
65b737a1eeSGaetan Rivet 		errstr = "unknown type";
66b737a1eeSGaetan Rivet 	else
67b737a1eeSGaetan Rivet 		errstr = errstrlist[error->type];
68b737a1eeSGaetan Rivet 	ERROR("Caught error type %d (%s): %s%s\n",
69b737a1eeSGaetan Rivet 		error->type, errstr,
70b737a1eeSGaetan Rivet 		error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
71b737a1eeSGaetan Rivet 				error->cause), buf) : "",
72b737a1eeSGaetan Rivet 		error->message ? error->message : "(no stated reason)");
73b737a1eeSGaetan Rivet 	return -err;
74b737a1eeSGaetan Rivet }
75b737a1eeSGaetan Rivet 
76ebea83f8SGaetan Rivet static int
772cc52cd7SGaetan Rivet eth_dev_flow_isolate_set(struct rte_eth_dev *dev,
782cc52cd7SGaetan Rivet 			 struct sub_device *sdev)
792cc52cd7SGaetan Rivet {
802cc52cd7SGaetan Rivet 	struct rte_flow_error ferror;
812cc52cd7SGaetan Rivet 	int ret;
822cc52cd7SGaetan Rivet 
832cc52cd7SGaetan Rivet 	if (!PRIV(dev)->flow_isolated) {
842cc52cd7SGaetan Rivet 		DEBUG("Flow isolation already disabled");
852cc52cd7SGaetan Rivet 	} else {
862cc52cd7SGaetan Rivet 		DEBUG("Enabling flow isolation");
872cc52cd7SGaetan Rivet 		ret = rte_flow_isolate(PORT_ID(sdev),
882cc52cd7SGaetan Rivet 				       PRIV(dev)->flow_isolated,
892cc52cd7SGaetan Rivet 				       &ferror);
902cc52cd7SGaetan Rivet 		if (ret) {
912cc52cd7SGaetan Rivet 			fs_flow_complain(&ferror);
922cc52cd7SGaetan Rivet 			return ret;
932cc52cd7SGaetan Rivet 		}
942cc52cd7SGaetan Rivet 	}
952cc52cd7SGaetan Rivet 	return 0;
962cc52cd7SGaetan Rivet }
972cc52cd7SGaetan Rivet 
982cc52cd7SGaetan Rivet static int
99ebea83f8SGaetan Rivet fs_eth_dev_conf_apply(struct rte_eth_dev *dev,
100ebea83f8SGaetan Rivet 		struct sub_device *sdev)
101ebea83f8SGaetan Rivet {
102ebea83f8SGaetan Rivet 	struct rte_eth_dev *edev;
103ebea83f8SGaetan Rivet 	struct rte_vlan_filter_conf *vfc1;
104ebea83f8SGaetan Rivet 	struct rte_vlan_filter_conf *vfc2;
105b737a1eeSGaetan Rivet 	struct rte_flow *flow;
106b737a1eeSGaetan Rivet 	struct rte_flow_error ferror;
107ebea83f8SGaetan Rivet 	uint32_t i;
108ebea83f8SGaetan Rivet 	int ret;
109ebea83f8SGaetan Rivet 
110ebea83f8SGaetan Rivet 	edev = ETH(sdev);
111ebea83f8SGaetan Rivet 	/* RX queue setup */
112ebea83f8SGaetan Rivet 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
113ebea83f8SGaetan Rivet 		struct rxq *rxq;
114ebea83f8SGaetan Rivet 
115ebea83f8SGaetan Rivet 		rxq = dev->data->rx_queues[i];
116ebea83f8SGaetan Rivet 		ret = rte_eth_rx_queue_setup(PORT_ID(sdev), i,
117ebea83f8SGaetan Rivet 				rxq->info.nb_desc, rxq->socket_id,
118ebea83f8SGaetan Rivet 				&rxq->info.conf, rxq->info.mp);
119ebea83f8SGaetan Rivet 		if (ret) {
120ebea83f8SGaetan Rivet 			ERROR("rx_queue_setup failed");
121ebea83f8SGaetan Rivet 			return ret;
122ebea83f8SGaetan Rivet 		}
123ebea83f8SGaetan Rivet 	}
124ebea83f8SGaetan Rivet 	/* TX queue setup */
125ebea83f8SGaetan Rivet 	for (i = 0; i < dev->data->nb_tx_queues; i++) {
126ebea83f8SGaetan Rivet 		struct txq *txq;
127ebea83f8SGaetan Rivet 
128ebea83f8SGaetan Rivet 		txq = dev->data->tx_queues[i];
129ebea83f8SGaetan Rivet 		ret = rte_eth_tx_queue_setup(PORT_ID(sdev), i,
130ebea83f8SGaetan Rivet 				txq->info.nb_desc, txq->socket_id,
131ebea83f8SGaetan Rivet 				&txq->info.conf);
132ebea83f8SGaetan Rivet 		if (ret) {
133ebea83f8SGaetan Rivet 			ERROR("tx_queue_setup failed");
134ebea83f8SGaetan Rivet 			return ret;
135ebea83f8SGaetan Rivet 		}
136ebea83f8SGaetan Rivet 	}
137ebea83f8SGaetan Rivet 	/* dev_link.link_status */
138ebea83f8SGaetan Rivet 	if (dev->data->dev_link.link_status !=
139ebea83f8SGaetan Rivet 	    edev->data->dev_link.link_status) {
140ebea83f8SGaetan Rivet 		DEBUG("Configuring link_status");
141ebea83f8SGaetan Rivet 		if (dev->data->dev_link.link_status)
142ebea83f8SGaetan Rivet 			ret = rte_eth_dev_set_link_up(PORT_ID(sdev));
143ebea83f8SGaetan Rivet 		else
144ebea83f8SGaetan Rivet 			ret = rte_eth_dev_set_link_down(PORT_ID(sdev));
145ebea83f8SGaetan Rivet 		if (ret) {
146ebea83f8SGaetan Rivet 			ERROR("Failed to apply link_status");
147ebea83f8SGaetan Rivet 			return ret;
148ebea83f8SGaetan Rivet 		}
149ebea83f8SGaetan Rivet 	} else {
150ebea83f8SGaetan Rivet 		DEBUG("link_status already set");
151ebea83f8SGaetan Rivet 	}
152ebea83f8SGaetan Rivet 	/* promiscuous */
153ebea83f8SGaetan Rivet 	if (dev->data->promiscuous != edev->data->promiscuous) {
154ebea83f8SGaetan Rivet 		DEBUG("Configuring promiscuous");
155ebea83f8SGaetan Rivet 		if (dev->data->promiscuous)
156ebea83f8SGaetan Rivet 			rte_eth_promiscuous_enable(PORT_ID(sdev));
157ebea83f8SGaetan Rivet 		else
158ebea83f8SGaetan Rivet 			rte_eth_promiscuous_disable(PORT_ID(sdev));
159ebea83f8SGaetan Rivet 	} else {
160ebea83f8SGaetan Rivet 		DEBUG("promiscuous already set");
161ebea83f8SGaetan Rivet 	}
162ebea83f8SGaetan Rivet 	/* all_multicast */
163ebea83f8SGaetan Rivet 	if (dev->data->all_multicast != edev->data->all_multicast) {
164ebea83f8SGaetan Rivet 		DEBUG("Configuring all_multicast");
165ebea83f8SGaetan Rivet 		if (dev->data->all_multicast)
166ebea83f8SGaetan Rivet 			rte_eth_allmulticast_enable(PORT_ID(sdev));
167ebea83f8SGaetan Rivet 		else
168ebea83f8SGaetan Rivet 			rte_eth_allmulticast_disable(PORT_ID(sdev));
169ebea83f8SGaetan Rivet 	} else {
170ebea83f8SGaetan Rivet 		DEBUG("all_multicast already set");
171ebea83f8SGaetan Rivet 	}
172ebea83f8SGaetan Rivet 	/* MTU */
173ebea83f8SGaetan Rivet 	if (dev->data->mtu != edev->data->mtu) {
174ebea83f8SGaetan Rivet 		DEBUG("Configuring MTU");
175ebea83f8SGaetan Rivet 		ret = rte_eth_dev_set_mtu(PORT_ID(sdev), dev->data->mtu);
176ebea83f8SGaetan Rivet 		if (ret) {
177ebea83f8SGaetan Rivet 			ERROR("Failed to apply MTU");
178ebea83f8SGaetan Rivet 			return ret;
179ebea83f8SGaetan Rivet 		}
180ebea83f8SGaetan Rivet 	} else {
181ebea83f8SGaetan Rivet 		DEBUG("MTU already set");
182ebea83f8SGaetan Rivet 	}
183ebea83f8SGaetan Rivet 	/* default MAC */
184ebea83f8SGaetan Rivet 	DEBUG("Configuring default MAC address");
185ebea83f8SGaetan Rivet 	ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
186ebea83f8SGaetan Rivet 			&dev->data->mac_addrs[0]);
187ebea83f8SGaetan Rivet 	if (ret) {
188ebea83f8SGaetan Rivet 		ERROR("Setting default MAC address failed");
189ebea83f8SGaetan Rivet 		return ret;
190ebea83f8SGaetan Rivet 	}
191ebea83f8SGaetan Rivet 	/* additional MAC */
192ebea83f8SGaetan Rivet 	if (PRIV(dev)->nb_mac_addr > 1)
193ebea83f8SGaetan Rivet 		DEBUG("Configure additional MAC address%s",
194ebea83f8SGaetan Rivet 			(PRIV(dev)->nb_mac_addr > 2 ? "es" : ""));
195ebea83f8SGaetan Rivet 	for (i = 1; i < PRIV(dev)->nb_mac_addr; i++) {
196ebea83f8SGaetan Rivet 		struct ether_addr *ea;
197ebea83f8SGaetan Rivet 
198ebea83f8SGaetan Rivet 		ea = &dev->data->mac_addrs[i];
199ebea83f8SGaetan Rivet 		ret = rte_eth_dev_mac_addr_add(PORT_ID(sdev), ea,
200ebea83f8SGaetan Rivet 				PRIV(dev)->mac_addr_pool[i]);
201ebea83f8SGaetan Rivet 		if (ret) {
202ebea83f8SGaetan Rivet 			char ea_fmt[ETHER_ADDR_FMT_SIZE];
203ebea83f8SGaetan Rivet 
204ebea83f8SGaetan Rivet 			ether_format_addr(ea_fmt, ETHER_ADDR_FMT_SIZE, ea);
205ebea83f8SGaetan Rivet 			ERROR("Adding MAC address %s failed", ea_fmt);
206ae7cb246SMatan Azrad 			return ret;
207ebea83f8SGaetan Rivet 		}
208ebea83f8SGaetan Rivet 	}
209ebea83f8SGaetan Rivet 	/* VLAN filter */
210ebea83f8SGaetan Rivet 	vfc1 = &dev->data->vlan_filter_conf;
211ebea83f8SGaetan Rivet 	vfc2 = &edev->data->vlan_filter_conf;
212ebea83f8SGaetan Rivet 	if (memcmp(vfc1, vfc2, sizeof(struct rte_vlan_filter_conf))) {
213ebea83f8SGaetan Rivet 		uint64_t vbit;
214ebea83f8SGaetan Rivet 		uint64_t ids;
215ebea83f8SGaetan Rivet 		size_t i;
216ebea83f8SGaetan Rivet 		uint16_t vlan_id;
217ebea83f8SGaetan Rivet 
218ebea83f8SGaetan Rivet 		DEBUG("Configuring VLAN filter");
219ebea83f8SGaetan Rivet 		for (i = 0; i < RTE_DIM(vfc1->ids); i++) {
220ebea83f8SGaetan Rivet 			if (vfc1->ids[i] == 0)
221ebea83f8SGaetan Rivet 				continue;
222ebea83f8SGaetan Rivet 			ids = vfc1->ids[i];
223ebea83f8SGaetan Rivet 			while (ids) {
224ebea83f8SGaetan Rivet 				vlan_id = 64 * i;
225ebea83f8SGaetan Rivet 				/* count trailing zeroes */
226ebea83f8SGaetan Rivet 				vbit = ~ids & (ids - 1);
227ebea83f8SGaetan Rivet 				/* clear least significant bit set */
228ebea83f8SGaetan Rivet 				ids ^= (ids ^ (ids - 1)) ^ vbit;
229ebea83f8SGaetan Rivet 				for (; vbit; vlan_id++)
230ebea83f8SGaetan Rivet 					vbit >>= 1;
231ebea83f8SGaetan Rivet 				ret = rte_eth_dev_vlan_filter(
232ebea83f8SGaetan Rivet 					PORT_ID(sdev), vlan_id, 1);
233ebea83f8SGaetan Rivet 				if (ret) {
234ebea83f8SGaetan Rivet 					ERROR("Failed to apply VLAN filter %hu",
235ebea83f8SGaetan Rivet 						vlan_id);
236ebea83f8SGaetan Rivet 					return ret;
237ebea83f8SGaetan Rivet 				}
238ebea83f8SGaetan Rivet 			}
239ebea83f8SGaetan Rivet 		}
240ebea83f8SGaetan Rivet 	} else {
241ebea83f8SGaetan Rivet 		DEBUG("VLAN filter already set");
242ebea83f8SGaetan Rivet 	}
243b737a1eeSGaetan Rivet 	/* rte_flow */
244b737a1eeSGaetan Rivet 	if (TAILQ_EMPTY(&PRIV(dev)->flow_list)) {
245b737a1eeSGaetan Rivet 		DEBUG("rte_flow already set");
246b737a1eeSGaetan Rivet 	} else {
247b737a1eeSGaetan Rivet 		DEBUG("Resetting rte_flow configuration");
248b737a1eeSGaetan Rivet 		ret = rte_flow_flush(PORT_ID(sdev), &ferror);
249b737a1eeSGaetan Rivet 		if (ret) {
250b737a1eeSGaetan Rivet 			fs_flow_complain(&ferror);
251b737a1eeSGaetan Rivet 			return ret;
252b737a1eeSGaetan Rivet 		}
253b737a1eeSGaetan Rivet 		i = 0;
254b737a1eeSGaetan Rivet 		rte_errno = 0;
255b737a1eeSGaetan Rivet 		DEBUG("Configuring rte_flow");
256b737a1eeSGaetan Rivet 		TAILQ_FOREACH(flow, &PRIV(dev)->flow_list, next) {
257b737a1eeSGaetan Rivet 			DEBUG("Creating flow #%" PRIu32, i++);
258b737a1eeSGaetan Rivet 			flow->flows[SUB_ID(sdev)] =
259b737a1eeSGaetan Rivet 				rte_flow_create(PORT_ID(sdev),
260b737a1eeSGaetan Rivet 						&flow->fd->attr,
261b737a1eeSGaetan Rivet 						flow->fd->items,
262b737a1eeSGaetan Rivet 						flow->fd->actions,
263b737a1eeSGaetan Rivet 						&ferror);
264b737a1eeSGaetan Rivet 			ret = rte_errno;
265b737a1eeSGaetan Rivet 			if (ret)
266b737a1eeSGaetan Rivet 				break;
267b737a1eeSGaetan Rivet 		}
268b737a1eeSGaetan Rivet 		if (ret) {
269b737a1eeSGaetan Rivet 			fs_flow_complain(&ferror);
270b737a1eeSGaetan Rivet 			return ret;
271b737a1eeSGaetan Rivet 		}
272b737a1eeSGaetan Rivet 	}
273ebea83f8SGaetan Rivet 	return 0;
274ebea83f8SGaetan Rivet }
275ebea83f8SGaetan Rivet 
276598fb8aeSGaetan Rivet static void
277598fb8aeSGaetan Rivet fs_dev_remove(struct sub_device *sdev)
278598fb8aeSGaetan Rivet {
279598fb8aeSGaetan Rivet 	int ret;
280598fb8aeSGaetan Rivet 
281598fb8aeSGaetan Rivet 	if (sdev == NULL)
282598fb8aeSGaetan Rivet 		return;
283598fb8aeSGaetan Rivet 	switch (sdev->state) {
284598fb8aeSGaetan Rivet 	case DEV_STARTED:
285598fb8aeSGaetan Rivet 		rte_eth_dev_stop(PORT_ID(sdev));
286598fb8aeSGaetan Rivet 		sdev->state = DEV_ACTIVE;
287598fb8aeSGaetan Rivet 		/* fallthrough */
288598fb8aeSGaetan Rivet 	case DEV_ACTIVE:
289598fb8aeSGaetan Rivet 		rte_eth_dev_close(PORT_ID(sdev));
290598fb8aeSGaetan Rivet 		sdev->state = DEV_PROBED;
291598fb8aeSGaetan Rivet 		/* fallthrough */
292598fb8aeSGaetan Rivet 	case DEV_PROBED:
293598fb8aeSGaetan Rivet 		ret = rte_eal_hotplug_remove(sdev->bus->name,
294598fb8aeSGaetan Rivet 					     sdev->dev->name);
295598fb8aeSGaetan Rivet 		if (ret) {
296598fb8aeSGaetan Rivet 			ERROR("Bus detach failed for sub_device %u",
297598fb8aeSGaetan Rivet 			      SUB_ID(sdev));
298598fb8aeSGaetan Rivet 		} else {
299598fb8aeSGaetan Rivet 			ETH(sdev)->state = RTE_ETH_DEV_UNUSED;
300598fb8aeSGaetan Rivet 		}
301598fb8aeSGaetan Rivet 		sdev->state = DEV_PARSED;
302598fb8aeSGaetan Rivet 		/* fallthrough */
303598fb8aeSGaetan Rivet 	case DEV_PARSED:
304598fb8aeSGaetan Rivet 	case DEV_UNDEFINED:
305598fb8aeSGaetan Rivet 		sdev->state = DEV_UNDEFINED;
306598fb8aeSGaetan Rivet 		/* the end */
307598fb8aeSGaetan Rivet 		break;
308598fb8aeSGaetan Rivet 	}
309598fb8aeSGaetan Rivet 	failsafe_hotplug_alarm_install(sdev->fs_dev);
310598fb8aeSGaetan Rivet }
311598fb8aeSGaetan Rivet 
312*6265ab51SMatan Azrad static void
313*6265ab51SMatan Azrad fs_dev_stats_save(struct sub_device *sdev)
314*6265ab51SMatan Azrad {
315*6265ab51SMatan Azrad 	failsafe_stats_increment(&PRIV(sdev->fs_dev)->stats_accumulator,
316*6265ab51SMatan Azrad 			&sdev->stats_snapshot);
317*6265ab51SMatan Azrad 	memset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats));
318*6265ab51SMatan Azrad }
319*6265ab51SMatan Azrad 
320598fb8aeSGaetan Rivet static inline int
321598fb8aeSGaetan Rivet fs_rxtx_clean(struct sub_device *sdev)
322598fb8aeSGaetan Rivet {
323598fb8aeSGaetan Rivet 	uint16_t i;
324598fb8aeSGaetan Rivet 
325598fb8aeSGaetan Rivet 	for (i = 0; i < ETH(sdev)->data->nb_rx_queues; i++)
326598fb8aeSGaetan Rivet 		if (FS_ATOMIC_RX(sdev, i))
327598fb8aeSGaetan Rivet 			return 0;
328598fb8aeSGaetan Rivet 	for (i = 0; i < ETH(sdev)->data->nb_tx_queues; i++)
329598fb8aeSGaetan Rivet 		if (FS_ATOMIC_TX(sdev, i))
330598fb8aeSGaetan Rivet 			return 0;
331598fb8aeSGaetan Rivet 	return 1;
332598fb8aeSGaetan Rivet }
333598fb8aeSGaetan Rivet 
334598fb8aeSGaetan Rivet void
335598fb8aeSGaetan Rivet failsafe_dev_remove(struct rte_eth_dev *dev)
336598fb8aeSGaetan Rivet {
337598fb8aeSGaetan Rivet 	struct sub_device *sdev;
338598fb8aeSGaetan Rivet 	uint8_t i;
339598fb8aeSGaetan Rivet 
340598fb8aeSGaetan Rivet 	FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE)
341*6265ab51SMatan Azrad 		if (sdev->remove && fs_rxtx_clean(sdev)) {
342*6265ab51SMatan Azrad 			fs_dev_stats_save(sdev);
343598fb8aeSGaetan Rivet 			fs_dev_remove(sdev);
344598fb8aeSGaetan Rivet 		}
345*6265ab51SMatan Azrad }
346598fb8aeSGaetan Rivet 
347ebea83f8SGaetan Rivet int
348ebea83f8SGaetan Rivet failsafe_eth_dev_state_sync(struct rte_eth_dev *dev)
349ebea83f8SGaetan Rivet {
350ebea83f8SGaetan Rivet 	struct sub_device *sdev;
351ebea83f8SGaetan Rivet 	uint32_t inactive;
352ebea83f8SGaetan Rivet 	int ret;
353ebea83f8SGaetan Rivet 	uint8_t i;
354ebea83f8SGaetan Rivet 
355a0194d82SGaetan Rivet 	if (PRIV(dev)->state < DEV_PARSED)
356a0194d82SGaetan Rivet 		return 0;
357a0194d82SGaetan Rivet 
358a0194d82SGaetan Rivet 	ret = failsafe_args_parse_subs(dev);
359a0194d82SGaetan Rivet 	if (ret)
360598fb8aeSGaetan Rivet 		goto err_remove;
361a0194d82SGaetan Rivet 
362ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_PROBED)
363ebea83f8SGaetan Rivet 		return 0;
364ebea83f8SGaetan Rivet 	ret = failsafe_eal_init(dev);
365ebea83f8SGaetan Rivet 	if (ret)
366598fb8aeSGaetan Rivet 		goto err_remove;
367ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_ACTIVE)
368ebea83f8SGaetan Rivet 		return 0;
369ebea83f8SGaetan Rivet 	inactive = 0;
3702cc52cd7SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
3712cc52cd7SGaetan Rivet 		if (sdev->state == DEV_PROBED) {
372ebea83f8SGaetan Rivet 			inactive |= UINT32_C(1) << i;
3732cc52cd7SGaetan Rivet 			ret = eth_dev_flow_isolate_set(dev, sdev);
3742cc52cd7SGaetan Rivet 			if (ret) {
3752cc52cd7SGaetan Rivet 				ERROR("Could not apply configuration to sub_device %d",
3762cc52cd7SGaetan Rivet 				      i);
3772cc52cd7SGaetan Rivet 				goto err_remove;
3782cc52cd7SGaetan Rivet 			}
3792cc52cd7SGaetan Rivet 		}
3802cc52cd7SGaetan Rivet 	}
381ebea83f8SGaetan Rivet 	ret = dev->dev_ops->dev_configure(dev);
382ebea83f8SGaetan Rivet 	if (ret)
383598fb8aeSGaetan Rivet 		goto err_remove;
384ebea83f8SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
385ebea83f8SGaetan Rivet 		if (inactive & (UINT32_C(1) << i)) {
386ebea83f8SGaetan Rivet 			ret = fs_eth_dev_conf_apply(dev, sdev);
387ebea83f8SGaetan Rivet 			if (ret) {
388ebea83f8SGaetan Rivet 				ERROR("Could not apply configuration to sub_device %d",
389ebea83f8SGaetan Rivet 				      i);
390598fb8aeSGaetan Rivet 				goto err_remove;
391ebea83f8SGaetan Rivet 			}
392ebea83f8SGaetan Rivet 		}
393ebea83f8SGaetan Rivet 	}
394ebea83f8SGaetan Rivet 	/*
395ebea83f8SGaetan Rivet 	 * If new devices have been configured, check if
396ebea83f8SGaetan Rivet 	 * the link state has changed.
397ebea83f8SGaetan Rivet 	 */
398ebea83f8SGaetan Rivet 	if (inactive)
399ebea83f8SGaetan Rivet 		dev->dev_ops->link_update(dev, 1);
400ebea83f8SGaetan Rivet 	if (PRIV(dev)->state < DEV_STARTED)
401ebea83f8SGaetan Rivet 		return 0;
402ebea83f8SGaetan Rivet 	ret = dev->dev_ops->dev_start(dev);
403ebea83f8SGaetan Rivet 	if (ret)
404598fb8aeSGaetan Rivet 		goto err_remove;
405598fb8aeSGaetan Rivet 	return 0;
406598fb8aeSGaetan Rivet err_remove:
407598fb8aeSGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev)
408598fb8aeSGaetan Rivet 		if (sdev->state != PRIV(dev)->state)
409598fb8aeSGaetan Rivet 			sdev->remove = 1;
410ebea83f8SGaetan Rivet 	return ret;
411598fb8aeSGaetan Rivet }
412598fb8aeSGaetan Rivet 
413*6265ab51SMatan Azrad void
414*6265ab51SMatan Azrad failsafe_stats_increment(struct rte_eth_stats *to, struct rte_eth_stats *from)
415*6265ab51SMatan Azrad {
416*6265ab51SMatan Azrad 	uint32_t i;
417*6265ab51SMatan Azrad 
418*6265ab51SMatan Azrad 	RTE_ASSERT(to != NULL && from != NULL);
419*6265ab51SMatan Azrad 	to->ipackets += from->ipackets;
420*6265ab51SMatan Azrad 	to->opackets += from->opackets;
421*6265ab51SMatan Azrad 	to->ibytes += from->ibytes;
422*6265ab51SMatan Azrad 	to->obytes += from->obytes;
423*6265ab51SMatan Azrad 	to->imissed += from->imissed;
424*6265ab51SMatan Azrad 	to->ierrors += from->ierrors;
425*6265ab51SMatan Azrad 	to->oerrors += from->oerrors;
426*6265ab51SMatan Azrad 	to->rx_nombuf += from->rx_nombuf;
427*6265ab51SMatan Azrad 	for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
428*6265ab51SMatan Azrad 		to->q_ipackets[i] += from->q_ipackets[i];
429*6265ab51SMatan Azrad 		to->q_opackets[i] += from->q_opackets[i];
430*6265ab51SMatan Azrad 		to->q_ibytes[i] += from->q_ibytes[i];
431*6265ab51SMatan Azrad 		to->q_obytes[i] += from->q_obytes[i];
432*6265ab51SMatan Azrad 		to->q_errors[i] += from->q_errors[i];
433*6265ab51SMatan Azrad 	}
434*6265ab51SMatan Azrad }
435*6265ab51SMatan Azrad 
436598fb8aeSGaetan Rivet int
437598fb8aeSGaetan Rivet failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused,
438598fb8aeSGaetan Rivet 				enum rte_eth_event_type event __rte_unused,
439598fb8aeSGaetan Rivet 				void *cb_arg, void *out __rte_unused)
440598fb8aeSGaetan Rivet {
441598fb8aeSGaetan Rivet 	struct sub_device *sdev = cb_arg;
442598fb8aeSGaetan Rivet 
443598fb8aeSGaetan Rivet 	/* Switch as soon as possible tx_dev. */
444598fb8aeSGaetan Rivet 	fs_switch_dev(sdev->fs_dev, sdev);
445598fb8aeSGaetan Rivet 	/* Use safe bursts in any case. */
446598fb8aeSGaetan Rivet 	set_burst_fn(sdev->fs_dev, 1);
447598fb8aeSGaetan Rivet 	/*
448598fb8aeSGaetan Rivet 	 * Async removal, the sub-PMD will try to unregister
449598fb8aeSGaetan Rivet 	 * the callback at the source of the current thread context.
450598fb8aeSGaetan Rivet 	 */
451598fb8aeSGaetan Rivet 	sdev->remove = 1;
452ebea83f8SGaetan Rivet 	return 0;
453ebea83f8SGaetan Rivet }
454ad7d6a35SGaetan Rivet 
455ad7d6a35SGaetan Rivet int
456ad7d6a35SGaetan Rivet failsafe_eth_lsc_event_callback(uint8_t port_id __rte_unused,
457ad7d6a35SGaetan Rivet 				enum rte_eth_event_type event __rte_unused,
458ad7d6a35SGaetan Rivet 				void *cb_arg, void *out __rte_unused)
459ad7d6a35SGaetan Rivet {
460ad7d6a35SGaetan Rivet 	struct rte_eth_dev *dev = cb_arg;
461ad7d6a35SGaetan Rivet 	int ret;
462ad7d6a35SGaetan Rivet 
463ad7d6a35SGaetan Rivet 	ret = dev->dev_ops->link_update(dev, 0);
464ad7d6a35SGaetan Rivet 	/* We must pass on the LSC event */
465ad7d6a35SGaetan Rivet 	if (ret)
466ad7d6a35SGaetan Rivet 		return _rte_eth_dev_callback_process(dev,
467ad7d6a35SGaetan Rivet 						     RTE_ETH_EVENT_INTR_LSC,
468ad7d6a35SGaetan Rivet 						     NULL, NULL);
469ad7d6a35SGaetan Rivet 	else
470ad7d6a35SGaetan Rivet 		return 0;
471ad7d6a35SGaetan Rivet }
472