xref: /f-stack/dpdk/drivers/net/failsafe/failsafe.c (revision 4418919f)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
22bfe3f2eSlogwang  * Copyright 2017 6WIND S.A.
3d30ea906Sjfb8856606  * Copyright 2017 Mellanox Technologies, Ltd
42bfe3f2eSlogwang  */
52bfe3f2eSlogwang 
6*4418919fSjohnjiang #include <stdbool.h>
7*4418919fSjohnjiang 
82bfe3f2eSlogwang #include <rte_alarm.h>
92bfe3f2eSlogwang #include <rte_malloc.h>
10d30ea906Sjfb8856606 #include <rte_ethdev_driver.h>
112bfe3f2eSlogwang #include <rte_ethdev_vdev.h>
122bfe3f2eSlogwang #include <rte_devargs.h>
132bfe3f2eSlogwang #include <rte_kvargs.h>
142bfe3f2eSlogwang #include <rte_bus_vdev.h>
152bfe3f2eSlogwang 
162bfe3f2eSlogwang #include "failsafe_private.h"
172bfe3f2eSlogwang 
18d30ea906Sjfb8856606 int failsafe_logtype;
19d30ea906Sjfb8856606 
202bfe3f2eSlogwang const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
212bfe3f2eSlogwang static const struct rte_eth_link eth_link = {
222bfe3f2eSlogwang 	.link_speed = ETH_SPEED_NUM_10G,
232bfe3f2eSlogwang 	.link_duplex = ETH_LINK_FULL_DUPLEX,
242bfe3f2eSlogwang 	.link_status = ETH_LINK_UP,
252bfe3f2eSlogwang 	.link_autoneg = ETH_LINK_AUTONEG,
262bfe3f2eSlogwang };
272bfe3f2eSlogwang 
282bfe3f2eSlogwang static int
292bfe3f2eSlogwang fs_sub_device_alloc(struct rte_eth_dev *dev,
302bfe3f2eSlogwang 		const char *params)
312bfe3f2eSlogwang {
322bfe3f2eSlogwang 	uint8_t nb_subs;
332bfe3f2eSlogwang 	int ret;
34d30ea906Sjfb8856606 	int i;
35*4418919fSjohnjiang 	struct sub_device *sdev;
36*4418919fSjohnjiang 	uint8_t sdev_iterator;
372bfe3f2eSlogwang 
382bfe3f2eSlogwang 	ret = failsafe_args_count_subdevice(dev, params);
392bfe3f2eSlogwang 	if (ret)
402bfe3f2eSlogwang 		return ret;
412bfe3f2eSlogwang 	if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
422bfe3f2eSlogwang 		ERROR("Cannot allocate more than %d ports",
432bfe3f2eSlogwang 			FAILSAFE_MAX_ETHPORTS);
442bfe3f2eSlogwang 		return -ENOSPC;
452bfe3f2eSlogwang 	}
462bfe3f2eSlogwang 	nb_subs = PRIV(dev)->subs_tail;
472bfe3f2eSlogwang 	PRIV(dev)->subs = rte_zmalloc(NULL,
482bfe3f2eSlogwang 			sizeof(struct sub_device) * nb_subs,
492bfe3f2eSlogwang 			RTE_CACHE_LINE_SIZE);
502bfe3f2eSlogwang 	if (PRIV(dev)->subs == NULL) {
512bfe3f2eSlogwang 		ERROR("Could not allocate sub_devices");
522bfe3f2eSlogwang 		return -ENOMEM;
532bfe3f2eSlogwang 	}
54d30ea906Sjfb8856606 	/* Initiate static sub devices linked list. */
55d30ea906Sjfb8856606 	for (i = 1; i < nb_subs; i++)
56d30ea906Sjfb8856606 		PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
57d30ea906Sjfb8856606 	PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
58*4418919fSjohnjiang 
59*4418919fSjohnjiang 	FOREACH_SUBDEV(sdev, sdev_iterator, dev) {
60*4418919fSjohnjiang 		sdev->sdev_port_id = RTE_MAX_ETHPORTS;
61*4418919fSjohnjiang 	}
622bfe3f2eSlogwang 	return 0;
632bfe3f2eSlogwang }
642bfe3f2eSlogwang 
652bfe3f2eSlogwang static void
662bfe3f2eSlogwang fs_sub_device_free(struct rte_eth_dev *dev)
672bfe3f2eSlogwang {
682bfe3f2eSlogwang 	rte_free(PRIV(dev)->subs);
692bfe3f2eSlogwang }
702bfe3f2eSlogwang 
712bfe3f2eSlogwang static void fs_hotplug_alarm(void *arg);
722bfe3f2eSlogwang 
732bfe3f2eSlogwang int
742bfe3f2eSlogwang failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
752bfe3f2eSlogwang {
762bfe3f2eSlogwang 	int ret;
772bfe3f2eSlogwang 
782bfe3f2eSlogwang 	if (dev == NULL)
792bfe3f2eSlogwang 		return -EINVAL;
802bfe3f2eSlogwang 	if (PRIV(dev)->pending_alarm)
812bfe3f2eSlogwang 		return 0;
82d30ea906Sjfb8856606 	ret = rte_eal_alarm_set(failsafe_hotplug_poll * 1000,
832bfe3f2eSlogwang 				fs_hotplug_alarm,
842bfe3f2eSlogwang 				dev);
852bfe3f2eSlogwang 	if (ret) {
862bfe3f2eSlogwang 		ERROR("Could not set up plug-in event detection");
872bfe3f2eSlogwang 		return ret;
882bfe3f2eSlogwang 	}
892bfe3f2eSlogwang 	PRIV(dev)->pending_alarm = 1;
902bfe3f2eSlogwang 	return 0;
912bfe3f2eSlogwang }
922bfe3f2eSlogwang 
932bfe3f2eSlogwang int
942bfe3f2eSlogwang failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
952bfe3f2eSlogwang {
962bfe3f2eSlogwang 	int ret = 0;
972bfe3f2eSlogwang 
982bfe3f2eSlogwang 	rte_errno = 0;
992bfe3f2eSlogwang 	rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
1002bfe3f2eSlogwang 	if (rte_errno) {
1012bfe3f2eSlogwang 		ERROR("rte_eal_alarm_cancel failed (errno: %s)",
1022bfe3f2eSlogwang 		      strerror(rte_errno));
1032bfe3f2eSlogwang 		ret = -rte_errno;
1042bfe3f2eSlogwang 	} else {
1052bfe3f2eSlogwang 		PRIV(dev)->pending_alarm = 0;
1062bfe3f2eSlogwang 	}
1072bfe3f2eSlogwang 	return ret;
1082bfe3f2eSlogwang }
1092bfe3f2eSlogwang 
1102bfe3f2eSlogwang static void
1112bfe3f2eSlogwang fs_hotplug_alarm(void *arg)
1122bfe3f2eSlogwang {
1132bfe3f2eSlogwang 	struct rte_eth_dev *dev = arg;
1142bfe3f2eSlogwang 	struct sub_device *sdev;
1152bfe3f2eSlogwang 	int ret;
1162bfe3f2eSlogwang 	uint8_t i;
1172bfe3f2eSlogwang 
1182bfe3f2eSlogwang 	if (!PRIV(dev)->pending_alarm)
1192bfe3f2eSlogwang 		return;
1202bfe3f2eSlogwang 	PRIV(dev)->pending_alarm = 0;
1212bfe3f2eSlogwang 	FOREACH_SUBDEV(sdev, i, dev)
1222bfe3f2eSlogwang 		if (sdev->state != PRIV(dev)->state)
1232bfe3f2eSlogwang 			break;
1242bfe3f2eSlogwang 	/* if we have non-probed device */
1252bfe3f2eSlogwang 	if (i != PRIV(dev)->subs_tail) {
126d30ea906Sjfb8856606 		if (fs_lock(dev, 1) != 0)
127d30ea906Sjfb8856606 			goto reinstall;
1282bfe3f2eSlogwang 		ret = failsafe_eth_dev_state_sync(dev);
129d30ea906Sjfb8856606 		fs_unlock(dev, 1);
1302bfe3f2eSlogwang 		if (ret)
1312bfe3f2eSlogwang 			ERROR("Unable to synchronize sub_device state");
1322bfe3f2eSlogwang 	}
1332bfe3f2eSlogwang 	failsafe_dev_remove(dev);
134d30ea906Sjfb8856606 reinstall:
1352bfe3f2eSlogwang 	ret = failsafe_hotplug_alarm_install(dev);
1362bfe3f2eSlogwang 	if (ret)
1372bfe3f2eSlogwang 		ERROR("Unable to set up next alarm");
1382bfe3f2eSlogwang }
1392bfe3f2eSlogwang 
1402bfe3f2eSlogwang static int
141d30ea906Sjfb8856606 fs_mutex_init(struct fs_priv *priv)
142d30ea906Sjfb8856606 {
143d30ea906Sjfb8856606 	int ret;
144d30ea906Sjfb8856606 	pthread_mutexattr_t attr;
145d30ea906Sjfb8856606 
146d30ea906Sjfb8856606 	ret = pthread_mutexattr_init(&attr);
147d30ea906Sjfb8856606 	if (ret) {
148d30ea906Sjfb8856606 		ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
149d30ea906Sjfb8856606 		return ret;
150d30ea906Sjfb8856606 	}
151d30ea906Sjfb8856606 	/* Allow mutex relocks for the thread holding the mutex. */
152d30ea906Sjfb8856606 	ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
153d30ea906Sjfb8856606 	if (ret) {
154d30ea906Sjfb8856606 		ERROR("Cannot set mutex type - %s", strerror(ret));
155d30ea906Sjfb8856606 		return ret;
156d30ea906Sjfb8856606 	}
157d30ea906Sjfb8856606 	ret = pthread_mutex_init(&priv->hotplug_mutex, &attr);
158d30ea906Sjfb8856606 	if (ret) {
159d30ea906Sjfb8856606 		ERROR("Cannot initiate mutex - %s", strerror(ret));
160d30ea906Sjfb8856606 		return ret;
161d30ea906Sjfb8856606 	}
162d30ea906Sjfb8856606 	return 0;
163d30ea906Sjfb8856606 }
164d30ea906Sjfb8856606 
165d30ea906Sjfb8856606 static int
1662bfe3f2eSlogwang fs_eth_dev_create(struct rte_vdev_device *vdev)
1672bfe3f2eSlogwang {
1682bfe3f2eSlogwang 	struct rte_eth_dev *dev;
169*4418919fSjohnjiang 	struct rte_ether_addr *mac;
1702bfe3f2eSlogwang 	struct fs_priv *priv;
1712bfe3f2eSlogwang 	struct sub_device *sdev;
1722bfe3f2eSlogwang 	const char *params;
1732bfe3f2eSlogwang 	unsigned int socket_id;
1742bfe3f2eSlogwang 	uint8_t i;
1752bfe3f2eSlogwang 	int ret;
1762bfe3f2eSlogwang 
1772bfe3f2eSlogwang 	dev = NULL;
1782bfe3f2eSlogwang 	priv = NULL;
1792bfe3f2eSlogwang 	socket_id = rte_socket_id();
1802bfe3f2eSlogwang 	INFO("Creating fail-safe device on NUMA socket %u", socket_id);
1812bfe3f2eSlogwang 	params = rte_vdev_device_args(vdev);
1822bfe3f2eSlogwang 	if (params == NULL) {
1832bfe3f2eSlogwang 		ERROR("This PMD requires sub-devices, none provided");
1842bfe3f2eSlogwang 		return -1;
1852bfe3f2eSlogwang 	}
1862bfe3f2eSlogwang 	dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
1872bfe3f2eSlogwang 	if (dev == NULL) {
1882bfe3f2eSlogwang 		ERROR("Unable to allocate rte_eth_dev");
1892bfe3f2eSlogwang 		return -1;
1902bfe3f2eSlogwang 	}
1912bfe3f2eSlogwang 	priv = PRIV(dev);
192*4418919fSjohnjiang 	priv->data = dev->data;
1932bfe3f2eSlogwang 	dev->dev_ops = &failsafe_ops;
1942bfe3f2eSlogwang 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
1952bfe3f2eSlogwang 	dev->data->dev_link = eth_link;
1962bfe3f2eSlogwang 	PRIV(dev)->nb_mac_addr = 1;
1972bfe3f2eSlogwang 	TAILQ_INIT(&PRIV(dev)->flow_list);
1982bfe3f2eSlogwang 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
1992bfe3f2eSlogwang 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
2002bfe3f2eSlogwang 	ret = fs_sub_device_alloc(dev, params);
2012bfe3f2eSlogwang 	if (ret) {
2022bfe3f2eSlogwang 		ERROR("Could not allocate sub_devices");
2032bfe3f2eSlogwang 		goto free_dev;
2042bfe3f2eSlogwang 	}
2052bfe3f2eSlogwang 	ret = failsafe_args_parse(dev, params);
2062bfe3f2eSlogwang 	if (ret)
2072bfe3f2eSlogwang 		goto free_subs;
208d30ea906Sjfb8856606 	ret = rte_eth_dev_owner_new(&priv->my_owner.id);
209d30ea906Sjfb8856606 	if (ret) {
210d30ea906Sjfb8856606 		ERROR("Failed to get unique owner identifier");
211d30ea906Sjfb8856606 		goto free_args;
212d30ea906Sjfb8856606 	}
213d30ea906Sjfb8856606 	snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
214d30ea906Sjfb8856606 		 FAILSAFE_OWNER_NAME);
215d30ea906Sjfb8856606 	DEBUG("Failsafe port %u owner info: %s_%016"PRIX64, dev->data->port_id,
216d30ea906Sjfb8856606 	      priv->my_owner.name, priv->my_owner.id);
217d30ea906Sjfb8856606 	ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
218d30ea906Sjfb8856606 					    failsafe_eth_new_event_callback,
219d30ea906Sjfb8856606 					    dev);
220d30ea906Sjfb8856606 	if (ret) {
221d30ea906Sjfb8856606 		ERROR("Failed to register NEW callback");
222d30ea906Sjfb8856606 		goto free_args;
223d30ea906Sjfb8856606 	}
2242bfe3f2eSlogwang 	ret = failsafe_eal_init(dev);
2252bfe3f2eSlogwang 	if (ret)
226d30ea906Sjfb8856606 		goto unregister_new_callback;
227d30ea906Sjfb8856606 	ret = fs_mutex_init(priv);
228d30ea906Sjfb8856606 	if (ret)
229d30ea906Sjfb8856606 		goto unregister_new_callback;
2302bfe3f2eSlogwang 	ret = failsafe_hotplug_alarm_install(dev);
2312bfe3f2eSlogwang 	if (ret) {
2322bfe3f2eSlogwang 		ERROR("Could not set up plug-in event detection");
233d30ea906Sjfb8856606 		goto unregister_new_callback;
2342bfe3f2eSlogwang 	}
2352bfe3f2eSlogwang 	mac = &dev->data->mac_addrs[0];
236d30ea906Sjfb8856606 	if (failsafe_mac_from_arg) {
2372bfe3f2eSlogwang 		/*
2382bfe3f2eSlogwang 		 * If MAC address was provided as a parameter,
2392bfe3f2eSlogwang 		 * apply to all probed slaves.
2402bfe3f2eSlogwang 		 */
2412bfe3f2eSlogwang 		FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
2422bfe3f2eSlogwang 			ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
2432bfe3f2eSlogwang 							       mac);
2442bfe3f2eSlogwang 			if (ret) {
2452bfe3f2eSlogwang 				ERROR("Failed to set default MAC address");
246579bf1e2Sjfb8856606 				goto cancel_alarm;
2472bfe3f2eSlogwang 			}
2482bfe3f2eSlogwang 		}
2492bfe3f2eSlogwang 	} else {
2502bfe3f2eSlogwang 		/*
2512bfe3f2eSlogwang 		 * Use the ether_addr from first probed
2522bfe3f2eSlogwang 		 * device, either preferred or fallback.
2532bfe3f2eSlogwang 		 */
2542bfe3f2eSlogwang 		FOREACH_SUBDEV(sdev, i, dev)
2552bfe3f2eSlogwang 			if (sdev->state >= DEV_PROBED) {
256*4418919fSjohnjiang 				rte_ether_addr_copy(
257*4418919fSjohnjiang 					&ETH(sdev)->data->mac_addrs[0], mac);
2582bfe3f2eSlogwang 				break;
2592bfe3f2eSlogwang 			}
2602bfe3f2eSlogwang 		/*
2612bfe3f2eSlogwang 		 * If no device has been probed and no ether_addr
2622bfe3f2eSlogwang 		 * has been provided on the command line, use a random
2632bfe3f2eSlogwang 		 * valid one.
2642bfe3f2eSlogwang 		 * It will be applied during future slave state syncs to
2652bfe3f2eSlogwang 		 * probed slaves.
2662bfe3f2eSlogwang 		 */
2672bfe3f2eSlogwang 		if (i == priv->subs_tail)
268*4418919fSjohnjiang 			rte_eth_random_addr(&mac->addr_bytes[0]);
2692bfe3f2eSlogwang 	}
2702bfe3f2eSlogwang 	INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
2712bfe3f2eSlogwang 		mac->addr_bytes[0], mac->addr_bytes[1],
2722bfe3f2eSlogwang 		mac->addr_bytes[2], mac->addr_bytes[3],
2732bfe3f2eSlogwang 		mac->addr_bytes[4], mac->addr_bytes[5]);
2742bfe3f2eSlogwang 	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
275d30ea906Sjfb8856606 	PRIV(dev)->intr_handle = (struct rte_intr_handle){
276d30ea906Sjfb8856606 		.fd = -1,
277d30ea906Sjfb8856606 		.type = RTE_INTR_HANDLE_EXT,
278d30ea906Sjfb8856606 	};
279d30ea906Sjfb8856606 	rte_eth_dev_probing_finish(dev);
2802bfe3f2eSlogwang 	return 0;
281579bf1e2Sjfb8856606 cancel_alarm:
282579bf1e2Sjfb8856606 	failsafe_hotplug_alarm_cancel(dev);
283d30ea906Sjfb8856606 unregister_new_callback:
284d30ea906Sjfb8856606 	rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
285d30ea906Sjfb8856606 					failsafe_eth_new_event_callback, dev);
2862bfe3f2eSlogwang free_args:
2872bfe3f2eSlogwang 	failsafe_args_free(dev);
2882bfe3f2eSlogwang free_subs:
2892bfe3f2eSlogwang 	fs_sub_device_free(dev);
2902bfe3f2eSlogwang free_dev:
291d30ea906Sjfb8856606 	/* mac_addrs must not be freed alone because part of dev_private */
292d30ea906Sjfb8856606 	dev->data->mac_addrs = NULL;
2932bfe3f2eSlogwang 	rte_eth_dev_release_port(dev);
2942bfe3f2eSlogwang 	return -1;
2952bfe3f2eSlogwang }
2962bfe3f2eSlogwang 
2972bfe3f2eSlogwang static int
2982bfe3f2eSlogwang fs_rte_eth_free(const char *name)
2992bfe3f2eSlogwang {
3002bfe3f2eSlogwang 	struct rte_eth_dev *dev;
3012bfe3f2eSlogwang 	int ret;
3022bfe3f2eSlogwang 
3032bfe3f2eSlogwang 	dev = rte_eth_dev_allocated(name);
3042bfe3f2eSlogwang 	if (dev == NULL)
3052bfe3f2eSlogwang 		return -ENODEV;
306d30ea906Sjfb8856606 	rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
307d30ea906Sjfb8856606 					failsafe_eth_new_event_callback, dev);
3082bfe3f2eSlogwang 	ret = failsafe_eal_uninit(dev);
3092bfe3f2eSlogwang 	if (ret)
3102bfe3f2eSlogwang 		ERROR("Error while uninitializing sub-EAL");
3112bfe3f2eSlogwang 	failsafe_args_free(dev);
3122bfe3f2eSlogwang 	fs_sub_device_free(dev);
313d30ea906Sjfb8856606 	ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex);
314d30ea906Sjfb8856606 	if (ret)
315d30ea906Sjfb8856606 		ERROR("Error while destroying hotplug mutex");
316d30ea906Sjfb8856606 	rte_free(PRIV(dev)->mcast_addrs);
317d30ea906Sjfb8856606 	/* mac_addrs must not be freed alone because part of dev_private */
318d30ea906Sjfb8856606 	dev->data->mac_addrs = NULL;
3192bfe3f2eSlogwang 	rte_eth_dev_release_port(dev);
3202bfe3f2eSlogwang 	return ret;
3212bfe3f2eSlogwang }
3222bfe3f2eSlogwang 
323*4418919fSjohnjiang static bool
324*4418919fSjohnjiang devargs_already_listed(struct rte_devargs *devargs)
325*4418919fSjohnjiang {
326*4418919fSjohnjiang 	struct rte_devargs *list_da;
327*4418919fSjohnjiang 
328*4418919fSjohnjiang 	RTE_EAL_DEVARGS_FOREACH(devargs->bus->name, list_da) {
329*4418919fSjohnjiang 		if (strcmp(list_da->name, devargs->name) == 0)
330*4418919fSjohnjiang 			/* devargs already in the list */
331*4418919fSjohnjiang 			return true;
332*4418919fSjohnjiang 	}
333*4418919fSjohnjiang 	return false;
334*4418919fSjohnjiang }
335*4418919fSjohnjiang 
3362bfe3f2eSlogwang static int
3372bfe3f2eSlogwang rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
3382bfe3f2eSlogwang {
3392bfe3f2eSlogwang 	const char *name;
340d30ea906Sjfb8856606 	struct rte_eth_dev *eth_dev;
341*4418919fSjohnjiang 	struct sub_device  *sdev;
342*4418919fSjohnjiang 	struct rte_devargs devargs;
343*4418919fSjohnjiang 	uint8_t i;
344*4418919fSjohnjiang 	int ret;
3452bfe3f2eSlogwang 
3462bfe3f2eSlogwang 	name = rte_vdev_device_name(vdev);
3472bfe3f2eSlogwang 	INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
3482bfe3f2eSlogwang 			name);
349d30ea906Sjfb8856606 
350d30ea906Sjfb8856606 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
351d30ea906Sjfb8856606 	    strlen(rte_vdev_device_args(vdev)) == 0) {
352d30ea906Sjfb8856606 		eth_dev = rte_eth_dev_attach_secondary(name);
353d30ea906Sjfb8856606 		if (!eth_dev) {
354d30ea906Sjfb8856606 			ERROR("Failed to probe %s", name);
355d30ea906Sjfb8856606 			return -1;
356d30ea906Sjfb8856606 		}
357d30ea906Sjfb8856606 		eth_dev->dev_ops = &failsafe_ops;
358d30ea906Sjfb8856606 		eth_dev->device = &vdev->device;
359*4418919fSjohnjiang 		eth_dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
360*4418919fSjohnjiang 		eth_dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
361*4418919fSjohnjiang 		/*
362*4418919fSjohnjiang 		 * Failsafe will attempt to probe all of its sub-devices.
363*4418919fSjohnjiang 		 * Any failure in sub-devices is not a fatal error.
364*4418919fSjohnjiang 		 * A sub-device can be plugged later.
365*4418919fSjohnjiang 		 */
366*4418919fSjohnjiang 		FOREACH_SUBDEV(sdev, i, eth_dev) {
367*4418919fSjohnjiang 			/* skip empty devargs */
368*4418919fSjohnjiang 			if (sdev->devargs.name[0] == '\0')
369*4418919fSjohnjiang 				continue;
370*4418919fSjohnjiang 
371*4418919fSjohnjiang 			/* rebuild devargs to be able to get the bus name. */
372*4418919fSjohnjiang 			ret = rte_devargs_parse(&devargs,
373*4418919fSjohnjiang 						sdev->devargs.name);
374*4418919fSjohnjiang 			if (ret != 0) {
375*4418919fSjohnjiang 				ERROR("Failed to parse devargs %s",
376*4418919fSjohnjiang 					devargs.name);
377*4418919fSjohnjiang 				continue;
378*4418919fSjohnjiang 			}
379*4418919fSjohnjiang 			if (!devargs_already_listed(&devargs)) {
380*4418919fSjohnjiang 				ret = rte_dev_probe(devargs.name);
381*4418919fSjohnjiang 				if (ret < 0) {
382*4418919fSjohnjiang 					ERROR("Failed to probe devargs %s",
383*4418919fSjohnjiang 					      devargs.name);
384*4418919fSjohnjiang 					continue;
385*4418919fSjohnjiang 				}
386*4418919fSjohnjiang 			}
387*4418919fSjohnjiang 		}
388d30ea906Sjfb8856606 		rte_eth_dev_probing_finish(eth_dev);
389d30ea906Sjfb8856606 		return 0;
390d30ea906Sjfb8856606 	}
391d30ea906Sjfb8856606 
3922bfe3f2eSlogwang 	return fs_eth_dev_create(vdev);
3932bfe3f2eSlogwang }
3942bfe3f2eSlogwang 
3952bfe3f2eSlogwang static int
3962bfe3f2eSlogwang rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
3972bfe3f2eSlogwang {
3982bfe3f2eSlogwang 	const char *name;
3992bfe3f2eSlogwang 
4002bfe3f2eSlogwang 	name = rte_vdev_device_name(vdev);
4012bfe3f2eSlogwang 	INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
4022bfe3f2eSlogwang 	return fs_rte_eth_free(name);
4032bfe3f2eSlogwang }
4042bfe3f2eSlogwang 
4052bfe3f2eSlogwang static struct rte_vdev_driver failsafe_drv = {
4062bfe3f2eSlogwang 	.probe = rte_pmd_failsafe_probe,
4072bfe3f2eSlogwang 	.remove = rte_pmd_failsafe_remove,
4082bfe3f2eSlogwang };
4092bfe3f2eSlogwang 
4102bfe3f2eSlogwang RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
4112bfe3f2eSlogwang RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
412d30ea906Sjfb8856606 
413d30ea906Sjfb8856606 RTE_INIT(failsafe_init_log)
414d30ea906Sjfb8856606 {
415d30ea906Sjfb8856606 	failsafe_logtype = rte_log_register("pmd.net.failsafe");
416d30ea906Sjfb8856606 	if (failsafe_logtype >= 0)
417d30ea906Sjfb8856606 		rte_log_set_level(failsafe_logtype, RTE_LOG_NOTICE);
418d30ea906Sjfb8856606 }
419