199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
572b452c5SDmitry Kozlyuk #include <stdlib.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson #include <unistd.h>
899a2dd95SBruce Richardson #include <signal.h>
999a2dd95SBruce Richardson #include <sys/socket.h>
1099a2dd95SBruce Richardson #include <linux/netlink.h>
1199a2dd95SBruce Richardson
1299a2dd95SBruce Richardson #include <rte_string_fns.h>
1399a2dd95SBruce Richardson #include <rte_log.h>
1499a2dd95SBruce Richardson #include <rte_dev.h>
1599a2dd95SBruce Richardson #include <rte_interrupts.h>
1699a2dd95SBruce Richardson #include <rte_alarm.h>
17a04322f6SDavid Marchand #include <bus_driver.h>
1899a2dd95SBruce Richardson #include <rte_spinlock.h>
1999a2dd95SBruce Richardson #include <rte_errno.h>
2099a2dd95SBruce Richardson
2199a2dd95SBruce Richardson #include "eal_private.h"
2299a2dd95SBruce Richardson
23c2bd9367SHarman Kalra static struct rte_intr_handle *intr_handle;
2499a2dd95SBruce Richardson static rte_rwlock_t monitor_lock = RTE_RWLOCK_INITIALIZER;
2599a2dd95SBruce Richardson static uint32_t monitor_refcount;
2699a2dd95SBruce Richardson static bool hotplug_handle;
2799a2dd95SBruce Richardson
2899a2dd95SBruce Richardson #define EAL_UEV_MSG_LEN 4096
2999a2dd95SBruce Richardson #define EAL_UEV_MSG_ELEM_LEN 128
3099a2dd95SBruce Richardson
3199a2dd95SBruce Richardson /*
3299a2dd95SBruce Richardson * spinlock for device hot-unplug failure handling. If it try to access bus or
3399a2dd95SBruce Richardson * device, such as handle sigbus on bus or handle memory failure for device
3499a2dd95SBruce Richardson * just need to use this lock. It could protect the bus and the device to avoid
3599a2dd95SBruce Richardson * race condition.
3699a2dd95SBruce Richardson */
3799a2dd95SBruce Richardson static rte_spinlock_t failure_handle_lock = RTE_SPINLOCK_INITIALIZER;
3899a2dd95SBruce Richardson
3999a2dd95SBruce Richardson static struct sigaction sigbus_action_old;
4099a2dd95SBruce Richardson
4199a2dd95SBruce Richardson static int sigbus_need_recover;
4299a2dd95SBruce Richardson
4399a2dd95SBruce Richardson static void dev_uev_handler(__rte_unused void *param);
4499a2dd95SBruce Richardson
4599a2dd95SBruce Richardson /* identify the system layer which reports this event. */
4699a2dd95SBruce Richardson enum eal_dev_event_subsystem {
4799a2dd95SBruce Richardson EAL_DEV_EVENT_SUBSYSTEM_PCI, /* PCI bus device event */
4899a2dd95SBruce Richardson EAL_DEV_EVENT_SUBSYSTEM_UIO, /* UIO driver device event */
4999a2dd95SBruce Richardson EAL_DEV_EVENT_SUBSYSTEM_VFIO, /* VFIO driver device event */
5099a2dd95SBruce Richardson EAL_DEV_EVENT_SUBSYSTEM_MAX
5199a2dd95SBruce Richardson };
5299a2dd95SBruce Richardson
5399a2dd95SBruce Richardson static void
sigbus_action_recover(void)5499a2dd95SBruce Richardson sigbus_action_recover(void)
5599a2dd95SBruce Richardson {
5699a2dd95SBruce Richardson if (sigbus_need_recover) {
5799a2dd95SBruce Richardson sigaction(SIGBUS, &sigbus_action_old, NULL);
5899a2dd95SBruce Richardson sigbus_need_recover = 0;
5999a2dd95SBruce Richardson }
6099a2dd95SBruce Richardson }
6199a2dd95SBruce Richardson
sigbus_handler(int signum,siginfo_t * info,void * ctx __rte_unused)6299a2dd95SBruce Richardson static void sigbus_handler(int signum, siginfo_t *info,
6399a2dd95SBruce Richardson void *ctx __rte_unused)
6499a2dd95SBruce Richardson {
6599a2dd95SBruce Richardson int ret;
6699a2dd95SBruce Richardson
67ae67895bSDavid Marchand EAL_LOG(DEBUG, "Thread catch SIGBUS, fault address:%p",
6899a2dd95SBruce Richardson info->si_addr);
6999a2dd95SBruce Richardson
7099a2dd95SBruce Richardson rte_spinlock_lock(&failure_handle_lock);
7199a2dd95SBruce Richardson ret = rte_bus_sigbus_handler(info->si_addr);
7299a2dd95SBruce Richardson rte_spinlock_unlock(&failure_handle_lock);
7399a2dd95SBruce Richardson if (ret == -1) {
7499a2dd95SBruce Richardson rte_exit(EXIT_FAILURE,
7599a2dd95SBruce Richardson "Failed to handle SIGBUS for hot-unplug, "
7699a2dd95SBruce Richardson "(rte_errno: %s)!", strerror(rte_errno));
7799a2dd95SBruce Richardson } else if (ret == 1) {
7899a2dd95SBruce Richardson if (sigbus_action_old.sa_flags == SA_SIGINFO
7999a2dd95SBruce Richardson && sigbus_action_old.sa_sigaction) {
8099a2dd95SBruce Richardson (*(sigbus_action_old.sa_sigaction))(signum,
8199a2dd95SBruce Richardson info, ctx);
8299a2dd95SBruce Richardson } else if (sigbus_action_old.sa_flags != SA_SIGINFO
8399a2dd95SBruce Richardson && sigbus_action_old.sa_handler) {
8499a2dd95SBruce Richardson (*(sigbus_action_old.sa_handler))(signum);
8599a2dd95SBruce Richardson } else {
8699a2dd95SBruce Richardson rte_exit(EXIT_FAILURE,
8799a2dd95SBruce Richardson "Failed to handle generic SIGBUS!");
8899a2dd95SBruce Richardson }
8999a2dd95SBruce Richardson }
9099a2dd95SBruce Richardson
91ae67895bSDavid Marchand EAL_LOG(DEBUG, "Success to handle SIGBUS for hot-unplug!");
9299a2dd95SBruce Richardson }
9399a2dd95SBruce Richardson
cmp_dev_name(const struct rte_device * dev,const void * _name)9499a2dd95SBruce Richardson static int cmp_dev_name(const struct rte_device *dev,
9599a2dd95SBruce Richardson const void *_name)
9699a2dd95SBruce Richardson {
9799a2dd95SBruce Richardson const char *name = _name;
9899a2dd95SBruce Richardson
9999a2dd95SBruce Richardson return strcmp(dev->name, name);
10099a2dd95SBruce Richardson }
10199a2dd95SBruce Richardson
10299a2dd95SBruce Richardson static int
dev_uev_socket_fd_create(void)10399a2dd95SBruce Richardson dev_uev_socket_fd_create(void)
10499a2dd95SBruce Richardson {
10599a2dd95SBruce Richardson struct sockaddr_nl addr;
106c2bd9367SHarman Kalra int ret, fd;
10799a2dd95SBruce Richardson
108c2bd9367SHarman Kalra fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
10999a2dd95SBruce Richardson NETLINK_KOBJECT_UEVENT);
110c2bd9367SHarman Kalra if (fd < 0) {
111ae67895bSDavid Marchand EAL_LOG(ERR, "create uevent fd failed.");
11299a2dd95SBruce Richardson return -1;
11399a2dd95SBruce Richardson }
11499a2dd95SBruce Richardson
11599a2dd95SBruce Richardson memset(&addr, 0, sizeof(addr));
11699a2dd95SBruce Richardson addr.nl_family = AF_NETLINK;
11799a2dd95SBruce Richardson addr.nl_pid = 0;
11899a2dd95SBruce Richardson addr.nl_groups = 0xffffffff;
11999a2dd95SBruce Richardson
120c2bd9367SHarman Kalra ret = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
12199a2dd95SBruce Richardson if (ret < 0) {
122ae67895bSDavid Marchand EAL_LOG(ERR, "Failed to bind uevent socket.");
12399a2dd95SBruce Richardson goto err;
12499a2dd95SBruce Richardson }
12599a2dd95SBruce Richardson
126c2bd9367SHarman Kalra if (rte_intr_fd_set(intr_handle, fd))
127c2bd9367SHarman Kalra goto err;
128c2bd9367SHarman Kalra
12999a2dd95SBruce Richardson return 0;
13099a2dd95SBruce Richardson err:
131c2bd9367SHarman Kalra close(fd);
132c2bd9367SHarman Kalra fd = -1;
13399a2dd95SBruce Richardson return ret;
13499a2dd95SBruce Richardson }
13599a2dd95SBruce Richardson
13699a2dd95SBruce Richardson struct rte_dev_event {
13799a2dd95SBruce Richardson enum rte_dev_event_type type; /**< device event type */
13899a2dd95SBruce Richardson int subsystem; /**< subsystem id */
13999a2dd95SBruce Richardson char *devname; /**< device name */
14099a2dd95SBruce Richardson };
14199a2dd95SBruce Richardson
14299a2dd95SBruce Richardson static int
dev_uev_parse(const char * buf,struct rte_dev_event * event,int length)14399a2dd95SBruce Richardson dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
14499a2dd95SBruce Richardson {
14599a2dd95SBruce Richardson char action[EAL_UEV_MSG_ELEM_LEN];
14699a2dd95SBruce Richardson char subsystem[EAL_UEV_MSG_ELEM_LEN];
14799a2dd95SBruce Richardson char pci_slot_name[EAL_UEV_MSG_ELEM_LEN];
14899a2dd95SBruce Richardson int i = 0;
14999a2dd95SBruce Richardson
15099a2dd95SBruce Richardson memset(action, 0, EAL_UEV_MSG_ELEM_LEN);
15199a2dd95SBruce Richardson memset(subsystem, 0, EAL_UEV_MSG_ELEM_LEN);
15299a2dd95SBruce Richardson memset(pci_slot_name, 0, EAL_UEV_MSG_ELEM_LEN);
15399a2dd95SBruce Richardson
15499a2dd95SBruce Richardson while (i < length) {
15599a2dd95SBruce Richardson for (; i < length; i++) {
15699a2dd95SBruce Richardson if (*buf)
15799a2dd95SBruce Richardson break;
15899a2dd95SBruce Richardson buf++;
15999a2dd95SBruce Richardson }
1604847122aSDavid Marchand if (i >= length)
1614847122aSDavid Marchand break;
1624847122aSDavid Marchand
16399a2dd95SBruce Richardson /**
16499a2dd95SBruce Richardson * check device uevent from kernel side, no need to check
16599a2dd95SBruce Richardson * uevent from udev.
16699a2dd95SBruce Richardson */
16799a2dd95SBruce Richardson if (!strncmp(buf, "libudev", 7)) {
16899a2dd95SBruce Richardson buf += 7;
16999a2dd95SBruce Richardson i += 7;
17099a2dd95SBruce Richardson return -1;
17199a2dd95SBruce Richardson }
17299a2dd95SBruce Richardson if (!strncmp(buf, "ACTION=", 7)) {
17399a2dd95SBruce Richardson buf += 7;
17499a2dd95SBruce Richardson i += 7;
17599a2dd95SBruce Richardson strlcpy(action, buf, sizeof(action));
17699a2dd95SBruce Richardson } else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
17799a2dd95SBruce Richardson buf += 10;
17899a2dd95SBruce Richardson i += 10;
17999a2dd95SBruce Richardson strlcpy(subsystem, buf, sizeof(subsystem));
18099a2dd95SBruce Richardson } else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
18199a2dd95SBruce Richardson buf += 14;
18299a2dd95SBruce Richardson i += 14;
18399a2dd95SBruce Richardson strlcpy(pci_slot_name, buf, sizeof(subsystem));
18499a2dd95SBruce Richardson event->devname = strdup(pci_slot_name);
1855821a384SChengwen Feng if (event->devname == NULL)
1865821a384SChengwen Feng return -1;
18799a2dd95SBruce Richardson }
18899a2dd95SBruce Richardson for (; i < length; i++) {
18999a2dd95SBruce Richardson if (*buf == '\0')
19099a2dd95SBruce Richardson break;
19199a2dd95SBruce Richardson buf++;
19299a2dd95SBruce Richardson }
19399a2dd95SBruce Richardson }
19499a2dd95SBruce Richardson
19599a2dd95SBruce Richardson /* parse the subsystem layer */
19699a2dd95SBruce Richardson if (!strncmp(subsystem, "uio", 3))
19799a2dd95SBruce Richardson event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_UIO;
19899a2dd95SBruce Richardson else if (!strncmp(subsystem, "pci", 3))
19999a2dd95SBruce Richardson event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_PCI;
20099a2dd95SBruce Richardson else if (!strncmp(subsystem, "vfio", 4))
20199a2dd95SBruce Richardson event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_VFIO;
20299a2dd95SBruce Richardson else
20399a2dd95SBruce Richardson goto err;
20499a2dd95SBruce Richardson
20599a2dd95SBruce Richardson /* parse the action type */
20699a2dd95SBruce Richardson if (!strncmp(action, "add", 3))
20799a2dd95SBruce Richardson event->type = RTE_DEV_EVENT_ADD;
20899a2dd95SBruce Richardson else if (!strncmp(action, "remove", 6))
20999a2dd95SBruce Richardson event->type = RTE_DEV_EVENT_REMOVE;
21099a2dd95SBruce Richardson else
21199a2dd95SBruce Richardson goto err;
21299a2dd95SBruce Richardson return 0;
21399a2dd95SBruce Richardson err:
21499a2dd95SBruce Richardson free(event->devname);
21599a2dd95SBruce Richardson return -1;
21699a2dd95SBruce Richardson }
21799a2dd95SBruce Richardson
21899a2dd95SBruce Richardson static void
dev_delayed_unregister(void * param)21999a2dd95SBruce Richardson dev_delayed_unregister(void *param)
22099a2dd95SBruce Richardson {
221c2bd9367SHarman Kalra rte_intr_callback_unregister(intr_handle, dev_uev_handler, param);
2227e2083e4SHarman Kalra if (rte_intr_fd_get(intr_handle) >= 0) {
223c2bd9367SHarman Kalra close(rte_intr_fd_get(intr_handle));
224c2bd9367SHarman Kalra rte_intr_fd_set(intr_handle, -1);
22599a2dd95SBruce Richardson }
2267e2083e4SHarman Kalra }
22799a2dd95SBruce Richardson
22899a2dd95SBruce Richardson static void
dev_uev_handler(__rte_unused void * param)22999a2dd95SBruce Richardson dev_uev_handler(__rte_unused void *param)
23099a2dd95SBruce Richardson {
23199a2dd95SBruce Richardson struct rte_dev_event uevent;
23299a2dd95SBruce Richardson int ret;
2331a287fc9SSteve Yang char buf[EAL_UEV_MSG_LEN + 1];
23499a2dd95SBruce Richardson struct rte_bus *bus;
23599a2dd95SBruce Richardson struct rte_device *dev;
23699a2dd95SBruce Richardson const char *busname = "";
23799a2dd95SBruce Richardson
23899a2dd95SBruce Richardson memset(&uevent, 0, sizeof(struct rte_dev_event));
2391a287fc9SSteve Yang memset(buf, 0, EAL_UEV_MSG_LEN + 1);
24099a2dd95SBruce Richardson
2417e2083e4SHarman Kalra if (rte_intr_fd_get(intr_handle) < 0)
2427e2083e4SHarman Kalra return;
2437e2083e4SHarman Kalra
244c2bd9367SHarman Kalra ret = recv(rte_intr_fd_get(intr_handle), buf, EAL_UEV_MSG_LEN,
245c2bd9367SHarman Kalra MSG_DONTWAIT);
24699a2dd95SBruce Richardson if (ret < 0 && errno == EAGAIN)
24799a2dd95SBruce Richardson return;
24899a2dd95SBruce Richardson else if (ret <= 0) {
24999a2dd95SBruce Richardson /* connection is closed or broken, can not up again. */
250ae67895bSDavid Marchand EAL_LOG(ERR, "uevent socket connection is broken.");
25199a2dd95SBruce Richardson rte_eal_alarm_set(1, dev_delayed_unregister, NULL);
25299a2dd95SBruce Richardson return;
25399a2dd95SBruce Richardson }
25499a2dd95SBruce Richardson
25599a2dd95SBruce Richardson ret = dev_uev_parse(buf, &uevent, EAL_UEV_MSG_LEN);
25699a2dd95SBruce Richardson if (ret < 0) {
257ae67895bSDavid Marchand EAL_LOG(DEBUG, "Ignoring uevent '%s'", buf);
25899a2dd95SBruce Richardson return;
25999a2dd95SBruce Richardson }
26099a2dd95SBruce Richardson
261ae67895bSDavid Marchand EAL_LOG(DEBUG, "receive uevent(name:%s, type:%d, subsystem:%d)",
26299a2dd95SBruce Richardson uevent.devname, uevent.type, uevent.subsystem);
26399a2dd95SBruce Richardson
26499a2dd95SBruce Richardson switch (uevent.subsystem) {
26599a2dd95SBruce Richardson case EAL_DEV_EVENT_SUBSYSTEM_PCI:
26699a2dd95SBruce Richardson case EAL_DEV_EVENT_SUBSYSTEM_UIO:
26799a2dd95SBruce Richardson busname = "pci";
26899a2dd95SBruce Richardson break;
26999a2dd95SBruce Richardson default:
27099a2dd95SBruce Richardson break;
27199a2dd95SBruce Richardson }
27299a2dd95SBruce Richardson
27399a2dd95SBruce Richardson if (uevent.devname) {
27499a2dd95SBruce Richardson if (uevent.type == RTE_DEV_EVENT_REMOVE && hotplug_handle) {
27599a2dd95SBruce Richardson rte_spinlock_lock(&failure_handle_lock);
27699a2dd95SBruce Richardson bus = rte_bus_find_by_name(busname);
27799a2dd95SBruce Richardson if (bus == NULL) {
278ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot find bus (%s)",
27999a2dd95SBruce Richardson busname);
28099a2dd95SBruce Richardson goto failure_handle_err;
28199a2dd95SBruce Richardson }
28299a2dd95SBruce Richardson
28399a2dd95SBruce Richardson dev = bus->find_device(NULL, cmp_dev_name,
28499a2dd95SBruce Richardson uevent.devname);
28599a2dd95SBruce Richardson if (dev == NULL) {
286ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot find device (%s) on "
287ae67895bSDavid Marchand "bus (%s)", uevent.devname, busname);
28899a2dd95SBruce Richardson goto failure_handle_err;
28999a2dd95SBruce Richardson }
29099a2dd95SBruce Richardson
29199a2dd95SBruce Richardson ret = bus->hot_unplug_handler(dev);
29299a2dd95SBruce Richardson if (ret) {
293ae67895bSDavid Marchand EAL_LOG(ERR, "Can not handle hot-unplug "
294ae67895bSDavid Marchand "for device (%s)", dev->name);
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson rte_spinlock_unlock(&failure_handle_lock);
29799a2dd95SBruce Richardson }
29899a2dd95SBruce Richardson rte_dev_event_callback_process(uevent.devname, uevent.type);
29999a2dd95SBruce Richardson free(uevent.devname);
30099a2dd95SBruce Richardson }
30199a2dd95SBruce Richardson
30299a2dd95SBruce Richardson return;
30399a2dd95SBruce Richardson
30499a2dd95SBruce Richardson failure_handle_err:
30599a2dd95SBruce Richardson rte_spinlock_unlock(&failure_handle_lock);
30699a2dd95SBruce Richardson free(uevent.devname);
30799a2dd95SBruce Richardson }
30899a2dd95SBruce Richardson
30999a2dd95SBruce Richardson int
rte_dev_event_monitor_start(void)31099a2dd95SBruce Richardson rte_dev_event_monitor_start(void)
31199a2dd95SBruce Richardson {
31299a2dd95SBruce Richardson int ret = 0;
31399a2dd95SBruce Richardson
31499a2dd95SBruce Richardson rte_rwlock_write_lock(&monitor_lock);
31599a2dd95SBruce Richardson
31699a2dd95SBruce Richardson if (monitor_refcount) {
31799a2dd95SBruce Richardson monitor_refcount++;
31899a2dd95SBruce Richardson goto exit;
31999a2dd95SBruce Richardson }
32099a2dd95SBruce Richardson
321c2bd9367SHarman Kalra intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
322c2bd9367SHarman Kalra if (intr_handle == NULL) {
323ae67895bSDavid Marchand EAL_LOG(ERR, "Fail to allocate intr_handle");
324c2bd9367SHarman Kalra goto exit;
325c2bd9367SHarman Kalra }
326c2bd9367SHarman Kalra
32756331733SDavid Marchand ret = rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_DEV_EVENT);
32856331733SDavid Marchand if (ret)
329c2bd9367SHarman Kalra goto exit;
330c2bd9367SHarman Kalra
33156331733SDavid Marchand ret = rte_intr_fd_set(intr_handle, -1);
33256331733SDavid Marchand if (ret)
333c2bd9367SHarman Kalra goto exit;
334c2bd9367SHarman Kalra
33599a2dd95SBruce Richardson ret = dev_uev_socket_fd_create();
33699a2dd95SBruce Richardson if (ret) {
337ae67895bSDavid Marchand EAL_LOG(ERR, "error create device event fd.");
33899a2dd95SBruce Richardson goto exit;
33999a2dd95SBruce Richardson }
34099a2dd95SBruce Richardson
341c2bd9367SHarman Kalra ret = rte_intr_callback_register(intr_handle, dev_uev_handler, NULL);
34299a2dd95SBruce Richardson
34399a2dd95SBruce Richardson if (ret) {
344c2bd9367SHarman Kalra close(rte_intr_fd_get(intr_handle));
34599a2dd95SBruce Richardson goto exit;
34699a2dd95SBruce Richardson }
34799a2dd95SBruce Richardson
34899a2dd95SBruce Richardson monitor_refcount++;
34999a2dd95SBruce Richardson
35099a2dd95SBruce Richardson exit:
35156331733SDavid Marchand if (ret) {
352c2bd9367SHarman Kalra rte_intr_instance_free(intr_handle);
35356331733SDavid Marchand intr_handle = NULL;
35456331733SDavid Marchand }
35599a2dd95SBruce Richardson rte_rwlock_write_unlock(&monitor_lock);
35699a2dd95SBruce Richardson return ret;
35799a2dd95SBruce Richardson }
35899a2dd95SBruce Richardson
35999a2dd95SBruce Richardson int
rte_dev_event_monitor_stop(void)36099a2dd95SBruce Richardson rte_dev_event_monitor_stop(void)
36199a2dd95SBruce Richardson {
36299a2dd95SBruce Richardson int ret = 0;
36399a2dd95SBruce Richardson
36499a2dd95SBruce Richardson rte_rwlock_write_lock(&monitor_lock);
36599a2dd95SBruce Richardson
36699a2dd95SBruce Richardson if (!monitor_refcount) {
367ae67895bSDavid Marchand EAL_LOG(ERR, "device event monitor already stopped");
36899a2dd95SBruce Richardson goto exit;
36999a2dd95SBruce Richardson }
37099a2dd95SBruce Richardson
37199a2dd95SBruce Richardson if (monitor_refcount > 1) {
37299a2dd95SBruce Richardson monitor_refcount--;
37399a2dd95SBruce Richardson goto exit;
37499a2dd95SBruce Richardson }
37599a2dd95SBruce Richardson
376c2bd9367SHarman Kalra ret = rte_intr_callback_unregister(intr_handle, dev_uev_handler,
37799a2dd95SBruce Richardson (void *)-1);
37899a2dd95SBruce Richardson if (ret < 0) {
379ae67895bSDavid Marchand EAL_LOG(ERR, "fail to unregister uevent callback.");
38099a2dd95SBruce Richardson goto exit;
38199a2dd95SBruce Richardson }
38299a2dd95SBruce Richardson
383c2bd9367SHarman Kalra close(rte_intr_fd_get(intr_handle));
384c2bd9367SHarman Kalra rte_intr_instance_free(intr_handle);
38556331733SDavid Marchand intr_handle = NULL;
3864e3582abSWenxuan Wu ret = 0;
38799a2dd95SBruce Richardson
38899a2dd95SBruce Richardson monitor_refcount--;
38999a2dd95SBruce Richardson
39099a2dd95SBruce Richardson exit:
39199a2dd95SBruce Richardson rte_rwlock_write_unlock(&monitor_lock);
39299a2dd95SBruce Richardson
39399a2dd95SBruce Richardson return ret;
39499a2dd95SBruce Richardson }
39599a2dd95SBruce Richardson
396*fcfb19cdSStephen Hemminger static int
dev_sigbus_handler_register(void)39799a2dd95SBruce Richardson dev_sigbus_handler_register(void)
39899a2dd95SBruce Richardson {
39999a2dd95SBruce Richardson sigset_t mask;
40099a2dd95SBruce Richardson struct sigaction action;
40199a2dd95SBruce Richardson
40299a2dd95SBruce Richardson rte_errno = 0;
40399a2dd95SBruce Richardson
40499a2dd95SBruce Richardson if (sigbus_need_recover)
40599a2dd95SBruce Richardson return 0;
40699a2dd95SBruce Richardson
40799a2dd95SBruce Richardson sigemptyset(&mask);
40899a2dd95SBruce Richardson sigaddset(&mask, SIGBUS);
40999a2dd95SBruce Richardson action.sa_flags = SA_SIGINFO;
41099a2dd95SBruce Richardson action.sa_mask = mask;
41199a2dd95SBruce Richardson action.sa_sigaction = sigbus_handler;
41299a2dd95SBruce Richardson sigbus_need_recover = !sigaction(SIGBUS, &action, &sigbus_action_old);
41399a2dd95SBruce Richardson
41499a2dd95SBruce Richardson return rte_errno;
41599a2dd95SBruce Richardson }
41699a2dd95SBruce Richardson
417*fcfb19cdSStephen Hemminger static int
dev_sigbus_handler_unregister(void)41899a2dd95SBruce Richardson dev_sigbus_handler_unregister(void)
41999a2dd95SBruce Richardson {
42099a2dd95SBruce Richardson rte_errno = 0;
42199a2dd95SBruce Richardson
42299a2dd95SBruce Richardson sigbus_action_recover();
42399a2dd95SBruce Richardson
42499a2dd95SBruce Richardson return rte_errno;
42599a2dd95SBruce Richardson }
42699a2dd95SBruce Richardson
42799a2dd95SBruce Richardson int
rte_dev_hotplug_handle_enable(void)42899a2dd95SBruce Richardson rte_dev_hotplug_handle_enable(void)
42999a2dd95SBruce Richardson {
43099a2dd95SBruce Richardson int ret = 0;
43199a2dd95SBruce Richardson
43299a2dd95SBruce Richardson ret = dev_sigbus_handler_register();
43399a2dd95SBruce Richardson if (ret < 0)
434ae67895bSDavid Marchand EAL_LOG(ERR,
435ae67895bSDavid Marchand "fail to register sigbus handler for devices.");
43699a2dd95SBruce Richardson
43799a2dd95SBruce Richardson hotplug_handle = true;
43899a2dd95SBruce Richardson
43999a2dd95SBruce Richardson return ret;
44099a2dd95SBruce Richardson }
44199a2dd95SBruce Richardson
44299a2dd95SBruce Richardson int
rte_dev_hotplug_handle_disable(void)44399a2dd95SBruce Richardson rte_dev_hotplug_handle_disable(void)
44499a2dd95SBruce Richardson {
44599a2dd95SBruce Richardson int ret = 0;
44699a2dd95SBruce Richardson
44799a2dd95SBruce Richardson ret = dev_sigbus_handler_unregister();
44899a2dd95SBruce Richardson if (ret < 0)
449ae67895bSDavid Marchand EAL_LOG(ERR,
450ae67895bSDavid Marchand "fail to unregister sigbus handler for devices.");
45199a2dd95SBruce Richardson
45299a2dd95SBruce Richardson hotplug_handle = false;
45399a2dd95SBruce Richardson
45499a2dd95SBruce Richardson return ret;
45599a2dd95SBruce Richardson }
456