xref: /dpdk/lib/eal/linux/eal_dev.c (revision 4e3582ab)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <string.h>
699a2dd95SBruce Richardson #include <unistd.h>
799a2dd95SBruce Richardson #include <signal.h>
899a2dd95SBruce Richardson #include <sys/socket.h>
999a2dd95SBruce Richardson #include <linux/netlink.h>
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #include <rte_string_fns.h>
1299a2dd95SBruce Richardson #include <rte_log.h>
1399a2dd95SBruce Richardson #include <rte_dev.h>
1499a2dd95SBruce Richardson #include <rte_interrupts.h>
1599a2dd95SBruce Richardson #include <rte_alarm.h>
1699a2dd95SBruce Richardson #include <rte_bus.h>
1799a2dd95SBruce Richardson #include <rte_spinlock.h>
1899a2dd95SBruce Richardson #include <rte_errno.h>
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson #include "eal_private.h"
2199a2dd95SBruce Richardson 
22c2bd9367SHarman Kalra static struct rte_intr_handle *intr_handle;
2399a2dd95SBruce Richardson static rte_rwlock_t monitor_lock = RTE_RWLOCK_INITIALIZER;
2499a2dd95SBruce Richardson static uint32_t monitor_refcount;
2599a2dd95SBruce Richardson static bool hotplug_handle;
2699a2dd95SBruce Richardson 
2799a2dd95SBruce Richardson #define EAL_UEV_MSG_LEN 4096
2899a2dd95SBruce Richardson #define EAL_UEV_MSG_ELEM_LEN 128
2999a2dd95SBruce Richardson 
3099a2dd95SBruce Richardson /*
3199a2dd95SBruce Richardson  * spinlock for device hot-unplug failure handling. If it try to access bus or
3299a2dd95SBruce Richardson  * device, such as handle sigbus on bus or handle memory failure for device
3399a2dd95SBruce Richardson  * just need to use this lock. It could protect the bus and the device to avoid
3499a2dd95SBruce Richardson  * race condition.
3599a2dd95SBruce Richardson  */
3699a2dd95SBruce Richardson static rte_spinlock_t failure_handle_lock = RTE_SPINLOCK_INITIALIZER;
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson static struct sigaction sigbus_action_old;
3999a2dd95SBruce Richardson 
4099a2dd95SBruce Richardson static int sigbus_need_recover;
4199a2dd95SBruce Richardson 
4299a2dd95SBruce Richardson static void dev_uev_handler(__rte_unused void *param);
4399a2dd95SBruce Richardson 
4499a2dd95SBruce Richardson /* identify the system layer which reports this event. */
4599a2dd95SBruce Richardson enum eal_dev_event_subsystem {
4699a2dd95SBruce Richardson 	EAL_DEV_EVENT_SUBSYSTEM_PCI, /* PCI bus device event */
4799a2dd95SBruce Richardson 	EAL_DEV_EVENT_SUBSYSTEM_UIO, /* UIO driver device event */
4899a2dd95SBruce Richardson 	EAL_DEV_EVENT_SUBSYSTEM_VFIO, /* VFIO driver device event */
4999a2dd95SBruce Richardson 	EAL_DEV_EVENT_SUBSYSTEM_MAX
5099a2dd95SBruce Richardson };
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson static void
sigbus_action_recover(void)5399a2dd95SBruce Richardson sigbus_action_recover(void)
5499a2dd95SBruce Richardson {
5599a2dd95SBruce Richardson 	if (sigbus_need_recover) {
5699a2dd95SBruce Richardson 		sigaction(SIGBUS, &sigbus_action_old, NULL);
5799a2dd95SBruce Richardson 		sigbus_need_recover = 0;
5899a2dd95SBruce Richardson 	}
5999a2dd95SBruce Richardson }
6099a2dd95SBruce Richardson 
sigbus_handler(int signum,siginfo_t * info,void * ctx __rte_unused)6199a2dd95SBruce Richardson static void sigbus_handler(int signum, siginfo_t *info,
6299a2dd95SBruce Richardson 				void *ctx __rte_unused)
6399a2dd95SBruce Richardson {
6499a2dd95SBruce Richardson 	int ret;
6599a2dd95SBruce Richardson 
6699a2dd95SBruce Richardson 	RTE_LOG(DEBUG, EAL, "Thread catch SIGBUS, fault address:%p\n",
6799a2dd95SBruce Richardson 		info->si_addr);
6899a2dd95SBruce Richardson 
6999a2dd95SBruce Richardson 	rte_spinlock_lock(&failure_handle_lock);
7099a2dd95SBruce Richardson 	ret = rte_bus_sigbus_handler(info->si_addr);
7199a2dd95SBruce Richardson 	rte_spinlock_unlock(&failure_handle_lock);
7299a2dd95SBruce Richardson 	if (ret == -1) {
7399a2dd95SBruce Richardson 		rte_exit(EXIT_FAILURE,
7499a2dd95SBruce Richardson 			 "Failed to handle SIGBUS for hot-unplug, "
7599a2dd95SBruce Richardson 			 "(rte_errno: %s)!", strerror(rte_errno));
7699a2dd95SBruce Richardson 	} else if (ret == 1) {
7799a2dd95SBruce Richardson 		if (sigbus_action_old.sa_flags == SA_SIGINFO
7899a2dd95SBruce Richardson 		    && sigbus_action_old.sa_sigaction) {
7999a2dd95SBruce Richardson 			(*(sigbus_action_old.sa_sigaction))(signum,
8099a2dd95SBruce Richardson 							    info, ctx);
8199a2dd95SBruce Richardson 		} else if (sigbus_action_old.sa_flags != SA_SIGINFO
8299a2dd95SBruce Richardson 			   && sigbus_action_old.sa_handler) {
8399a2dd95SBruce Richardson 			(*(sigbus_action_old.sa_handler))(signum);
8499a2dd95SBruce Richardson 		} else {
8599a2dd95SBruce Richardson 			rte_exit(EXIT_FAILURE,
8699a2dd95SBruce Richardson 				 "Failed to handle generic SIGBUS!");
8799a2dd95SBruce Richardson 		}
8899a2dd95SBruce Richardson 	}
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson 	RTE_LOG(DEBUG, EAL, "Success to handle SIGBUS for hot-unplug!\n");
9199a2dd95SBruce Richardson }
9299a2dd95SBruce Richardson 
cmp_dev_name(const struct rte_device * dev,const void * _name)9399a2dd95SBruce Richardson static int cmp_dev_name(const struct rte_device *dev,
9499a2dd95SBruce Richardson 	const void *_name)
9599a2dd95SBruce Richardson {
9699a2dd95SBruce Richardson 	const char *name = _name;
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson 	return strcmp(dev->name, name);
9999a2dd95SBruce Richardson }
10099a2dd95SBruce Richardson 
10199a2dd95SBruce Richardson static int
dev_uev_socket_fd_create(void)10299a2dd95SBruce Richardson dev_uev_socket_fd_create(void)
10399a2dd95SBruce Richardson {
10499a2dd95SBruce Richardson 	struct sockaddr_nl addr;
105c2bd9367SHarman Kalra 	int ret, fd;
10699a2dd95SBruce Richardson 
107c2bd9367SHarman Kalra 	fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
10899a2dd95SBruce Richardson 		    NETLINK_KOBJECT_UEVENT);
109c2bd9367SHarman Kalra 	if (fd < 0) {
11099a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "create uevent fd failed.\n");
11199a2dd95SBruce Richardson 		return -1;
11299a2dd95SBruce Richardson 	}
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 	memset(&addr, 0, sizeof(addr));
11599a2dd95SBruce Richardson 	addr.nl_family = AF_NETLINK;
11699a2dd95SBruce Richardson 	addr.nl_pid = 0;
11799a2dd95SBruce Richardson 	addr.nl_groups = 0xffffffff;
11899a2dd95SBruce Richardson 
119c2bd9367SHarman Kalra 	ret = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
12099a2dd95SBruce Richardson 	if (ret < 0) {
12199a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "Failed to bind uevent socket.\n");
12299a2dd95SBruce Richardson 		goto err;
12399a2dd95SBruce Richardson 	}
12499a2dd95SBruce Richardson 
125c2bd9367SHarman Kalra 	if (rte_intr_fd_set(intr_handle, fd))
126c2bd9367SHarman Kalra 		goto err;
127c2bd9367SHarman Kalra 
12899a2dd95SBruce Richardson 	return 0;
12999a2dd95SBruce Richardson err:
130c2bd9367SHarman Kalra 	close(fd);
131c2bd9367SHarman Kalra 	fd = -1;
13299a2dd95SBruce Richardson 	return ret;
13399a2dd95SBruce Richardson }
13499a2dd95SBruce Richardson 
13599a2dd95SBruce Richardson struct rte_dev_event {
13699a2dd95SBruce Richardson 	enum rte_dev_event_type type;	/**< device event type */
13799a2dd95SBruce Richardson 	int subsystem;			/**< subsystem id */
13899a2dd95SBruce Richardson 	char *devname;			/**< device name */
13999a2dd95SBruce Richardson };
14099a2dd95SBruce Richardson 
14199a2dd95SBruce Richardson static int
dev_uev_parse(const char * buf,struct rte_dev_event * event,int length)14299a2dd95SBruce Richardson dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
14399a2dd95SBruce Richardson {
14499a2dd95SBruce Richardson 	char action[EAL_UEV_MSG_ELEM_LEN];
14599a2dd95SBruce Richardson 	char subsystem[EAL_UEV_MSG_ELEM_LEN];
14699a2dd95SBruce Richardson 	char pci_slot_name[EAL_UEV_MSG_ELEM_LEN];
14799a2dd95SBruce Richardson 	int i = 0;
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson 	memset(action, 0, EAL_UEV_MSG_ELEM_LEN);
15099a2dd95SBruce Richardson 	memset(subsystem, 0, EAL_UEV_MSG_ELEM_LEN);
15199a2dd95SBruce Richardson 	memset(pci_slot_name, 0, EAL_UEV_MSG_ELEM_LEN);
15299a2dd95SBruce Richardson 
15399a2dd95SBruce Richardson 	while (i < length) {
15499a2dd95SBruce Richardson 		for (; i < length; i++) {
15599a2dd95SBruce Richardson 			if (*buf)
15699a2dd95SBruce Richardson 				break;
15799a2dd95SBruce Richardson 			buf++;
15899a2dd95SBruce Richardson 		}
1594847122aSDavid Marchand 		if (i >= length)
1604847122aSDavid Marchand 			break;
1614847122aSDavid Marchand 
16299a2dd95SBruce Richardson 		/**
16399a2dd95SBruce Richardson 		 * check device uevent from kernel side, no need to check
16499a2dd95SBruce Richardson 		 * uevent from udev.
16599a2dd95SBruce Richardson 		 */
16699a2dd95SBruce Richardson 		if (!strncmp(buf, "libudev", 7)) {
16799a2dd95SBruce Richardson 			buf += 7;
16899a2dd95SBruce Richardson 			i += 7;
16999a2dd95SBruce Richardson 			return -1;
17099a2dd95SBruce Richardson 		}
17199a2dd95SBruce Richardson 		if (!strncmp(buf, "ACTION=", 7)) {
17299a2dd95SBruce Richardson 			buf += 7;
17399a2dd95SBruce Richardson 			i += 7;
17499a2dd95SBruce Richardson 			strlcpy(action, buf, sizeof(action));
17599a2dd95SBruce Richardson 		} else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
17699a2dd95SBruce Richardson 			buf += 10;
17799a2dd95SBruce Richardson 			i += 10;
17899a2dd95SBruce Richardson 			strlcpy(subsystem, buf, sizeof(subsystem));
17999a2dd95SBruce Richardson 		} else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
18099a2dd95SBruce Richardson 			buf += 14;
18199a2dd95SBruce Richardson 			i += 14;
18299a2dd95SBruce Richardson 			strlcpy(pci_slot_name, buf, sizeof(subsystem));
18399a2dd95SBruce Richardson 			event->devname = strdup(pci_slot_name);
18499a2dd95SBruce Richardson 		}
18599a2dd95SBruce Richardson 		for (; i < length; i++) {
18699a2dd95SBruce Richardson 			if (*buf == '\0')
18799a2dd95SBruce Richardson 				break;
18899a2dd95SBruce Richardson 			buf++;
18999a2dd95SBruce Richardson 		}
19099a2dd95SBruce Richardson 	}
19199a2dd95SBruce Richardson 
19299a2dd95SBruce Richardson 	/* parse the subsystem layer */
19399a2dd95SBruce Richardson 	if (!strncmp(subsystem, "uio", 3))
19499a2dd95SBruce Richardson 		event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_UIO;
19599a2dd95SBruce Richardson 	else if (!strncmp(subsystem, "pci", 3))
19699a2dd95SBruce Richardson 		event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_PCI;
19799a2dd95SBruce Richardson 	else if (!strncmp(subsystem, "vfio", 4))
19899a2dd95SBruce Richardson 		event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_VFIO;
19999a2dd95SBruce Richardson 	else
20099a2dd95SBruce Richardson 		goto err;
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson 	/* parse the action type */
20399a2dd95SBruce Richardson 	if (!strncmp(action, "add", 3))
20499a2dd95SBruce Richardson 		event->type = RTE_DEV_EVENT_ADD;
20599a2dd95SBruce Richardson 	else if (!strncmp(action, "remove", 6))
20699a2dd95SBruce Richardson 		event->type = RTE_DEV_EVENT_REMOVE;
20799a2dd95SBruce Richardson 	else
20899a2dd95SBruce Richardson 		goto err;
20999a2dd95SBruce Richardson 	return 0;
21099a2dd95SBruce Richardson err:
21199a2dd95SBruce Richardson 	free(event->devname);
21299a2dd95SBruce Richardson 	return -1;
21399a2dd95SBruce Richardson }
21499a2dd95SBruce Richardson 
21599a2dd95SBruce Richardson static void
dev_delayed_unregister(void * param)21699a2dd95SBruce Richardson dev_delayed_unregister(void *param)
21799a2dd95SBruce Richardson {
218c2bd9367SHarman Kalra 	rte_intr_callback_unregister(intr_handle, dev_uev_handler, param);
2197e2083e4SHarman Kalra 	if (rte_intr_fd_get(intr_handle) >= 0) {
220c2bd9367SHarman Kalra 		close(rte_intr_fd_get(intr_handle));
221c2bd9367SHarman Kalra 		rte_intr_fd_set(intr_handle, -1);
22299a2dd95SBruce Richardson 	}
2237e2083e4SHarman Kalra }
22499a2dd95SBruce Richardson 
22599a2dd95SBruce Richardson static void
dev_uev_handler(__rte_unused void * param)22699a2dd95SBruce Richardson dev_uev_handler(__rte_unused void *param)
22799a2dd95SBruce Richardson {
22899a2dd95SBruce Richardson 	struct rte_dev_event uevent;
22999a2dd95SBruce Richardson 	int ret;
2301a287fc9SSteve Yang 	char buf[EAL_UEV_MSG_LEN + 1];
23199a2dd95SBruce Richardson 	struct rte_bus *bus;
23299a2dd95SBruce Richardson 	struct rte_device *dev;
23399a2dd95SBruce Richardson 	const char *busname = "";
23499a2dd95SBruce Richardson 
23599a2dd95SBruce Richardson 	memset(&uevent, 0, sizeof(struct rte_dev_event));
2361a287fc9SSteve Yang 	memset(buf, 0, EAL_UEV_MSG_LEN + 1);
23799a2dd95SBruce Richardson 
2387e2083e4SHarman Kalra 	if (rte_intr_fd_get(intr_handle) < 0)
2397e2083e4SHarman Kalra 		return;
2407e2083e4SHarman Kalra 
241c2bd9367SHarman Kalra 	ret = recv(rte_intr_fd_get(intr_handle), buf, EAL_UEV_MSG_LEN,
242c2bd9367SHarman Kalra 		   MSG_DONTWAIT);
24399a2dd95SBruce Richardson 	if (ret < 0 && errno == EAGAIN)
24499a2dd95SBruce Richardson 		return;
24599a2dd95SBruce Richardson 	else if (ret <= 0) {
24699a2dd95SBruce Richardson 		/* connection is closed or broken, can not up again. */
24799a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "uevent socket connection is broken.\n");
24899a2dd95SBruce Richardson 		rte_eal_alarm_set(1, dev_delayed_unregister, NULL);
24999a2dd95SBruce Richardson 		return;
25099a2dd95SBruce Richardson 	}
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 	ret = dev_uev_parse(buf, &uevent, EAL_UEV_MSG_LEN);
25399a2dd95SBruce Richardson 	if (ret < 0) {
25499a2dd95SBruce Richardson 		RTE_LOG(DEBUG, EAL, "Ignoring uevent '%s'\n", buf);
25599a2dd95SBruce Richardson 		return;
25699a2dd95SBruce Richardson 	}
25799a2dd95SBruce Richardson 
25899a2dd95SBruce Richardson 	RTE_LOG(DEBUG, EAL, "receive uevent(name:%s, type:%d, subsystem:%d)\n",
25999a2dd95SBruce Richardson 		uevent.devname, uevent.type, uevent.subsystem);
26099a2dd95SBruce Richardson 
26199a2dd95SBruce Richardson 	switch (uevent.subsystem) {
26299a2dd95SBruce Richardson 	case EAL_DEV_EVENT_SUBSYSTEM_PCI:
26399a2dd95SBruce Richardson 	case EAL_DEV_EVENT_SUBSYSTEM_UIO:
26499a2dd95SBruce Richardson 		busname = "pci";
26599a2dd95SBruce Richardson 		break;
26699a2dd95SBruce Richardson 	default:
26799a2dd95SBruce Richardson 		break;
26899a2dd95SBruce Richardson 	}
26999a2dd95SBruce Richardson 
27099a2dd95SBruce Richardson 	if (uevent.devname) {
27199a2dd95SBruce Richardson 		if (uevent.type == RTE_DEV_EVENT_REMOVE && hotplug_handle) {
27299a2dd95SBruce Richardson 			rte_spinlock_lock(&failure_handle_lock);
27399a2dd95SBruce Richardson 			bus = rte_bus_find_by_name(busname);
27499a2dd95SBruce Richardson 			if (bus == NULL) {
27599a2dd95SBruce Richardson 				RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n",
27699a2dd95SBruce Richardson 					busname);
27799a2dd95SBruce Richardson 				goto failure_handle_err;
27899a2dd95SBruce Richardson 			}
27999a2dd95SBruce Richardson 
28099a2dd95SBruce Richardson 			dev = bus->find_device(NULL, cmp_dev_name,
28199a2dd95SBruce Richardson 					       uevent.devname);
28299a2dd95SBruce Richardson 			if (dev == NULL) {
28399a2dd95SBruce Richardson 				RTE_LOG(ERR, EAL, "Cannot find device (%s) on "
28499a2dd95SBruce Richardson 					"bus (%s)\n", uevent.devname, busname);
28599a2dd95SBruce Richardson 				goto failure_handle_err;
28699a2dd95SBruce Richardson 			}
28799a2dd95SBruce Richardson 
28899a2dd95SBruce Richardson 			ret = bus->hot_unplug_handler(dev);
28999a2dd95SBruce Richardson 			if (ret) {
29099a2dd95SBruce Richardson 				RTE_LOG(ERR, EAL, "Can not handle hot-unplug "
29199a2dd95SBruce Richardson 					"for device (%s)\n", dev->name);
29299a2dd95SBruce Richardson 			}
29399a2dd95SBruce Richardson 			rte_spinlock_unlock(&failure_handle_lock);
29499a2dd95SBruce Richardson 		}
29599a2dd95SBruce Richardson 		rte_dev_event_callback_process(uevent.devname, uevent.type);
29699a2dd95SBruce Richardson 		free(uevent.devname);
29799a2dd95SBruce Richardson 	}
29899a2dd95SBruce Richardson 
29999a2dd95SBruce Richardson 	return;
30099a2dd95SBruce Richardson 
30199a2dd95SBruce Richardson failure_handle_err:
30299a2dd95SBruce Richardson 	rte_spinlock_unlock(&failure_handle_lock);
30399a2dd95SBruce Richardson 	free(uevent.devname);
30499a2dd95SBruce Richardson }
30599a2dd95SBruce Richardson 
30699a2dd95SBruce Richardson int
rte_dev_event_monitor_start(void)30799a2dd95SBruce Richardson rte_dev_event_monitor_start(void)
30899a2dd95SBruce Richardson {
30999a2dd95SBruce Richardson 	int ret = 0;
31099a2dd95SBruce Richardson 
31199a2dd95SBruce Richardson 	rte_rwlock_write_lock(&monitor_lock);
31299a2dd95SBruce Richardson 
31399a2dd95SBruce Richardson 	if (monitor_refcount) {
31499a2dd95SBruce Richardson 		monitor_refcount++;
31599a2dd95SBruce Richardson 		goto exit;
31699a2dd95SBruce Richardson 	}
31799a2dd95SBruce Richardson 
318c2bd9367SHarman Kalra 	intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
319c2bd9367SHarman Kalra 	if (intr_handle == NULL) {
320c2bd9367SHarman Kalra 		RTE_LOG(ERR, EAL, "Fail to allocate intr_handle\n");
321c2bd9367SHarman Kalra 		goto exit;
322c2bd9367SHarman Kalra 	}
323c2bd9367SHarman Kalra 
32456331733SDavid Marchand 	ret = rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_DEV_EVENT);
32556331733SDavid Marchand 	if (ret)
326c2bd9367SHarman Kalra 		goto exit;
327c2bd9367SHarman Kalra 
32856331733SDavid Marchand 	ret = rte_intr_fd_set(intr_handle, -1);
32956331733SDavid Marchand 	if (ret)
330c2bd9367SHarman Kalra 		goto exit;
331c2bd9367SHarman Kalra 
33299a2dd95SBruce Richardson 	ret = dev_uev_socket_fd_create();
33399a2dd95SBruce Richardson 	if (ret) {
33499a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "error create device event fd.\n");
33599a2dd95SBruce Richardson 		goto exit;
33699a2dd95SBruce Richardson 	}
33799a2dd95SBruce Richardson 
338c2bd9367SHarman Kalra 	ret = rte_intr_callback_register(intr_handle, dev_uev_handler, NULL);
33999a2dd95SBruce Richardson 
34099a2dd95SBruce Richardson 	if (ret) {
341c2bd9367SHarman Kalra 		close(rte_intr_fd_get(intr_handle));
34299a2dd95SBruce Richardson 		goto exit;
34399a2dd95SBruce Richardson 	}
34499a2dd95SBruce Richardson 
34599a2dd95SBruce Richardson 	monitor_refcount++;
34699a2dd95SBruce Richardson 
34799a2dd95SBruce Richardson exit:
34856331733SDavid Marchand 	if (ret) {
349c2bd9367SHarman Kalra 		rte_intr_instance_free(intr_handle);
35056331733SDavid Marchand 		intr_handle = NULL;
35156331733SDavid Marchand 	}
35299a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&monitor_lock);
35399a2dd95SBruce Richardson 	return ret;
35499a2dd95SBruce Richardson }
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson int
rte_dev_event_monitor_stop(void)35799a2dd95SBruce Richardson rte_dev_event_monitor_stop(void)
35899a2dd95SBruce Richardson {
35999a2dd95SBruce Richardson 	int ret = 0;
36099a2dd95SBruce Richardson 
36199a2dd95SBruce Richardson 	rte_rwlock_write_lock(&monitor_lock);
36299a2dd95SBruce Richardson 
36399a2dd95SBruce Richardson 	if (!monitor_refcount) {
36499a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "device event monitor already stopped\n");
36599a2dd95SBruce Richardson 		goto exit;
36699a2dd95SBruce Richardson 	}
36799a2dd95SBruce Richardson 
36899a2dd95SBruce Richardson 	if (monitor_refcount > 1) {
36999a2dd95SBruce Richardson 		monitor_refcount--;
37099a2dd95SBruce Richardson 		goto exit;
37199a2dd95SBruce Richardson 	}
37299a2dd95SBruce Richardson 
373c2bd9367SHarman Kalra 	ret = rte_intr_callback_unregister(intr_handle, dev_uev_handler,
37499a2dd95SBruce Richardson 					   (void *)-1);
37599a2dd95SBruce Richardson 	if (ret < 0) {
37699a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL, "fail to unregister uevent callback.\n");
37799a2dd95SBruce Richardson 		goto exit;
37899a2dd95SBruce Richardson 	}
37999a2dd95SBruce Richardson 
380c2bd9367SHarman Kalra 	close(rte_intr_fd_get(intr_handle));
381c2bd9367SHarman Kalra 	rte_intr_instance_free(intr_handle);
38256331733SDavid Marchand 	intr_handle = NULL;
383*4e3582abSWenxuan Wu 	ret = 0;
38499a2dd95SBruce Richardson 
38599a2dd95SBruce Richardson 	monitor_refcount--;
38699a2dd95SBruce Richardson 
38799a2dd95SBruce Richardson exit:
38899a2dd95SBruce Richardson 	rte_rwlock_write_unlock(&monitor_lock);
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson 	return ret;
39199a2dd95SBruce Richardson }
39299a2dd95SBruce Richardson 
39399a2dd95SBruce Richardson int
dev_sigbus_handler_register(void)39499a2dd95SBruce Richardson dev_sigbus_handler_register(void)
39599a2dd95SBruce Richardson {
39699a2dd95SBruce Richardson 	sigset_t mask;
39799a2dd95SBruce Richardson 	struct sigaction action;
39899a2dd95SBruce Richardson 
39999a2dd95SBruce Richardson 	rte_errno = 0;
40099a2dd95SBruce Richardson 
40199a2dd95SBruce Richardson 	if (sigbus_need_recover)
40299a2dd95SBruce Richardson 		return 0;
40399a2dd95SBruce Richardson 
40499a2dd95SBruce Richardson 	sigemptyset(&mask);
40599a2dd95SBruce Richardson 	sigaddset(&mask, SIGBUS);
40699a2dd95SBruce Richardson 	action.sa_flags = SA_SIGINFO;
40799a2dd95SBruce Richardson 	action.sa_mask = mask;
40899a2dd95SBruce Richardson 	action.sa_sigaction = sigbus_handler;
40999a2dd95SBruce Richardson 	sigbus_need_recover = !sigaction(SIGBUS, &action, &sigbus_action_old);
41099a2dd95SBruce Richardson 
41199a2dd95SBruce Richardson 	return rte_errno;
41299a2dd95SBruce Richardson }
41399a2dd95SBruce Richardson 
41499a2dd95SBruce Richardson int
dev_sigbus_handler_unregister(void)41599a2dd95SBruce Richardson dev_sigbus_handler_unregister(void)
41699a2dd95SBruce Richardson {
41799a2dd95SBruce Richardson 	rte_errno = 0;
41899a2dd95SBruce Richardson 
41999a2dd95SBruce Richardson 	sigbus_action_recover();
42099a2dd95SBruce Richardson 
42199a2dd95SBruce Richardson 	return rte_errno;
42299a2dd95SBruce Richardson }
42399a2dd95SBruce Richardson 
42499a2dd95SBruce Richardson int
rte_dev_hotplug_handle_enable(void)42599a2dd95SBruce Richardson rte_dev_hotplug_handle_enable(void)
42699a2dd95SBruce Richardson {
42799a2dd95SBruce Richardson 	int ret = 0;
42899a2dd95SBruce Richardson 
42999a2dd95SBruce Richardson 	ret = dev_sigbus_handler_register();
43099a2dd95SBruce Richardson 	if (ret < 0)
43199a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL,
43299a2dd95SBruce Richardson 			"fail to register sigbus handler for devices.\n");
43399a2dd95SBruce Richardson 
43499a2dd95SBruce Richardson 	hotplug_handle = true;
43599a2dd95SBruce Richardson 
43699a2dd95SBruce Richardson 	return ret;
43799a2dd95SBruce Richardson }
43899a2dd95SBruce Richardson 
43999a2dd95SBruce Richardson int
rte_dev_hotplug_handle_disable(void)44099a2dd95SBruce Richardson rte_dev_hotplug_handle_disable(void)
44199a2dd95SBruce Richardson {
44299a2dd95SBruce Richardson 	int ret = 0;
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson 	ret = dev_sigbus_handler_unregister();
44599a2dd95SBruce Richardson 	if (ret < 0)
44699a2dd95SBruce Richardson 		RTE_LOG(ERR, EAL,
44799a2dd95SBruce Richardson 			"fail to unregister sigbus handler for devices.\n");
44899a2dd95SBruce Richardson 
44999a2dd95SBruce Richardson 	hotplug_handle = false;
45099a2dd95SBruce Richardson 
45199a2dd95SBruce Richardson 	return ret;
45299a2dd95SBruce Richardson }
453