xref: /dpdk/drivers/net/failsafe/failsafe.c (revision 58825f4138629d35a74011db62863c7af8e64669)
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 
649377908SRaslan Darawsheh #include <stdbool.h>
749377908SRaslan Darawsheh 
8a46f8d58SGaetan Rivet #include <rte_alarm.h>
9a46f8d58SGaetan Rivet #include <rte_malloc.h>
10df96fd0dSBruce Richardson #include <ethdev_driver.h>
11df96fd0dSBruce Richardson #include <ethdev_vdev.h>
12a46f8d58SGaetan Rivet #include <rte_devargs.h>
13a46f8d58SGaetan Rivet #include <rte_kvargs.h>
14a04322f6SDavid Marchand #include <bus_driver.h>
154851ef2bSDavid Marchand #include <bus_vdev_driver.h>
16a46f8d58SGaetan Rivet 
17a46f8d58SGaetan Rivet #include "failsafe_private.h"
18a46f8d58SGaetan Rivet 
19a46f8d58SGaetan Rivet const char pmd_failsafe_driver_name[] = FAILSAFE_DRIVER_NAME;
20a46f8d58SGaetan Rivet static const struct rte_eth_link eth_link = {
21295968d1SFerruh Yigit 	.link_speed = RTE_ETH_SPEED_NUM_10G,
22295968d1SFerruh Yigit 	.link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
23295968d1SFerruh Yigit 	.link_status = RTE_ETH_LINK_UP,
24295968d1SFerruh Yigit 	.link_autoneg = RTE_ETH_LINK_AUTONEG,
25a46f8d58SGaetan Rivet };
26a46f8d58SGaetan Rivet 
27a46f8d58SGaetan Rivet static int
28a46f8d58SGaetan Rivet fs_sub_device_alloc(struct rte_eth_dev *dev,
29a46f8d58SGaetan Rivet 		const char *params)
30a46f8d58SGaetan Rivet {
31a46f8d58SGaetan Rivet 	uint8_t nb_subs;
32a46f8d58SGaetan Rivet 	int ret;
338052bbd9SMatan Azrad 	int i;
342f4b9983SRaslan Darawsheh 	struct sub_device *sdev;
352f4b9983SRaslan Darawsheh 	uint8_t sdev_iterator;
36a46f8d58SGaetan Rivet 
37a46f8d58SGaetan Rivet 	ret = failsafe_args_count_subdevice(dev, params);
38a46f8d58SGaetan Rivet 	if (ret)
39a46f8d58SGaetan Rivet 		return ret;
40a46f8d58SGaetan Rivet 	if (PRIV(dev)->subs_tail > FAILSAFE_MAX_ETHPORTS) {
41a46f8d58SGaetan Rivet 		ERROR("Cannot allocate more than %d ports",
42a46f8d58SGaetan Rivet 			FAILSAFE_MAX_ETHPORTS);
43a46f8d58SGaetan Rivet 		return -ENOSPC;
44a46f8d58SGaetan Rivet 	}
45a46f8d58SGaetan Rivet 	nb_subs = PRIV(dev)->subs_tail;
46a46f8d58SGaetan Rivet 	PRIV(dev)->subs = rte_zmalloc(NULL,
47a46f8d58SGaetan Rivet 			sizeof(struct sub_device) * nb_subs,
48a46f8d58SGaetan Rivet 			RTE_CACHE_LINE_SIZE);
49a46f8d58SGaetan Rivet 	if (PRIV(dev)->subs == NULL) {
50a46f8d58SGaetan Rivet 		ERROR("Could not allocate sub_devices");
51a46f8d58SGaetan Rivet 		return -ENOMEM;
52a46f8d58SGaetan Rivet 	}
538052bbd9SMatan Azrad 	/* Initiate static sub devices linked list. */
548052bbd9SMatan Azrad 	for (i = 1; i < nb_subs; i++)
558052bbd9SMatan Azrad 		PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs + i;
568052bbd9SMatan Azrad 	PRIV(dev)->subs[i - 1].next = PRIV(dev)->subs;
572f4b9983SRaslan Darawsheh 
582f4b9983SRaslan Darawsheh 	FOREACH_SUBDEV(sdev, sdev_iterator, dev) {
592f4b9983SRaslan Darawsheh 		sdev->sdev_port_id = RTE_MAX_ETHPORTS;
602f4b9983SRaslan Darawsheh 	}
61a46f8d58SGaetan Rivet 	return 0;
62a46f8d58SGaetan Rivet }
63a46f8d58SGaetan Rivet 
64ebea83f8SGaetan Rivet static void fs_hotplug_alarm(void *arg);
65ebea83f8SGaetan Rivet 
66ebea83f8SGaetan Rivet int
67ebea83f8SGaetan Rivet failsafe_hotplug_alarm_install(struct rte_eth_dev *dev)
68ebea83f8SGaetan Rivet {
69ebea83f8SGaetan Rivet 	int ret;
70ebea83f8SGaetan Rivet 
71ebea83f8SGaetan Rivet 	if (dev == NULL)
72ebea83f8SGaetan Rivet 		return -EINVAL;
73ebea83f8SGaetan Rivet 	if (PRIV(dev)->pending_alarm)
74ebea83f8SGaetan Rivet 		return 0;
75520dd992SFerruh Yigit 	ret = rte_eal_alarm_set(failsafe_hotplug_poll * 1000,
76ebea83f8SGaetan Rivet 				fs_hotplug_alarm,
77ebea83f8SGaetan Rivet 				dev);
78ebea83f8SGaetan Rivet 	if (ret) {
79ebea83f8SGaetan Rivet 		ERROR("Could not set up plug-in event detection");
80ebea83f8SGaetan Rivet 		return ret;
81ebea83f8SGaetan Rivet 	}
82ebea83f8SGaetan Rivet 	PRIV(dev)->pending_alarm = 1;
83ebea83f8SGaetan Rivet 	return 0;
84ebea83f8SGaetan Rivet }
85ebea83f8SGaetan Rivet 
86ebea83f8SGaetan Rivet int
87ebea83f8SGaetan Rivet failsafe_hotplug_alarm_cancel(struct rte_eth_dev *dev)
88ebea83f8SGaetan Rivet {
89ebea83f8SGaetan Rivet 	int ret = 0;
90ebea83f8SGaetan Rivet 
91ebea83f8SGaetan Rivet 	rte_errno = 0;
92ebea83f8SGaetan Rivet 	rte_eal_alarm_cancel(fs_hotplug_alarm, dev);
93ebea83f8SGaetan Rivet 	if (rte_errno) {
94ebea83f8SGaetan Rivet 		ERROR("rte_eal_alarm_cancel failed (errno: %s)",
95ebea83f8SGaetan Rivet 		      strerror(rte_errno));
96ebea83f8SGaetan Rivet 		ret = -rte_errno;
97ebea83f8SGaetan Rivet 	} else {
98ebea83f8SGaetan Rivet 		PRIV(dev)->pending_alarm = 0;
99ebea83f8SGaetan Rivet 	}
100ebea83f8SGaetan Rivet 	return ret;
101ebea83f8SGaetan Rivet }
102ebea83f8SGaetan Rivet 
103ebea83f8SGaetan Rivet static void
104ebea83f8SGaetan Rivet fs_hotplug_alarm(void *arg)
105ebea83f8SGaetan Rivet {
106ebea83f8SGaetan Rivet 	struct rte_eth_dev *dev = arg;
107ebea83f8SGaetan Rivet 	struct sub_device *sdev;
108ebea83f8SGaetan Rivet 	int ret;
109ebea83f8SGaetan Rivet 	uint8_t i;
110ebea83f8SGaetan Rivet 
111ebea83f8SGaetan Rivet 	if (!PRIV(dev)->pending_alarm)
112ebea83f8SGaetan Rivet 		return;
113ebea83f8SGaetan Rivet 	PRIV(dev)->pending_alarm = 0;
114ebea83f8SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev)
115ebea83f8SGaetan Rivet 		if (sdev->state != PRIV(dev)->state)
116ebea83f8SGaetan Rivet 			break;
117ebea83f8SGaetan Rivet 	/* if we have non-probed device */
118ebea83f8SGaetan Rivet 	if (i != PRIV(dev)->subs_tail) {
119655fcd68SMatan Azrad 		if (fs_lock(dev, 1) != 0)
120655fcd68SMatan Azrad 			goto reinstall;
121ebea83f8SGaetan Rivet 		ret = failsafe_eth_dev_state_sync(dev);
122655fcd68SMatan Azrad 		fs_unlock(dev, 1);
123ebea83f8SGaetan Rivet 		if (ret)
124ebea83f8SGaetan Rivet 			ERROR("Unable to synchronize sub_device state");
125ebea83f8SGaetan Rivet 	}
126598fb8aeSGaetan Rivet 	failsafe_dev_remove(dev);
127655fcd68SMatan Azrad reinstall:
128ebea83f8SGaetan Rivet 	ret = failsafe_hotplug_alarm_install(dev);
129ebea83f8SGaetan Rivet 	if (ret)
130ebea83f8SGaetan Rivet 		ERROR("Unable to set up next alarm");
131ebea83f8SGaetan Rivet }
132ebea83f8SGaetan Rivet 
133a46f8d58SGaetan Rivet static int
134655fcd68SMatan Azrad fs_mutex_init(struct fs_priv *priv)
135655fcd68SMatan Azrad {
136655fcd68SMatan Azrad 	int ret;
137655fcd68SMatan Azrad 	pthread_mutexattr_t attr;
138655fcd68SMatan Azrad 
139655fcd68SMatan Azrad 	ret = pthread_mutexattr_init(&attr);
140655fcd68SMatan Azrad 	if (ret) {
141655fcd68SMatan Azrad 		ERROR("Cannot initiate mutex attributes - %s", strerror(ret));
142655fcd68SMatan Azrad 		return ret;
143655fcd68SMatan Azrad 	}
144655fcd68SMatan Azrad 	/* Allow mutex relocks for the thread holding the mutex. */
145655fcd68SMatan Azrad 	ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
146655fcd68SMatan Azrad 	if (ret) {
147655fcd68SMatan Azrad 		ERROR("Cannot set mutex type - %s", strerror(ret));
148655fcd68SMatan Azrad 		return ret;
149655fcd68SMatan Azrad 	}
150*58825f41SAriel Otilibili 
151*58825f41SAriel Otilibili 	return pthread_mutex_init(&priv->hotplug_mutex, &attr);
152655fcd68SMatan Azrad }
153655fcd68SMatan Azrad 
154655fcd68SMatan Azrad static int
155a46f8d58SGaetan Rivet fs_eth_dev_create(struct rte_vdev_device *vdev)
156a46f8d58SGaetan Rivet {
157a46f8d58SGaetan Rivet 	struct rte_eth_dev *dev;
1586d13ea8eSOlivier Matz 	struct rte_ether_addr *mac;
159a46f8d58SGaetan Rivet 	struct fs_priv *priv;
160a46f8d58SGaetan Rivet 	struct sub_device *sdev;
161a46f8d58SGaetan Rivet 	const char *params;
162a46f8d58SGaetan Rivet 	unsigned int socket_id;
163a46f8d58SGaetan Rivet 	uint8_t i;
164a46f8d58SGaetan Rivet 	int ret;
165a46f8d58SGaetan Rivet 
166a46f8d58SGaetan Rivet 	dev = NULL;
167a46f8d58SGaetan Rivet 	priv = NULL;
168a46f8d58SGaetan Rivet 	socket_id = rte_socket_id();
169a46f8d58SGaetan Rivet 	INFO("Creating fail-safe device on NUMA socket %u", socket_id);
170a46f8d58SGaetan Rivet 	params = rte_vdev_device_args(vdev);
171a46f8d58SGaetan Rivet 	if (params == NULL) {
172a46f8d58SGaetan Rivet 		ERROR("This PMD requires sub-devices, none provided");
173a46f8d58SGaetan Rivet 		return -1;
174a46f8d58SGaetan Rivet 	}
175a46f8d58SGaetan Rivet 	dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
176a46f8d58SGaetan Rivet 	if (dev == NULL) {
177a46f8d58SGaetan Rivet 		ERROR("Unable to allocate rte_eth_dev");
178a46f8d58SGaetan Rivet 		return -1;
179a46f8d58SGaetan Rivet 	}
180a46f8d58SGaetan Rivet 	priv = PRIV(dev);
18108647012SRaslan Darawsheh 	priv->data = dev->data;
182b9663f60SYunjian Wang 	priv->rxp = FS_RX_PROXY_INIT;
183a46f8d58SGaetan Rivet 	dev->dev_ops = &failsafe_ops;
184a46f8d58SGaetan Rivet 	dev->data->mac_addrs = &PRIV(dev)->mac_addrs[0];
185a46f8d58SGaetan Rivet 	dev->data->dev_link = eth_link;
186a46f8d58SGaetan Rivet 	PRIV(dev)->nb_mac_addr = 1;
187b737a1eeSGaetan Rivet 	TAILQ_INIT(&PRIV(dev)->flow_list);
188a46f8d58SGaetan Rivet 	dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
189a46f8d58SGaetan Rivet 	dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
190a46f8d58SGaetan Rivet 	ret = fs_sub_device_alloc(dev, params);
191a46f8d58SGaetan Rivet 	if (ret) {
192a46f8d58SGaetan Rivet 		ERROR("Could not allocate sub_devices");
193a46f8d58SGaetan Rivet 		goto free_dev;
194a46f8d58SGaetan Rivet 	}
195a46f8d58SGaetan Rivet 	ret = failsafe_args_parse(dev, params);
196a46f8d58SGaetan Rivet 	if (ret)
197a46f8d58SGaetan Rivet 		goto free_subs;
198dcd0c9c3SMatan Azrad 	ret = rte_eth_dev_owner_new(&priv->my_owner.id);
199dcd0c9c3SMatan Azrad 	if (ret) {
200dcd0c9c3SMatan Azrad 		ERROR("Failed to get unique owner identifier");
201dcd0c9c3SMatan Azrad 		goto free_args;
202dcd0c9c3SMatan Azrad 	}
203dcd0c9c3SMatan Azrad 	snprintf(priv->my_owner.name, sizeof(priv->my_owner.name),
204dcd0c9c3SMatan Azrad 		 FAILSAFE_OWNER_NAME);
2057fda13d3SMatan Azrad 	DEBUG("Failsafe port %u owner info: %s_%016"PRIX64, dev->data->port_id,
2067fda13d3SMatan Azrad 	      priv->my_owner.name, priv->my_owner.id);
2077fda13d3SMatan Azrad 	ret = rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
2087fda13d3SMatan Azrad 					    failsafe_eth_new_event_callback,
2097fda13d3SMatan Azrad 					    dev);
2107fda13d3SMatan Azrad 	if (ret) {
2117fda13d3SMatan Azrad 		ERROR("Failed to register NEW callback");
2127fda13d3SMatan Azrad 		goto free_args;
2137fda13d3SMatan Azrad 	}
214a46f8d58SGaetan Rivet 	ret = failsafe_eal_init(dev);
215a46f8d58SGaetan Rivet 	if (ret)
2167fda13d3SMatan Azrad 		goto unregister_new_callback;
217655fcd68SMatan Azrad 	ret = fs_mutex_init(priv);
218655fcd68SMatan Azrad 	if (ret)
2197fda13d3SMatan Azrad 		goto unregister_new_callback;
220ebea83f8SGaetan Rivet 	ret = failsafe_hotplug_alarm_install(dev);
221ebea83f8SGaetan Rivet 	if (ret) {
222ebea83f8SGaetan Rivet 		ERROR("Could not set up plug-in event detection");
2237fda13d3SMatan Azrad 		goto unregister_new_callback;
224ebea83f8SGaetan Rivet 	}
225a46f8d58SGaetan Rivet 	mac = &dev->data->mac_addrs[0];
226520dd992SFerruh Yigit 	if (failsafe_mac_from_arg) {
227a46f8d58SGaetan Rivet 		/*
228a46f8d58SGaetan Rivet 		 * If MAC address was provided as a parameter,
22939fab5a0SStephen Hemminger 		 * apply to all probed subdevices.
230a46f8d58SGaetan Rivet 		 */
231a46f8d58SGaetan Rivet 		FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_PROBED) {
232a46f8d58SGaetan Rivet 			ret = rte_eth_dev_default_mac_addr_set(PORT_ID(sdev),
233a46f8d58SGaetan Rivet 							       mac);
234a46f8d58SGaetan Rivet 			if (ret) {
235a46f8d58SGaetan Rivet 				ERROR("Failed to set default MAC address");
23695e7a72fSRaslan Darawsheh 				goto cancel_alarm;
237a46f8d58SGaetan Rivet 			}
238a46f8d58SGaetan Rivet 		}
239a46f8d58SGaetan Rivet 	} else {
240a46f8d58SGaetan Rivet 		/*
241a46f8d58SGaetan Rivet 		 * Use the ether_addr from first probed
242a46f8d58SGaetan Rivet 		 * device, either preferred or fallback.
243a46f8d58SGaetan Rivet 		 */
244a46f8d58SGaetan Rivet 		FOREACH_SUBDEV(sdev, i, dev)
245a46f8d58SGaetan Rivet 			if (sdev->state >= DEV_PROBED) {
246538da7a1SOlivier Matz 				rte_ether_addr_copy(
247538da7a1SOlivier Matz 					&ETH(sdev)->data->mac_addrs[0], mac);
248a46f8d58SGaetan Rivet 				break;
249a46f8d58SGaetan Rivet 			}
250a46f8d58SGaetan Rivet 		/*
251a46f8d58SGaetan Rivet 		 * If no device has been probed and no ether_addr
252a46f8d58SGaetan Rivet 		 * has been provided on the command line, use a random
253a46f8d58SGaetan Rivet 		 * valid one.
25439fab5a0SStephen Hemminger 		 * It will be applied during future state syncs to
25539fab5a0SStephen Hemminger 		 * probed subdevices.
256a46f8d58SGaetan Rivet 		 */
257a46f8d58SGaetan Rivet 		if (i == priv->subs_tail)
258538da7a1SOlivier Matz 			rte_eth_random_addr(&mac->addr_bytes[0]);
259a46f8d58SGaetan Rivet 	}
260c2c4f87bSAman Deep Singh 	INFO("MAC address is " RTE_ETHER_ADDR_PRT_FMT,
261a7db3afcSAman Deep Singh 		RTE_ETHER_ADDR_BYTES(mac));
262f30e69b4SFerruh Yigit 	dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC |
263f30e69b4SFerruh Yigit 				RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
264d61138d4SHarman Kalra 
265d61138d4SHarman Kalra 	/* Allocate interrupt instance */
266d61138d4SHarman Kalra 	PRIV(dev)->intr_handle =
267d61138d4SHarman Kalra 		rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
268d61138d4SHarman Kalra 	if (PRIV(dev)->intr_handle == NULL) {
269d61138d4SHarman Kalra 		ERROR("Failed to allocate intr handle");
270d61138d4SHarman Kalra 		goto cancel_alarm;
271d61138d4SHarman Kalra 	}
272d61138d4SHarman Kalra 
273d61138d4SHarman Kalra 	if (rte_intr_fd_set(PRIV(dev)->intr_handle, -1))
274d61138d4SHarman Kalra 		goto cancel_alarm;
275d61138d4SHarman Kalra 
276d61138d4SHarman Kalra 	if (rte_intr_type_set(PRIV(dev)->intr_handle, RTE_INTR_HANDLE_EXT))
277d61138d4SHarman Kalra 		goto cancel_alarm;
278d61138d4SHarman Kalra 
279fbe90cddSThomas Monjalon 	rte_eth_dev_probing_finish(dev);
280d61138d4SHarman Kalra 
281a46f8d58SGaetan Rivet 	return 0;
28295e7a72fSRaslan Darawsheh cancel_alarm:
28395e7a72fSRaslan Darawsheh 	failsafe_hotplug_alarm_cancel(dev);
2847fda13d3SMatan Azrad unregister_new_callback:
2857fda13d3SMatan Azrad 	rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW,
2867fda13d3SMatan Azrad 					failsafe_eth_new_event_callback, dev);
287a46f8d58SGaetan Rivet free_args:
288a46f8d58SGaetan Rivet 	failsafe_args_free(dev);
289a46f8d58SGaetan Rivet free_subs:
2901a7fa562SThomas Monjalon 	rte_free(PRIV(dev)->subs);
291a46f8d58SGaetan Rivet free_dev:
292e16adf08SThomas Monjalon 	/* mac_addrs must not be freed alone because part of dev_private */
293e16adf08SThomas Monjalon 	dev->data->mac_addrs = NULL;
294a46f8d58SGaetan Rivet 	rte_eth_dev_release_port(dev);
295a46f8d58SGaetan Rivet 	return -1;
296a46f8d58SGaetan Rivet }
297a46f8d58SGaetan Rivet 
298a46f8d58SGaetan Rivet static int
299a46f8d58SGaetan Rivet fs_rte_eth_free(const char *name)
300a46f8d58SGaetan Rivet {
301a46f8d58SGaetan Rivet 	struct rte_eth_dev *dev;
302a46f8d58SGaetan Rivet 	int ret;
303a46f8d58SGaetan Rivet 
304a46f8d58SGaetan Rivet 	dev = rte_eth_dev_allocated(name);
305a46f8d58SGaetan Rivet 	if (dev == NULL)
3061a7fa562SThomas Monjalon 		return 0; /* port already released */
3071a7fa562SThomas Monjalon 	ret = failsafe_eth_dev_close(dev);
308d61138d4SHarman Kalra 	rte_intr_instance_free(PRIV(dev)->intr_handle);
309fd819cadSYunjian Wang 	rte_eth_dev_release_port(dev);
310a46f8d58SGaetan Rivet 	return ret;
311a46f8d58SGaetan Rivet }
312a46f8d58SGaetan Rivet 
31349377908SRaslan Darawsheh static bool
31449377908SRaslan Darawsheh devargs_already_listed(struct rte_devargs *devargs)
31549377908SRaslan Darawsheh {
31649377908SRaslan Darawsheh 	struct rte_devargs *list_da;
31749377908SRaslan Darawsheh 
31849377908SRaslan Darawsheh 	RTE_EAL_DEVARGS_FOREACH(devargs->bus->name, list_da) {
31949377908SRaslan Darawsheh 		if (strcmp(list_da->name, devargs->name) == 0)
32049377908SRaslan Darawsheh 			/* devargs already in the list */
32149377908SRaslan Darawsheh 			return true;
32249377908SRaslan Darawsheh 	}
32349377908SRaslan Darawsheh 	return false;
32449377908SRaslan Darawsheh }
32549377908SRaslan Darawsheh 
326a46f8d58SGaetan Rivet static int
327a46f8d58SGaetan Rivet rte_pmd_failsafe_probe(struct rte_vdev_device *vdev)
328a46f8d58SGaetan Rivet {
329a46f8d58SGaetan Rivet 	const char *name;
330ee27edbeSJianfeng Tan 	struct rte_eth_dev *eth_dev;
33149377908SRaslan Darawsheh 	struct sub_device  *sdev;
33249377908SRaslan Darawsheh 	struct rte_devargs devargs;
33349377908SRaslan Darawsheh 	uint8_t i;
33449377908SRaslan Darawsheh 	int ret;
335a46f8d58SGaetan Rivet 
336a46f8d58SGaetan Rivet 	name = rte_vdev_device_name(vdev);
337a46f8d58SGaetan Rivet 	INFO("Initializing " FAILSAFE_DRIVER_NAME " for %s",
338a46f8d58SGaetan Rivet 			name);
339ee27edbeSJianfeng Tan 
34047f5dee1SKumara Parameshwaran 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
341ee27edbeSJianfeng Tan 		eth_dev = rte_eth_dev_attach_secondary(name);
342ee27edbeSJianfeng Tan 		if (!eth_dev) {
343ebeb72ecSStephen Hemminger 			ERROR("Failed to probe %s", name);
344ee27edbeSJianfeng Tan 			return -1;
345ee27edbeSJianfeng Tan 		}
346ee27edbeSJianfeng Tan 		eth_dev->dev_ops = &failsafe_ops;
347d1c3ab22SFerruh Yigit 		eth_dev->device = &vdev->device;
34849377908SRaslan Darawsheh 		eth_dev->rx_pkt_burst = (eth_rx_burst_t)&failsafe_rx_burst;
34949377908SRaslan Darawsheh 		eth_dev->tx_pkt_burst = (eth_tx_burst_t)&failsafe_tx_burst;
35049377908SRaslan Darawsheh 		/*
35149377908SRaslan Darawsheh 		 * Failsafe will attempt to probe all of its sub-devices.
35249377908SRaslan Darawsheh 		 * Any failure in sub-devices is not a fatal error.
35349377908SRaslan Darawsheh 		 * A sub-device can be plugged later.
35449377908SRaslan Darawsheh 		 */
35549377908SRaslan Darawsheh 		FOREACH_SUBDEV(sdev, i, eth_dev) {
35669a27a5fSStephen Hemminger 			/* skip empty devargs */
35769a27a5fSStephen Hemminger 			if (sdev->devargs.name[0] == '\0')
35869a27a5fSStephen Hemminger 				continue;
35969a27a5fSStephen Hemminger 
36049377908SRaslan Darawsheh 			/* rebuild devargs to be able to get the bus name. */
36149377908SRaslan Darawsheh 			ret = rte_devargs_parse(&devargs,
36249377908SRaslan Darawsheh 						sdev->devargs.name);
36349377908SRaslan Darawsheh 			if (ret != 0) {
36449377908SRaslan Darawsheh 				ERROR("Failed to parse devargs %s",
36549377908SRaslan Darawsheh 					devargs.name);
36649377908SRaslan Darawsheh 				continue;
36749377908SRaslan Darawsheh 			}
36849377908SRaslan Darawsheh 			if (!devargs_already_listed(&devargs)) {
36949377908SRaslan Darawsheh 				ret = rte_dev_probe(devargs.name);
37075b66decSIlya Maximets 				if (ret < 0) {
37149377908SRaslan Darawsheh 					ERROR("Failed to probe devargs %s",
37249377908SRaslan Darawsheh 					      devargs.name);
37349377908SRaslan Darawsheh 					continue;
37449377908SRaslan Darawsheh 				}
37549377908SRaslan Darawsheh 			}
37649377908SRaslan Darawsheh 		}
377fbe90cddSThomas Monjalon 		rte_eth_dev_probing_finish(eth_dev);
378ee27edbeSJianfeng Tan 		return 0;
379ee27edbeSJianfeng Tan 	}
380ee27edbeSJianfeng Tan 
381a46f8d58SGaetan Rivet 	return fs_eth_dev_create(vdev);
382a46f8d58SGaetan Rivet }
383a46f8d58SGaetan Rivet 
384a46f8d58SGaetan Rivet static int
385a46f8d58SGaetan Rivet rte_pmd_failsafe_remove(struct rte_vdev_device *vdev)
386a46f8d58SGaetan Rivet {
387a46f8d58SGaetan Rivet 	const char *name;
388a46f8d58SGaetan Rivet 
389a46f8d58SGaetan Rivet 	name = rte_vdev_device_name(vdev);
390a46f8d58SGaetan Rivet 	INFO("Uninitializing " FAILSAFE_DRIVER_NAME " for %s", name);
391a46f8d58SGaetan Rivet 	return fs_rte_eth_free(name);
392a46f8d58SGaetan Rivet }
393a46f8d58SGaetan Rivet 
394a46f8d58SGaetan Rivet static struct rte_vdev_driver failsafe_drv = {
395a46f8d58SGaetan Rivet 	.probe = rte_pmd_failsafe_probe,
396a46f8d58SGaetan Rivet 	.remove = rte_pmd_failsafe_remove,
397a46f8d58SGaetan Rivet };
398a46f8d58SGaetan Rivet 
399a46f8d58SGaetan Rivet RTE_PMD_REGISTER_VDEV(net_failsafe, failsafe_drv);
400a46f8d58SGaetan Rivet RTE_PMD_REGISTER_PARAM_STRING(net_failsafe, PMD_FAILSAFE_PARAM_STRING);
401eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(failsafe_logtype, NOTICE)
402