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