xref: /dpdk/drivers/net/failsafe/failsafe.c (revision d1c3ab220a367085451f595d94e481320e091a77)
1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
2a46f8d58SGaetan Rivet  * Copyright 2017 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2017 Mellanox Technologies, Ltd
4a46f8d58SGaetan Rivet  */
5a46f8d58SGaetan Rivet 
6a46f8d58SGaetan Rivet #include <rte_alarm.h>
7a46f8d58SGaetan Rivet #include <rte_malloc.h>
8ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h>
9a46f8d58SGaetan Rivet #include <rte_ethdev_vdev.h>
10a46f8d58SGaetan Rivet #include <rte_devargs.h>
11a46f8d58SGaetan Rivet #include <rte_kvargs.h>
12d4a586d2SJianfeng Tan #include <rte_bus_vdev.h>
13a46f8d58SGaetan Rivet 
14a46f8d58SGaetan Rivet #include "failsafe_private.h"
15a46f8d58SGaetan Rivet 
16ebeb72ecSStephen Hemminger int failsafe_logtype;
17ebeb72ecSStephen Hemminger 
18a46f8d58SGaetan Rivet const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
19a46f8d58SGaetan Rivet static const struct rte_eth_link eth_link = {
20a46f8d58SGaetan Rivet 	.link_speed = ETH_SPEED_NUM_10G,
21a46f8d58SGaetan Rivet 	.link_duplex = ETH_LINK_FULL_DUPLEX,
22a46f8d58SGaetan Rivet 	.link_status = ETH_LINK_UP,
231e3a958fSThomas Monjalon 	.link_autoneg = ETH_LINK_AUTONEG,
24a46f8d58SGaetan Rivet };
25a46f8d58SGaetan Rivet 
26a46f8d58SGaetan Rivet static int
27a46f8d58SGaetan Rivet fs_sub_device_alloc(struct rte_eth_dev *dev,
28a46f8d58SGaetan Rivet 		const char *params)
29a46f8d58SGaetan Rivet {
30a46f8d58SGaetan Rivet 	uint8_t nb_subs;
31a46f8d58SGaetan Rivet 	int ret;
328052bbd9SMatan Azrad 	int i;
33a46f8d58SGaetan Rivet 
34a46f8d58SGaetan Rivet 	ret = failsafe_args_count_subdevice(dev, params);
35a46f8d58SGaetan Rivet 	if (ret)
36a46f8d58SGaetan Rivet 		return ret;
37a46f8d58SGaetan Rivet 	if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
38a46f8d58SGaetan Rivet 		ERROR("Cannot allocate more than %d ports",
39a46f8d58SGaetan Rivet 			FAILSAFE_MAX_ETHPORTS);
40a46f8d58SGaetan Rivet 		return -ENOSPC;
41a46f8d58SGaetan Rivet 	}
42a46f8d58SGaetan Rivet 	nb_subs = PRIV(dev)->subs_tail;
43a46f8d58SGaetan Rivet 	PRIV(dev)->subs = rte_zmalloc(NULL,
44a46f8d58SGaetan Rivet 			sizeof(struct sub_device) * nb_subs,
45a46f8d58SGaetan Rivet 			RTE_CACHE_LINE_SIZE);
46a46f8d58SGaetan Rivet 	if (PRIV(dev)->subs == NULL) {
47a46f8d58SGaetan Rivet 		ERROR("Could not allocate sub_devices");
48a46f8d58SGaetan Rivet 		return -ENOMEM;
49a46f8d58SGaetan Rivet 	}
508052bbd9SMatan Azrad 	/* Initiate static sub devices linked list. */
518052bbd9SMatan Azrad 	for (i = 1; i < nb_subs; i++)
528052bbd9SMatan Azrad 		PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
538052bbd9SMatan Azrad 	PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
54a46f8d58SGaetan Rivet 	return 0;
55a46f8d58SGaetan Rivet }
56a46f8d58SGaetan Rivet 
57a46f8d58SGaetan Rivet static void
58a46f8d58SGaetan Rivet fs_sub_device_free(struct rte_eth_dev *dev)
59a46f8d58SGaetan Rivet {
60a46f8d58SGaetan Rivet 	rte_free(PRIV(dev)->subs);
61a46f8d58SGaetan Rivet }
62a46f8d58SGaetan Rivet 
63ebea83f8SGaetan Rivet static void fs_hotplug_alarm(void *arg);
64ebea83f8SGaetan Rivet 
65ebea83f8SGaetan Rivet int
66ebea83f8SGaetan Rivet failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
67ebea83f8SGaetan Rivet {
68ebea83f8SGaetan Rivet 	int ret;
69ebea83f8SGaetan Rivet 
70ebea83f8SGaetan Rivet 	if (dev == NULL)
71ebea83f8SGaetan Rivet 		return -EINVAL;
72ebea83f8SGaetan Rivet 	if (PRIV(dev)->pending_alarm)
73ebea83f8SGaetan Rivet 		return 0;
74ebea83f8SGaetan Rivet 	ret = rte_eal_alarm_set(hotplug_poll * 1000,
75ebea83f8SGaetan Rivet 				fs_hotplug_alarm,
76ebea83f8SGaetan Rivet 				dev);
77ebea83f8SGaetan Rivet 	if (ret) {
78ebea83f8SGaetan Rivet 		ERROR("Could not set up plug-in event detection");
79ebea83f8SGaetan Rivet 		return ret;
80ebea83f8SGaetan Rivet 	}
81ebea83f8SGaetan Rivet 	PRIV(dev)->pending_alarm = 1;
82ebea83f8SGaetan Rivet 	return 0;
83ebea83f8SGaetan Rivet }
84ebea83f8SGaetan Rivet 
85ebea83f8SGaetan Rivet int
86ebea83f8SGaetan Rivet failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
87ebea83f8SGaetan Rivet {
88ebea83f8SGaetan Rivet 	int ret = 0;
89ebea83f8SGaetan Rivet 
90ebea83f8SGaetan Rivet 	rte_errno = 0;
91ebea83f8SGaetan Rivet 	rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
92ebea83f8SGaetan Rivet 	if (rte_errno) {
93ebea83f8SGaetan Rivet 		ERROR("rte_eal_alarm_cancel failed (errno: %s)",
94ebea83f8SGaetan Rivet 		      strerror(rte_errno));
95ebea83f8SGaetan Rivet 		ret = -rte_errno;
96ebea83f8SGaetan Rivet 	} else {
97ebea83f8SGaetan Rivet 		PRIV(dev)->pending_alarm = 0;
98ebea83f8SGaetan Rivet 	}
99ebea83f8SGaetan Rivet 	return ret;
100ebea83f8SGaetan Rivet }
101ebea83f8SGaetan Rivet 
102ebea83f8SGaetan Rivet static void
103ebea83f8SGaetan Rivet fs_hotplug_alarm(void *arg)
104ebea83f8SGaetan Rivet {
105ebea83f8SGaetan Rivet 	struct rte_eth_dev *dev = arg;
106ebea83f8SGaetan Rivet 	struct sub_device *sdev;
107ebea83f8SGaetan Rivet 	int ret;
108ebea83f8SGaetan Rivet 	uint8_t i;
109ebea83f8SGaetan Rivet 
110ebea83f8SGaetan Rivet 	if (!PRIV(dev)->pending_alarm)
111ebea83f8SGaetan Rivet 		return;
112ebea83f8SGaetan Rivet 	PRIV(dev)->pending_alarm = 0;
113ebea83f8SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev)
114ebea83f8SGaetan Rivet 		if (sdev->state != PRIV(dev)->state)
115ebea83f8SGaetan Rivet 			break;
116ebea83f8SGaetan Rivet 	/* if we have non-probed device */
117ebea83f8SGaetan Rivet 	if (i != PRIV(dev)->subs_tail) {
118655fcd68SMatan Azrad 		if (fs_lock(dev, 1) != 0)
119655fcd68SMatan Azrad 			goto reinstall;
120ebea83f8SGaetan Rivet 		ret = failsafe_eth_dev_state_sync(dev);
121655fcd68SMatan Azrad 		fs_unlock(dev, 1);
122ebea83f8SGaetan Rivet 		if (ret)
123ebea83f8SGaetan Rivet 			ERROR("Unable to synchronize sub_device state");
124ebea83f8SGaetan Rivet 	}
125598fb8aeSGaetan Rivet 	failsafe_dev_remove(dev);
126655fcd68SMatan Azrad reinstall:
127ebea83f8SGaetan Rivet 	ret = failsafe_hotplug_alarm_install(dev);
128ebea83f8SGaetan Rivet 	if (ret)
129ebea83f8SGaetan Rivet 		ERROR("Unable to set up next alarm");
130ebea83f8SGaetan Rivet }
131ebea83f8SGaetan Rivet 
132a46f8d58SGaetan Rivet static int
133655fcd68SMatan Azrad fs_mutex_init(struct fs_priv *priv)
134655fcd68SMatan Azrad {
135655fcd68SMatan Azrad 	int ret;
136655fcd68SMatan Azrad 	pthread_mutexattr_t attr;
137655fcd68SMatan Azrad 
138655fcd68SMatan Azrad 	ret = pthread_mutexattr_init(&attr);
139655fcd68SMatan Azrad 	if (ret) {
140655fcd68SMatan Azrad 		ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
141655fcd68SMatan Azrad 		return ret;
142655fcd68SMatan Azrad 	}
143655fcd68SMatan Azrad 	/* Allow mutex relocks for the thread holding the mutex. */
144655fcd68SMatan Azrad 	ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
145655fcd68SMatan Azrad 	if (ret) {
146655fcd68SMatan Azrad 		ERROR("Cannot set mutex type - %s", strerror(ret));
147655fcd68SMatan Azrad 		return ret;
148655fcd68SMatan Azrad 	}
149655fcd68SMatan Azrad 	ret = pthread_mutex_init(&priv->hotplug_mutex, &attr);
150655fcd68SMatan Azrad 	if (ret) {
151655fcd68SMatan Azrad 		ERROR("Cannot initiate mutex - %s", strerror(ret));
152655fcd68SMatan Azrad 		return ret;
153655fcd68SMatan Azrad 	}
154655fcd68SMatan Azrad 	return 0;
155655fcd68SMatan Azrad }
156655fcd68SMatan Azrad 
157655fcd68SMatan Azrad static int
158a46f8d58SGaetan Rivet fs_eth_dev_create(struct rte_vdev_device *vdev)
159a46f8d58SGaetan Rivet {
160a46f8d58SGaetan Rivet 	struct rte_eth_dev *dev;
161a46f8d58SGaetan Rivet 	struct ether_addr *mac;
162a46f8d58SGaetan Rivet 	struct fs_priv *priv;
163a46f8d58SGaetan Rivet 	struct sub_device *sdev;
164a46f8d58SGaetan Rivet 	const char *params;
165a46f8d58SGaetan Rivet 	unsigned int socket_id;
166a46f8d58SGaetan Rivet 	uint8_t i;
167a46f8d58SGaetan Rivet 	int ret;
168a46f8d58SGaetan Rivet 
169a46f8d58SGaetan Rivet 	dev = NULL;
170a46f8d58SGaetan Rivet 	priv = NULL;
171a46f8d58SGaetan Rivet 	socket_id = rte_socket_id();
172a46f8d58SGaetan Rivet 	INFO("Creating fail-safe device on NUMA socket %u", socket_id);
173a46f8d58SGaetan Rivet 	params = rte_vdev_device_args(vdev);
174a46f8d58SGaetan Rivet 	if (params == NULL) {
175a46f8d58SGaetan Rivet 		ERROR("This PMD requires sub-devices, none provided");
176a46f8d58SGaetan Rivet 		return -1;
177a46f8d58SGaetan Rivet 	}
178a46f8d58SGaetan Rivet 	dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
179a46f8d58SGaetan Rivet 	if (dev == NULL) {
180a46f8d58SGaetan Rivet 		ERROR("Unable to allocate rte_eth_dev");
181a46f8d58SGaetan Rivet 		return -1;
182a46f8d58SGaetan Rivet 	}
183a46f8d58SGaetan Rivet 	priv = PRIV(dev);
184a46f8d58SGaetan Rivet 	priv->dev = dev;
185a46f8d58SGaetan Rivet 	dev->dev_ops = &failsafe_ops;
186a46f8d58SGaetan Rivet 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
187a46f8d58SGaetan Rivet 	dev->data->dev_link = eth_link;
188a46f8d58SGaetan Rivet 	PRIV(dev)->nb_mac_addr = 1;
189b737a1eeSGaetan Rivet 	TAILQ_INIT(&PRIV(dev)->flow_list);
190a46f8d58SGaetan Rivet 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
191a46f8d58SGaetan Rivet 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
192a46f8d58SGaetan Rivet 	ret = fs_sub_device_alloc(dev, params);
193a46f8d58SGaetan Rivet 	if (ret) {
194a46f8d58SGaetan Rivet 		ERROR("Could not allocate sub_devices");
195a46f8d58SGaetan Rivet 		goto free_dev;
196a46f8d58SGaetan Rivet 	}
197a46f8d58SGaetan Rivet 	ret = failsafe_args_parse(dev, params);
198a46f8d58SGaetan Rivet 	if (ret)
199a46f8d58SGaetan Rivet 		goto free_subs;
200dcd0c9c3SMatan Azrad 	ret = rte_eth_dev_owner_new(&priv->my_owner.id);
201dcd0c9c3SMatan Azrad 	if (ret) {
202dcd0c9c3SMatan Azrad 		ERROR("Failed to get unique owner identifier");
203dcd0c9c3SMatan Azrad 		goto free_args;
204dcd0c9c3SMatan Azrad 	}
205dcd0c9c3SMatan Azrad 	snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
206dcd0c9c3SMatan Azrad 		 FAILSAFE_OWNER_NAME);
2077fda13d3SMatan Azrad 	DEBUG("Failsafe port %u owner info: %s_%016"PRIX64, dev->data->port_id,
2087fda13d3SMatan Azrad 	      priv->my_owner.name, priv->my_owner.id);
2097fda13d3SMatan Azrad 	ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
2107fda13d3SMatan Azrad 					    failsafe_eth_new_event_callback,
2117fda13d3SMatan Azrad 					    dev);
2127fda13d3SMatan Azrad 	if (ret) {
2137fda13d3SMatan Azrad 		ERROR("Failed to register NEW callback");
2147fda13d3SMatan Azrad 		goto free_args;
2157fda13d3SMatan Azrad 	}
216a46f8d58SGaetan Rivet 	ret = failsafe_eal_init(dev);
217a46f8d58SGaetan Rivet 	if (ret)
2187fda13d3SMatan Azrad 		goto unregister_new_callback;
219655fcd68SMatan Azrad 	ret = fs_mutex_init(priv);
220655fcd68SMatan Azrad 	if (ret)
2217fda13d3SMatan Azrad 		goto unregister_new_callback;
222ebea83f8SGaetan Rivet 	ret = failsafe_hotplug_alarm_install(dev);
223ebea83f8SGaetan Rivet 	if (ret) {
224ebea83f8SGaetan Rivet 		ERROR("Could not set up plug-in event detection");
2257fda13d3SMatan Azrad 		goto unregister_new_callback;
226ebea83f8SGaetan Rivet 	}
227a46f8d58SGaetan Rivet 	mac = &dev->data->mac_addrs[0];
228a46f8d58SGaetan Rivet 	if (mac_from_arg) {
229a46f8d58SGaetan Rivet 		/*
230a46f8d58SGaetan Rivet 		 * If MAC address was provided as a parameter,
231a46f8d58SGaetan Rivet 		 * apply to all probed slaves.
232a46f8d58SGaetan Rivet 		 */
233a46f8d58SGaetan Rivet 		FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
234a46f8d58SGaetan Rivet 			ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
235a46f8d58SGaetan Rivet 							       mac);
236a46f8d58SGaetan Rivet 			if (ret) {
237a46f8d58SGaetan Rivet 				ERROR("Failed to set default MAC address");
23895e7a72fSRaslan Darawsheh 				goto cancel_alarm;
239a46f8d58SGaetan Rivet 			}
240a46f8d58SGaetan Rivet 		}
241a46f8d58SGaetan Rivet 	} else {
242a46f8d58SGaetan Rivet 		/*
243a46f8d58SGaetan Rivet 		 * Use the ether_addr from first probed
244a46f8d58SGaetan Rivet 		 * device, either preferred or fallback.
245a46f8d58SGaetan Rivet 		 */
246a46f8d58SGaetan Rivet 		FOREACH_SUBDEV(sdev, i, dev)
247a46f8d58SGaetan Rivet 			if (sdev->state >= DEV_PROBED) {
248a46f8d58SGaetan Rivet 				ether_addr_copy(&ETH(sdev)->data->mac_addrs[0],
249a46f8d58SGaetan Rivet 						mac);
250a46f8d58SGaetan Rivet 				break;
251a46f8d58SGaetan Rivet 			}
252a46f8d58SGaetan Rivet 		/*
253a46f8d58SGaetan Rivet 		 * If no device has been probed and no ether_addr
254a46f8d58SGaetan Rivet 		 * has been provided on the command line, use a random
255a46f8d58SGaetan Rivet 		 * valid one.
256a46f8d58SGaetan Rivet 		 * It will be applied during future slave state syncs to
257a46f8d58SGaetan Rivet 		 * probed slaves.
258a46f8d58SGaetan Rivet 		 */
259a46f8d58SGaetan Rivet 		if (i == priv->subs_tail)
260a46f8d58SGaetan Rivet 			eth_random_addr(&mac->addr_bytes[0]);
261a46f8d58SGaetan Rivet 	}
262a46f8d58SGaetan Rivet 	INFO("MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
263a46f8d58SGaetan Rivet 		mac->addr_bytes[0], mac->addr_bytes[1],
264a46f8d58SGaetan Rivet 		mac->addr_bytes[2], mac->addr_bytes[3],
265a46f8d58SGaetan Rivet 		mac->addr_bytes[4], mac->addr_bytes[5]);
266ad7d6a35SGaetan Rivet 	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
2679e0360aeSMoti Haimovsky 	PRIV(dev)->intr_handle = (struct rte_intr_handle){
2689e0360aeSMoti Haimovsky 		.fd = -1,
2699e0360aeSMoti Haimovsky 		.type = RTE_INTR_HANDLE_EXT,
2709e0360aeSMoti Haimovsky 	};
271fbe90cddSThomas Monjalon 	rte_eth_dev_probing_finish(dev);
272a46f8d58SGaetan Rivet 	return 0;
27395e7a72fSRaslan Darawsheh cancel_alarm:
27495e7a72fSRaslan Darawsheh 	failsafe_hotplug_alarm_cancel(dev);
2757fda13d3SMatan Azrad unregister_new_callback:
2767fda13d3SMatan Azrad 	rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
2777fda13d3SMatan Azrad 					failsafe_eth_new_event_callback, dev);
278a46f8d58SGaetan Rivet free_args:
279a46f8d58SGaetan Rivet 	failsafe_args_free(dev);
280a46f8d58SGaetan Rivet free_subs:
281a46f8d58SGaetan Rivet 	fs_sub_device_free(dev);
282a46f8d58SGaetan Rivet free_dev:
283a46f8d58SGaetan Rivet 	rte_free(PRIV(dev));
284a46f8d58SGaetan Rivet 	rte_eth_dev_release_port(dev);
285a46f8d58SGaetan Rivet 	return -1;
286a46f8d58SGaetan Rivet }
287a46f8d58SGaetan Rivet 
288a46f8d58SGaetan Rivet static int
289a46f8d58SGaetan Rivet fs_rte_eth_free(const char *name)
290a46f8d58SGaetan Rivet {
291a46f8d58SGaetan Rivet 	struct rte_eth_dev *dev;
292a46f8d58SGaetan Rivet 	int ret;
293a46f8d58SGaetan Rivet 
294a46f8d58SGaetan Rivet 	dev = rte_eth_dev_allocated(name);
295a46f8d58SGaetan Rivet 	if (dev == NULL)
296a46f8d58SGaetan Rivet 		return -ENODEV;
2977fda13d3SMatan Azrad 	rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
2987fda13d3SMatan Azrad 					failsafe_eth_new_event_callback, dev);
299a46f8d58SGaetan Rivet 	ret = failsafe_eal_uninit(dev);
300a46f8d58SGaetan Rivet 	if (ret)
301a46f8d58SGaetan Rivet 		ERROR("Error while uninitializing sub-EAL");
302a46f8d58SGaetan Rivet 	failsafe_args_free(dev);
303a46f8d58SGaetan Rivet 	fs_sub_device_free(dev);
304655fcd68SMatan Azrad 	ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex);
305655fcd68SMatan Azrad 	if (ret)
306655fcd68SMatan Azrad 		ERROR("Error while destroying hotplug mutex");
307a46f8d58SGaetan Rivet 	rte_free(PRIV(dev));
308a46f8d58SGaetan Rivet 	rte_eth_dev_release_port(dev);
309a46f8d58SGaetan Rivet 	return ret;
310a46f8d58SGaetan Rivet }
311a46f8d58SGaetan Rivet 
312a46f8d58SGaetan Rivet static int
313a46f8d58SGaetan Rivet rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
314a46f8d58SGaetan Rivet {
315a46f8d58SGaetan Rivet 	const char *name;
316ee27edbeSJianfeng Tan 	struct rte_eth_dev *eth_dev;
317a46f8d58SGaetan Rivet 
318a46f8d58SGaetan Rivet 	name = rte_vdev_device_name(vdev);
319a46f8d58SGaetan Rivet 	INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
320a46f8d58SGaetan Rivet 			name);
321ee27edbeSJianfeng Tan 
322ee27edbeSJianfeng Tan 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
323ee27edbeSJianfeng Tan 	    strlen(rte_vdev_device_args(vdev)) == 0) {
324ee27edbeSJianfeng Tan 		eth_dev = rte_eth_dev_attach_secondary(name);
325ee27edbeSJianfeng Tan 		if (!eth_dev) {
326ebeb72ecSStephen Hemminger 			ERROR("Failed to probe %s", name);
327ee27edbeSJianfeng Tan 			return -1;
328ee27edbeSJianfeng Tan 		}
329ee27edbeSJianfeng Tan 		/* TODO: request info from primary to set up Rx and Tx */
330ee27edbeSJianfeng Tan 		eth_dev->dev_ops = &failsafe_ops;
331*d1c3ab22SFerruh Yigit 		eth_dev->device = &vdev->device;
332fbe90cddSThomas Monjalon 		rte_eth_dev_probing_finish(eth_dev);
333ee27edbeSJianfeng Tan 		return 0;
334ee27edbeSJianfeng Tan 	}
335ee27edbeSJianfeng Tan 
336a46f8d58SGaetan Rivet 	return fs_eth_dev_create(vdev);
337a46f8d58SGaetan Rivet }
338a46f8d58SGaetan Rivet 
339a46f8d58SGaetan Rivet static int
340a46f8d58SGaetan Rivet rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
341a46f8d58SGaetan Rivet {
342a46f8d58SGaetan Rivet 	const char *name;
343a46f8d58SGaetan Rivet 
344a46f8d58SGaetan Rivet 	name = rte_vdev_device_name(vdev);
345a46f8d58SGaetan Rivet 	INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
346a46f8d58SGaetan Rivet 	return fs_rte_eth_free(name);
347a46f8d58SGaetan Rivet }
348a46f8d58SGaetan Rivet 
349a46f8d58SGaetan Rivet static struct rte_vdev_driver failsafe_drv = {
350a46f8d58SGaetan Rivet 	.probe = rte_pmd_failsafe_probe,
351a46f8d58SGaetan Rivet 	.remove = rte_pmd_failsafe_remove,
352a46f8d58SGaetan Rivet };
353a46f8d58SGaetan Rivet 
354a46f8d58SGaetan Rivet RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
355a46f8d58SGaetan Rivet RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
356ebeb72ecSStephen Hemminger 
357f8e99896SThomas Monjalon RTE_INIT(failsafe_init_log)
358ebeb72ecSStephen Hemminger {
359ebeb72ecSStephen Hemminger 	failsafe_logtype = rte_log_register("pmd.net.failsafe");
360ebeb72ecSStephen Hemminger 	if (failsafe_logtype >= 0)
361ebeb72ecSStephen Hemminger 		rte_log_set_level(failsafe_logtype, RTE_LOG_NOTICE);
362ebeb72ecSStephen Hemminger }
363