get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/28310/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 28310,
    "url": "https://patches.dpdk.org/api/patches/28310/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1504453785-15735-2-git-send-email-jia.guo@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1504453785-15735-2-git-send-email-jia.guo@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1504453785-15735-2-git-send-email-jia.guo@intel.com",
    "date": "2017-09-03T15:49:44",
    "name": "[dpdk-dev,v4,1/2] eal: add uevent monitor for hot plug",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "007c54457a6f986ecfc0867b836785ef3827bab4",
    "submitter": {
        "id": 507,
        "url": "https://patches.dpdk.org/api/people/507/?format=api",
        "name": "Guo, Jia",
        "email": "jia.guo@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1504453785-15735-2-git-send-email-jia.guo@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/28310/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/28310/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 1D6397CCA;\n\tSun,  3 Sep 2017 17:49:09 +0200 (CEST)",
            "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby dpdk.org (Postfix) with ESMTP id 981087CB5\n\tfor <dev@dpdk.org>; Sun,  3 Sep 2017 17:49:06 +0200 (CEST)",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t03 Sep 2017 08:49:06 -0700",
            "from jeffguo-s2600wt2.sh.intel.com (HELO localhost.localdomain)\n\t([10.67.110.10])\n\tby fmsmga004.fm.intel.com with ESMTP; 03 Sep 2017 08:49:03 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.41,469,1498546800\"; d=\"scan'208\";a=\"307495746\"",
        "From": "Jeff Guo <jia.guo@intel.com>",
        "To": "stephen@networkplumber.org,\n\tbruce.richardson@intel.com",
        "Cc": "dev@dpdk.org, gaetan.rivet@6wind.com, shreyansh.jain@nxp.com,\n\tjblunck@infradead.org, helin.zhang@intel.com, ferruh.yigit@intel.com, \n\tkonstantin.ananyev@intel.com, thomas@monjalon.net,\n\tjingjing.wu@intel.com, jia.guo@intel.com",
        "Date": "Sun,  3 Sep 2017 23:49:44 +0800",
        "Message-Id": "<1504453785-15735-2-git-send-email-jia.guo@intel.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1504453785-15735-1-git-send-email-jia.guo@intel.com>",
        "References": "<1498712510-44217-2-git-send-email-jia.guo@intel.com>\n\t<1504453785-15735-1-git-send-email-jia.guo@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 1/2] eal: add uevent monitor for hot plug",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch aim to add a general uevent mechanism in eal device layer,\nto enable all kernel object hot plug monitoring, so user could use these\nAPI to monitor and read out the device status info sent from the kernel\nside, then corresponding to handle it, such as detach or attach the\ndevice, and even benefit to use it for do smoothly fail safe work.\n\n1) About uevent monitoring:\na: add uevent_fd in struct rte_intr_handle, and use eal interrupt\n   epolling to monitoring the netlink of uevent_fd.\nb: add enum of rte_eal_uevent_type and struct of rte_eal_uevent.\nc: add below API in rte eal device layer.\n   rte_eal_uev_fd_new\n   rte_eal_uev_enable\n   rte_eal_uev_receive\n   rte_eal_uev_callback_register\n   rte_eal_uev_callback_unregister\n\n2) About uevent handler and failure handler, use pci uio for example,\nadd below API to process it:\n   pci_uio_uev_handler\n   pci_uio_remap_resource\n   pci_map_private_resource\n\nSigned-off-by: Jeff Guo <jia.guo@intel.com>\n---\nv4->v3:\nmove uevent monitor api from eal interrupt to eal device layer.\ncreate uevent type and struct in eal device.\nmove uevent handler for each driver to eal layer.\nadd uevent failure handler to process signal fault issue.\nadd example for request and use uevent monitoring in testpmd.\n---\n lib/librte_eal/common/eal_common_dev.c             | 248 ++++++++++++++++++++-\n lib/librte_eal/common/eal_common_pci.c             |  20 ++\n lib/librte_eal/common/eal_private.h                |  14 ++\n lib/librte_eal/common/include/rte_dev.h            | 136 +++++++++++\n lib/librte_eal/common/include/rte_pci.h            |  17 ++\n lib/librte_eal/linuxapp/eal/eal_interrupts.c       |  28 ++-\n lib/librte_eal/linuxapp/eal/eal_pci_init.h         |   4 +\n lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  62 ++++++\n .../linuxapp/eal/include/exec-env/rte_interrupts.h |   2 +-\n 9 files changed, 524 insertions(+), 7 deletions(-)",
    "diff": "diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c\nindex f98302d..ae8f673 100644\n--- a/lib/librte_eal/common/eal_common_dev.c\n+++ b/lib/librte_eal/common/eal_common_dev.c\n@@ -36,15 +36,41 @@\n #include <string.h>\n #include <inttypes.h>\n #include <sys/queue.h>\n-\n+#include <sys/signalfd.h>\n+#include <sys/ioctl.h>\n+#include <sys/socket.h>\n+#include <linux/netlink.h>\n+#include <sys/epoll.h>\n+#include <unistd.h>\n+\n+#include <rte_malloc.h>\n #include <rte_bus.h>\n #include <rte_dev.h>\n #include <rte_devargs.h>\n #include <rte_debug.h>\n #include <rte_log.h>\n+#include <rte_spinlock.h>\n \n #include \"eal_private.h\"\n \n+/* spinlock for uevent callbacks */\n+static rte_spinlock_t rte_eal_uev_cb_lock = RTE_SPINLOCK_INITIALIZER;\n+\n+/**\n+ * The user application callback description.\n+ *\n+ * It contains callback address to be registered by user application,\n+ * the pointer to the parameters for callback, and the event type.\n+ */\n+struct rte_eal_uev_callback {\n+\tTAILQ_ENTRY(rte_eal_uev_callback) next; /**< Callbacks list */\n+\trte_eal_uev_cb_fn cb_fn;                /**< Callback address */\n+\tvoid *cb_arg;                           /**< Parameter for callback */\n+\tvoid *ret_param;                        /**< Return parameter */\n+\tenum rte_eal_uevent_type event;          /**< Interrupt event type */\n+\tuint32_t active;                        /**< Callback is executing */\n+};\n+\n static int cmp_detached_dev_name(const struct rte_device *dev,\n \tconst void *_name)\n {\n@@ -244,3 +270,223 @@ int rte_eal_hotplug_remove(const char *busname, const char *devname)\n \trte_eal_devargs_remove(busname, devname);\n \treturn ret;\n }\n+\n+int\n+rte_eal_uev_fd_new(void)\n+{\n+\n+\tint netlink_fd = -1;\n+\n+\tnetlink_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);\n+\tif (netlink_fd < 0)\n+\t\treturn -1;\n+\n+\treturn netlink_fd;\n+}\n+\n+int\n+rte_eal_uev_enable(int netlink_fd)\n+{\n+\tstruct sockaddr_nl addr;\n+\tint ret;\n+\tint size = 64 * 1024;\n+\tint nonblock = 1;\n+\tmemset(&addr, 0, sizeof(addr));\n+\taddr.nl_family = AF_NETLINK;\n+\taddr.nl_pid = 0;\n+\taddr.nl_groups = 0xffffffff;\n+\n+\tsetsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));\n+\n+\tret = ioctl(netlink_fd, FIONBIO, &nonblock);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(ERR, EAL,\n+\t\t\"ioctl(FIONBIO) failed\\n\");\n+\t\tclose(netlink_fd);\n+\t\treturn -1;\n+\t}\n+\n+\tif (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {\n+\t\tclose(netlink_fd);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+rte_eal_uev_parse(const char *buf, struct rte_eal_uevent *event)\n+{\n+\tchar action[RTE_EAL_UEVENT_MSG_LEN];\n+\tchar subsystem[RTE_EAL_UEVENT_MSG_LEN];\n+\tchar dev_path[RTE_EAL_UEVENT_MSG_LEN];\n+\tint i = 0;\n+\n+\tmemset(action, 0, RTE_EAL_UEVENT_MSG_LEN);\n+\tmemset(subsystem, 0, RTE_EAL_UEVENT_MSG_LEN);\n+\tmemset(dev_path, 0, RTE_EAL_UEVENT_MSG_LEN);\n+\n+\twhile (i < RTE_EAL_UEVENT_MSG_LEN) {\n+\t\tfor (; i < RTE_EAL_UEVENT_MSG_LEN; i++) {\n+\t\t\tif (*buf)\n+\t\t\t\tbreak;\n+\t\t\tbuf++;\n+\t\t}\n+\t\tif (!strncmp(buf, \"ACTION=\", 7)) {\n+\t\t\tbuf += 7;\n+\t\t\ti += 7;\n+\t\t\tsnprintf(action, sizeof(action), \"%s\", buf);\n+\t\t} else if (!strncmp(buf, \"DEVPATH=\", 8)) {\n+\t\t\tbuf += 8;\n+\t\t\ti += 8;\n+\t\t\tsnprintf(dev_path, sizeof(dev_path), \"%s\", buf);\n+\t\t} else if (!strncmp(buf, \"SUBSYSTEM=\", 10)) {\n+\t\t\tbuf += 10;\n+\t\t\ti += 10;\n+\t\t\tsnprintf(subsystem, sizeof(subsystem), \"%s\", buf);\n+\t\t}\n+\t\tfor (; i < RTE_EAL_UEVENT_MSG_LEN; i++) {\n+\t\t\tif (*buf == '\\0')\n+\t\t\t\tbreak;\n+\t\t\tbuf++;\n+\t\t}\n+\t}\n+\n+\tif ((!strncmp(subsystem, \"uio\", 3)) ||\n+\t\t(!strncmp(subsystem, \"pci\", 3))) {\n+\t\tevent->subsystem = RTE_EAL_UEVENT_SUBSYSTEM_UIO;\n+\t\tif (!strncmp(action, \"add\", 3))\n+\t\t\tevent->type = RTE_EAL_UEVENT_ADD;\n+\t\tif (!strncmp(action, \"remove\", 6))\n+\t\t\tevent->type = RTE_EAL_UEVENT_REMOVE;\n+\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+int\n+rte_eal_uev_receive(int fd, struct rte_eal_uevent *uevent)\n+{\n+\tint ret;\n+\tchar buf[RTE_EAL_UEVENT_MSG_LEN];\n+\n+\tmemset(uevent, 0, sizeof(struct rte_eal_uevent));\n+\tmemset(buf, 0, RTE_EAL_UEVENT_MSG_LEN);\n+\n+\tret = recv(fd, buf, RTE_EAL_UEVENT_MSG_LEN - 1, MSG_DONTWAIT);\n+\tif (ret > 0)\n+\t\treturn rte_eal_uev_parse(buf, uevent);\n+\telse if (ret < 0) {\n+\t\tRTE_LOG(ERR, EAL,\n+\t\t\"Socket read error(%d): %s\\n\",\n+\t\terrno, strerror(errno));\n+\t\treturn -1;\n+\t} else\n+\t\t/* connection closed */\n+\t\treturn -1;\n+}\n+\n+int\n+rte_eal_uev_callback_register(struct rte_device *dev,\n+\t\t\tenum rte_eal_uevent_type event,\n+\t\t\trte_eal_uev_cb_fn cb_fn, void *cb_arg)\n+{\n+\tstruct rte_eal_uev_callback *user_cb;\n+\n+\tif (!cb_fn)\n+\t\treturn -EINVAL;\n+\n+\trte_spinlock_lock(&rte_eal_uev_cb_lock);\n+\n+\tTAILQ_FOREACH(user_cb, &(dev->uev_cbs), next) {\n+\t\tif (user_cb->cb_fn == cb_fn &&\n+\t\t\tuser_cb->cb_arg == cb_arg &&\n+\t\t\tuser_cb->event == event) {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* create a new callback. */\n+\tif (user_cb == NULL) {\n+\t\tuser_cb = rte_zmalloc(\"EAL_UEV_CALLBACK\",\n+\t\t\t\t\tsizeof(struct rte_eal_uev_callback), 0);\n+\t\tif (user_cb != NULL) {\n+\t\t\tuser_cb->cb_fn = cb_fn;\n+\t\t\tuser_cb->cb_arg = cb_arg;\n+\t\t\tuser_cb->event = event;\n+\t\t\tTAILQ_INSERT_TAIL(&(dev->uev_cbs), user_cb, next);\n+\t\t}\n+\t}\n+\n+\trte_spinlock_unlock(&rte_eal_uev_cb_lock);\n+\treturn (user_cb == NULL) ? -ENOMEM : 0;\n+}\n+\n+int\n+rte_eal_uev_callback_unregister(struct rte_device *dev,\n+\t\t\tenum rte_eal_uevent_type event,\n+\t\t\trte_eal_uev_cb_fn cb_fn, void *cb_arg)\n+{\n+\tint ret;\n+\tstruct rte_eal_uev_callback *cb, *next;\n+\n+\tif (!cb_fn)\n+\t\treturn -EINVAL;\n+\n+\trte_spinlock_lock(&rte_eal_uev_cb_lock);\n+\n+\tret = 0;\n+\tfor (cb = TAILQ_FIRST(&dev->uev_cbs); cb != NULL; cb = next) {\n+\n+\t\tnext = TAILQ_NEXT(cb, next);\n+\n+\t\tif (cb->cb_fn != cb_fn || cb->event != event ||\n+\t\t\t\t(cb->cb_arg != (void *)-1 &&\n+\t\t\t\tcb->cb_arg != cb_arg))\n+\t\t\tcontinue;\n+\n+\t\t/*\n+\t\t * if this callback is not executing right now,\n+\t\t * then remove it.\n+\t\t */\n+\t\tif (cb->active == 0) {\n+\t\t\tTAILQ_REMOVE(&(dev->uev_cbs), cb, next);\n+\t\t\trte_free(cb);\n+\t\t} else {\n+\t\t\tret = -EAGAIN;\n+\t\t}\n+\t}\n+\n+\trte_spinlock_unlock(&rte_eal_uev_cb_lock);\n+\treturn ret;\n+}\n+\n+int\n+_rte_eal_uev_callback_process(struct rte_device *dev,\n+\tenum rte_eal_uevent_type event, void *cb_arg, void *ret_param)\n+{\n+\tstruct rte_eal_uev_callback *cb_lst;\n+\tstruct rte_eal_uev_callback dev_cb;\n+\tint rc = 0;\n+\n+\trte_spinlock_lock(&rte_eal_uev_cb_lock);\n+\tTAILQ_FOREACH(cb_lst, &(dev->uev_cbs), next) {\n+\t\tif (cb_lst->cb_fn == NULL || cb_lst->event != event)\n+\t\t\tcontinue;\n+\t\tdev_cb = *cb_lst;\n+\t\tcb_lst->active = 1;\n+\t\tif (cb_arg != NULL)\n+\t\t\tdev_cb.cb_arg = cb_arg;\n+\t\tif (ret_param != NULL)\n+\t\t\tdev_cb.ret_param = ret_param;\n+\n+\t\trte_spinlock_unlock(&rte_eal_uev_cb_lock);\n+\t\trc = dev_cb.cb_fn(dev, dev_cb.event,\n+\t\t\t\tdev_cb.cb_arg, dev_cb.ret_param);\n+\t\trte_spinlock_lock(&rte_eal_uev_cb_lock);\n+\t\tcb_lst->active = 0;\n+\t}\n+\trte_spinlock_unlock(&rte_eal_uev_cb_lock);\n+\treturn rc;\n+}\ndiff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c\nindex 52fd38c..0d640bc 100644\n--- a/lib/librte_eal/common/eal_common_pci.c\n+++ b/lib/librte_eal/common/eal_common_pci.c\n@@ -110,6 +110,26 @@ pci_name_set(struct rte_pci_device *dev)\n \t\tdev->device.name = dev->name;\n }\n \n+/* map a private resource from an address*/\n+void *\n+pci_map_private_resource(void *requested_addr, off_t offset, size_t size)\n+{\n+\tvoid *mapaddr;\n+\n+\tmapaddr = mmap(requested_addr, size,\n+\t\t\t   PROT_READ | PROT_WRITE,\n+\t\t\t   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);\n+\tif (mapaddr == MAP_FAILED) {\n+\t\tRTE_LOG(ERR, EAL, \"%s(): cannot mmap(%p, 0x%lx, 0x%lx): %s (%p)\\n\",\n+\t\t\t__func__, requested_addr,\n+\t\t\t(unsigned long)size, (unsigned long)offset,\n+\t\t\tstrerror(errno), mapaddr);\n+\t} else\n+\t\tRTE_LOG(DEBUG, EAL, \"  PCI memory mapped at %p\\n\", mapaddr);\n+\n+\treturn mapaddr;\n+}\n+\n /* map a particular resource from a file */\n void *\n pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,\ndiff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h\nindex 597d82e..8f5e283 100644\n--- a/lib/librte_eal/common/eal_private.h\n+++ b/lib/librte_eal/common/eal_private.h\n@@ -192,6 +192,8 @@ int pci_uio_map_resource(struct rte_pci_device *dev);\n  */\n void pci_uio_unmap_resource(struct rte_pci_device *dev);\n \n+void pci_uio_uev_handler(void *parm);\n+\n /**\n  * Allocate uio resource for PCI device\n  *\n@@ -222,6 +224,18 @@ void pci_uio_free_resource(struct rte_pci_device *dev,\n \t\tstruct mapped_pci_resource *uio_res);\n \n /**\n+ * remap the pci uio resource..\n+ *\n+ * @param dev\n+ *   Point to the struct rte pci device.\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int\n+pci_uio_remap_resource(struct rte_pci_device *dev);\n+\n+/**\n  * Map device memory to uio resource\n  *\n  * This function is private to EAL.\ndiff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h\nindex 5386d3a..656023e 100644\n--- a/lib/librte_eal/common/include/rte_dev.h\n+++ b/lib/librte_eal/common/include/rte_dev.h\n@@ -52,6 +52,13 @@ extern \"C\" {\n #include <rte_config.h>\n #include <rte_log.h>\n \n+struct rte_device;\n+\n+struct rte_eal_uev_callback;\n+/** @internal Structure to keep track of registered callbacks */\n+TAILQ_HEAD(rte_eal_uev_cb_list, rte_eal_uev_callback);\n+\n+\n __attribute__((format(printf, 2, 0)))\n static inline void\n rte_pmd_debug_trace(const char *func_name, const char *fmt, ...)\n@@ -163,6 +170,8 @@ struct rte_device {\n \tconst struct rte_driver *driver;/**< Associated driver */\n \tint numa_node;                /**< NUMA node connection */\n \tstruct rte_devargs *devargs;  /**< Device user arguments */\n+\t/** User application callbacks for device uevent monitoring  */\n+\tstruct rte_eal_uev_cb_list uev_cbs;\n };\n \n /**\n@@ -246,6 +255,133 @@ int rte_eal_hotplug_add(const char *busname, const char *devname,\n  */\n int rte_eal_hotplug_remove(const char *busname, const char *devname);\n \n+#define RTE_EAL_UEVENT_MSG_LEN 4096\n+#define RTE_EAL_UEVENT_SUBSYSTEM_UIO 1\n+#define RTE_EAL_UEVENT_SUBSYSTEM_VFIO 2\n+\n+/**\n+ * The eth device event type for interrupt, and maybe others in the future.\n+ */\n+enum rte_eal_uevent_type {\n+\tRTE_EAL_UEVENT_UNKNOWN,  /**< unknown event type */\n+\tRTE_EAL_UEVENT_ADD, /**< lsc interrupt event */\n+\tRTE_EAL_UEVENT_REMOVE,\n+\t\t\t\t/**< queue state event (enabled/disabled) */\n+\tRTE_EAL_UEVENT_CHANGE,\n+\t\t\t/**< reset interrupt event, sent to VF on PF reset */\n+\tRTE_EAL_UEVENT_MOVE,  /**< message from the VF received by PF */\n+\tRTE_EAL_UEVENT_ONLINE,   /**< MACsec offload related event */\n+\tRTE_EAL_UEVENT_OFFLINE, /**< device removal event */\n+\tRTE_EAL_UEVENT_MAX       /**< max value of this enum */\n+};\n+\n+struct rte_eal_uevent {\n+\tenum rte_eal_uevent_type type;\t/**< uevent action type */\n+\tint subsystem;\t\t\t\t/**< subsystem id */\n+};\n+\n+/**\n+ * create  the device uevent file descriptor.\n+ * @return\n+ *   - On success, the device uevent fd.\n+ *   - On failure, a negative value.\n+ */\n+int\n+rte_eal_uev_fd_new(void);\n+\n+/**\n+ * Bind  the netlink to enable  uevent receiving.\n+ *\n+ * @param fd\n+ *   The fd which the uevent associated to\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int\n+rte_eal_uev_enable(int fd);\n+\n+/**\n+ * It read out the uevent from the specific file descriptor.\n+ *\n+ * @param fd\n+ *   The fd which the uevent associated to\n+ * @param uevent\n+ *   Pointer to the uevent which read from the monitoring fd.\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int\n+rte_eal_uev_receive(int fd, struct rte_eal_uevent *uevent);\n+\n+typedef int (*rte_eal_uev_cb_fn)(struct rte_device *dev,\n+\t\tenum rte_eal_uevent_type event, void *cb_arg, void *ret_param);\n+/**< user application callback to be registered for interrupts */\n+\n+/**\n+ * Register a callback function for specific device..\n+ *\n+ * @param dev\n+ *  Pointer to struct rte_device.\n+ * @param event\n+ *  Uevent interested.\n+ * @param cb_fn\n+ *  User supplied callback function to be called.\n+ * @param cb_arg\n+ *  Pointer to the parameters for the registered callback.\n+ *\n+ * @return\n+ *  - On success, zero.\n+ *  - On failure, a negative value.\n+ */\n+int rte_eal_uev_callback_register(struct rte_device *dev,\n+\t\t\tenum rte_eal_uevent_type event,\n+\t\t\trte_eal_uev_cb_fn cb_fn, void *cb_arg);\n+\n+/**\n+ * Unregister a callback function for specific device.\n+ *\n+ * @param device\n+ *  Pointer to struct rte_device.\n+ * @param event\n+ *  Uevent interested.\n+ * @param cb_fn\n+ *  User supplied callback function to be called.\n+ * @param cb_arg\n+ *  Pointer to the parameters for the registered callback. -1 means to\n+ *  remove all for the same callback address and same event.\n+ *\n+ * @return\n+ *  - On success, zero.\n+ *  - On failure, a negative value.\n+ */\n+int rte_eal_uev_callback_unregister(struct rte_device *dev,\n+\t\t\tenum rte_eal_uevent_type event,\n+\t\trte_eal_uev_cb_fn cb_fn, void *cb_arg);\n+\n+/**\n+ * @internal Executes all the user application registered callbacks for\n+ * the specific device. It is for DPDK internal user only. User\n+ * application should not call it directly.\n+ *\n+ * @param dev\n+ *  Pointer to struct rte_device.\n+ * @param event\n+ *  rte device uevent type.\n+ * @param cb_arg\n+ *  callback parameter.\n+ * @param ret_param\n+ *  To pass data back to user application.\n+ *  This allows the user application to decide if a particular function\n+ *  is permitted or not.\n+ *\n+ * @return\n+ *  int\n+ */\n+int _rte_eal_uev_callback_process(struct rte_device *dev,\n+\t\tenum rte_eal_uevent_type event, void *cb_arg, void *ret_param);\n+\n /**\n  * Device comparison function.\n  *\ndiff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h\nindex 8b12339..d3ced27 100644\n--- a/lib/librte_eal/common/include/rte_pci.h\n+++ b/lib/librte_eal/common/include/rte_pci.h\n@@ -394,6 +394,23 @@ void rte_pci_unmap_device(struct rte_pci_device *dev);\n \n /**\n  * @internal\n+ * Map to a particular private resource.\n+ *\n+ * @param requested_addr\n+ *      The starting address for the new mapping range.\n+ * @param offset\n+ *      The offset for the mapping range.\n+ * @param size\n+ *      The size for the mapping range.\n+ * @return\n+ *   - On success, the function returns a pointer to the mapped area.\n+ *   - On error, the value MAP_FAILED is returned.\n+ */\n+void *pci_map_private_resource(void *requested_addr, off_t offset,\n+\t\tsize_t size);\n+\n+/**\n+ * @internal\n  * Map a particular resource from a file.\n  *\n  * @param requested_addr\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c\nindex 3e9ac41..06cbdab 100644\n--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c\n+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c\n@@ -670,11 +670,16 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds)\n \t\t\tRTE_SET_USED(r);\n \t\t\treturn -1;\n \t\t}\n+\n \t\trte_spinlock_lock(&intr_lock);\n-\t\tTAILQ_FOREACH(src, &intr_sources, next)\n+\t\tTAILQ_FOREACH(src, &intr_sources, next) {\n \t\t\tif (src->intr_handle.fd ==\n \t\t\t\t\tevents[n].data.fd)\n \t\t\t\tbreak;\n+\t\t\telse if (src->intr_handle.uevent_fd ==\n+\t\t\t\t\tevents[n].data.fd)\n+\t\t\t\tbreak;\n+\t\t}\n \t\tif (src == NULL){\n \t\t\trte_spinlock_unlock(&intr_lock);\n \t\t\tcontinue;\n@@ -736,17 +741,13 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds)\n \t\trte_spinlock_lock(&intr_lock);\n \n \t\tif (call) {\n-\n \t\t\t/* Finally, call all callbacks. */\n \t\t\tTAILQ_FOREACH(cb, &src->callbacks, next) {\n-\n \t\t\t\t/* make a copy and unlock. */\n \t\t\t\tactive_cb = *cb;\n \t\t\t\trte_spinlock_unlock(&intr_lock);\n-\n \t\t\t\t/* call the actual callback */\n \t\t\t\tactive_cb.cb_fn(active_cb.cb_arg);\n-\n \t\t\t\t/*get the lock back. */\n \t\t\t\trte_spinlock_lock(&intr_lock);\n \t\t\t}\n@@ -859,7 +860,24 @@ eal_intr_thread_main(__rte_unused void *arg)\n \t\t\t}\n \t\t\telse\n \t\t\t\tnumfds++;\n+\n+\t\t\t/**\n+\t\t\t * add device uevent file descriptor\n+\t\t\t * into wait list for uevent monitoring.\n+\t\t\t */\n+\t\t\tev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;\n+\t\t\tev.data.fd = src->intr_handle.uevent_fd;\n+\t\t\tif (epoll_ctl(pfd, EPOLL_CTL_ADD,\n+\t\t\t\t\tsrc->intr_handle.uevent_fd, &ev) < 0){\n+\t\t\t\trte_panic(\"Error adding uevent_fd %d epoll_ctl\"\n+\t\t\t\t\t\", %s\\n\",\n+\t\t\t\t\tsrc->intr_handle.uevent_fd,\n+\t\t\t\t\tstrerror(errno));\n+\t\t\t} else\n+\t\t\t\tnumfds++;\n \t\t}\n+\n+\n \t\trte_spinlock_unlock(&intr_lock);\n \t\t/* serve the interrupt */\n \t\teal_intr_handle_interrupts(pfd, numfds);\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h\nindex ae2980d..2f040b4 100644\n--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h\n+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h\n@@ -52,10 +52,14 @@ void *pci_find_max_end_va(void);\n int pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr,\n \tuint64_t *end_addr, uint64_t *flags);\n \n+void pci_uio_uev_handler(void *param);\n int pci_uio_alloc_resource(struct rte_pci_device *dev,\n \t\tstruct mapped_pci_resource **uio_res);\n void pci_uio_free_resource(struct rte_pci_device *dev,\n \t\tstruct mapped_pci_resource *uio_res);\n+\n+int pci_uio_remap_resource(struct rte_pci_device *dev);\n+\n int pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,\n \t\tstruct mapped_pci_resource *uio_res, int map_idx);\n \ndiff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c\nindex fa10329..c85eb6c 100644\n--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c\n+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c\n@@ -231,6 +231,10 @@ pci_uio_free_resource(struct rte_pci_device *dev,\n \t\tclose(dev->intr_handle.uio_cfg_fd);\n \t\tdev->intr_handle.uio_cfg_fd = -1;\n \t}\n+\tif (dev->intr_handle.uevent_fd >= 0) {\n+\t\tclose(dev->intr_handle.uevent_fd);\n+\t\tdev->intr_handle.uevent_fd = -1;\n+\t}\n \tif (dev->intr_handle.fd >= 0) {\n \t\tclose(dev->intr_handle.fd);\n \t\tdev->intr_handle.fd = -1;\n@@ -239,6 +243,53 @@ pci_uio_free_resource(struct rte_pci_device *dev,\n }\n \n int\n+pci_uio_remap_resource(struct rte_pci_device *dev)\n+{\n+\tint i;\n+\tuint64_t phaddr;\n+\tvoid *map_address;\n+\n+\t\t/* Map all BARs */\n+\t\tfor (i = 0; i != PCI_MAX_RESOURCE; i++) {\n+\t\t\t/* skip empty BAR */\n+\t\t\tphaddr = dev->mem_resource[i].phys_addr;\n+\t\t\tif (phaddr == 0)\n+\t\t\t\tcontinue;\n+\t\t\tmap_address = pci_map_private_resource(dev->mem_resource[i].addr, 0,\n+\t\t\t\t\t(size_t)dev->mem_resource[i].len);\n+\t\t\tif (map_address == MAP_FAILED)\n+\t\t\t\tgoto error;\n+\t\t\tmemset(map_address, 0xFF, (size_t)dev->mem_resource[i].len);\n+\t\t\tdev->mem_resource[i].addr = map_address;\n+\t\t}\n+\n+\treturn 0;\n+error:\n+\treturn -1;\n+}\n+\n+void\n+pci_uio_uev_handler(void *param)\n+{\n+\n+\tstruct rte_pci_device *dev = (struct rte_pci_device *)param;\n+\tstruct rte_eal_uevent event;\n+\tint ret;\n+\n+\t/* check device uevent */\n+\tif (rte_eal_uev_receive(dev->intr_handle.uevent_fd, &event) == 0) {\n+\t\tif (event.subsystem == RTE_EAL_UEVENT_SUBSYSTEM_UIO) {\n+\t\t\tif (event.type == RTE_EAL_UEVENT_REMOVE) {\n+\t\t\t\t/*remap the resource to be fake before removal processing */\n+\t\t\t\tret = pci_uio_remap_resource(dev);\n+\t\t\t\tif (!ret)\n+\t\t\t\t\t_rte_eal_uev_callback_process(&dev->device, RTE_EAL_UEVENT_REMOVE, NULL, NULL);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+int\n pci_uio_alloc_resource(struct rte_pci_device *dev,\n \t\tstruct mapped_pci_resource **uio_res)\n {\n@@ -246,6 +297,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,\n \tchar cfgname[PATH_MAX];\n \tchar devname[PATH_MAX]; /* contains the /dev/uioX */\n \tint uio_num;\n+\tstruct rte_intr_handle *intr_handle;\n \tstruct rte_pci_addr *loc;\n \n \tloc = &dev->addr;\n@@ -276,6 +328,16 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,\n \t\tgoto error;\n \t}\n \n+\tdev->intr_handle.uevent_fd = rte_eal_uev_fd_new();\n+\tintr_handle = &dev->intr_handle;\n+\n+\trte_eal_uev_enable(intr_handle->uevent_fd);\n+\tTAILQ_INIT(&(dev->device.uev_cbs));\n+\n+\t/* register callback func to eal lib */\n+\trte_intr_callback_register(intr_handle,\n+\t\t\t\t   pci_uio_uev_handler, dev);\n+\n \tif (dev->kdrv == RTE_KDRV_IGB_UIO)\n \t\tdev->intr_handle.type = RTE_INTR_HANDLE_UIO;\n \telse {\ndiff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h\nindex 6daffeb..8c7fce4 100644\n--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h\n+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h\n@@ -90,6 +90,7 @@ struct rte_intr_handle {\n \t\t\t\t\tfor uio_pci_generic */\n \t};\n \tint fd;\t /**< interrupt event file descriptor */\n+\tint uevent_fd;\t /**< uevent file descriptor */\n \tenum rte_intr_handle_type type;  /**< handle type */\n \tuint32_t max_intr;             /**< max interrupt requested */\n \tuint32_t nb_efd;               /**< number of available efd(event fd) */\n@@ -235,5 +236,4 @@ rte_intr_allow_others(struct rte_intr_handle *intr_handle);\n  */\n int\n rte_intr_cap_multiple(struct rte_intr_handle *intr_handle);\n-\n #endif /* _RTE_LINUXAPP_INTERRUPTS_H_ */\n",
    "prefixes": [
        "dpdk-dev",
        "v4",
        "1/2"
    ]
}