net/failsafe: register slaves Rx interrupts
authorMoti Haimovsky <motih@mellanox.com>
Thu, 25 Jan 2018 16:19:31 +0000 (18:19 +0200)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 29 Jan 2018 09:04:28 +0000 (10:04 +0100)
This commit adds the following functionality to failsafe PMD:
* Register and unregister slaves Rx interrupts.
* Enable and Disable slaves Rx interrupts.
The interrupts events generated by the slaves are not handled in this
commit.

Signed-off-by: Moti Haimovsky <motih@mellanox.com>
Acked-by: Gaetan Rivet <gaetan.rivet@6wind.com>
drivers/net/failsafe/Makefile
drivers/net/failsafe/failsafe_ether.c
drivers/net/failsafe/failsafe_intr.c
drivers/net/failsafe/failsafe_ops.c
drivers/net/failsafe/failsafe_private.h

index 98a0526..d1ae899 100644 (file)
@@ -47,6 +47,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_ether.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe_intr.c
+ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
+CFLAGS += -DLINUX
+else
+CFLAGS += -DBSD
+endif
 
 # No exported include files
 
index 8a4cacf..0f1630e 100644 (file)
@@ -283,6 +283,7 @@ fs_dev_remove(struct sub_device *sdev)
                return;
        switch (sdev->state) {
        case DEV_STARTED:
+               failsafe_rx_intr_uninstall_subdevice(sdev);
                rte_eth_dev_stop(PORT_ID(sdev));
                sdev->state = DEV_ACTIVE;
                /* fallthrough */
index 8829ca4..b0eacdc 100644 (file)
  * Interrupts handling for failsafe driver.
  */
 
+#if defined(LINUX)
+#include <sys/epoll.h>
+#endif
 #include <unistd.h>
 
 #include "failsafe_private.h"
 
+#define NUM_RX_PROXIES (FAILSAFE_MAX_ETHPORTS * RTE_MAX_RXTX_INTR_VEC_ID)
+
+
+/**
+ * Open an epoll file descriptor.
+ *
+ * @param flags
+ *   Flags for defining epoll behavior.
+ * @return
+ *   0 on success, negative errno value otherwise.
+ */
+static int
+fs_epoll_create1(int flags)
+{
+#if defined(LINUX)
+       return epoll_create1(flags);
+#elif defined(BSD)
+       RTE_SET_USED(flags);
+       return -ENOTSUP;
+#endif
+}
+
+/**
+ * Install failsafe Rx event proxy subsystem.
+ * This is the way the failsafe PMD generates Rx events on behalf of its
+ * subdevices.
+ *
+ * @param priv
+ *   Pointer to failsafe private structure.
+ * @return
+ *   0 on success, negative errno value otherwise and rte_errno is set.
+ */
+static int
+fs_rx_event_proxy_install(struct fs_priv *priv)
+{
+       int rc = 0;
+
+       /*
+        * Create the epoll fd and event vector for the proxy service to
+        * wait on for Rx events generated by the subdevices.
+        */
+       priv->rxp.efd = fs_epoll_create1(0);
+       if (priv->rxp.efd < 0) {
+               rte_errno = errno;
+               ERROR("Failed to create epoll,"
+                     " Rx interrupts will not be supported");
+               return -rte_errno;
+       }
+       priv->rxp.evec = calloc(NUM_RX_PROXIES, sizeof(*priv->rxp.evec));
+       if (priv->rxp.evec == NULL) {
+               ERROR("Failed to allocate memory for event vectors,"
+                     " Rx interrupts will not be supported");
+               rc = -ENOMEM;
+               goto error;
+       }
+       return 0;
+error:
+       if (priv->rxp.efd >= 0) {
+               close(priv->rxp.efd);
+               priv->rxp.efd = -1;
+       }
+       if (priv->rxp.evec != NULL) {
+               free(priv->rxp.evec);
+               priv->rxp.evec = NULL;
+       }
+       rte_errno = -rc;
+       return rc;
+}
+
+/**
+ * RX Interrupt control per subdevice.
+ *
+ * @param sdev
+ *   Pointer to sub-device structure.
+ * @param op
+ *   The operation be performed for the vector.
+ *   Operation type of {RTE_INTR_EVENT_ADD, RTE_INTR_EVENT_DEL}.
+ * @return
+ *   - On success, zero.
+ *   - On failure, a negative value.
+ */
+static int
+failsafe_eth_rx_intr_ctl_subdevice(struct sub_device *sdev, int op)
+{
+       struct rte_eth_dev *dev;
+       struct rte_eth_dev *fsdev;
+       int epfd;
+       uint16_t pid;
+       uint16_t qid;
+       struct rxq *fsrxq;
+       int rc;
+       int ret = 0;
+
+       if (sdev == NULL || (ETH(sdev) == NULL) ||
+           sdev->fs_dev == NULL || (PRIV(sdev->fs_dev) == NULL)) {
+               ERROR("Called with invalid arguments");
+               return -EINVAL;
+       }
+       dev = ETH(sdev);
+       fsdev = sdev->fs_dev;
+       epfd = PRIV(sdev->fs_dev)->rxp.efd;
+       pid = PORT_ID(sdev);
+
+       if (epfd <= 0) {
+               if (op == RTE_INTR_EVENT_ADD) {
+                       ERROR("Proxy events are not initialized");
+                       return -EBADF;
+               } else {
+                       return 0;
+               }
+       }
+       if (dev->data->nb_rx_queues > fsdev->data->nb_rx_queues) {
+               ERROR("subdevice has too many queues,"
+                     " Interrupts will not be enabled");
+                       return -E2BIG;
+       }
+       for (qid = 0; qid < dev->data->nb_rx_queues; qid++) {
+               fsrxq = fsdev->data->rx_queues[qid];
+               rc = rte_eth_dev_rx_intr_ctl_q(pid, qid, epfd,
+                                              op, (void *)fsrxq);
+               if (rc) {
+                       ERROR("rte_eth_dev_rx_intr_ctl_q failed for "
+                             "port %d  queue %d, epfd %d, error %d",
+                             pid, qid, epfd, rc);
+                       ret = rc;
+               }
+       }
+       return ret;
+}
+
+/**
+ * Install Rx interrupts subsystem for a subdevice.
+ * This is a support for dynamically adding subdevices.
+ *
+ * @param sdev
+ *   Pointer to subdevice structure.
+ *
+ * @return
+ *   0 on success, negative errno value otherwise and rte_errno is set.
+ */
+int failsafe_rx_intr_install_subdevice(struct sub_device *sdev)
+{
+       int rc;
+       int qid;
+       struct rte_eth_dev *fsdev;
+       struct rxq **rxq;
+       const struct rte_intr_conf *const intr_conf =
+                               &ETH(sdev)->data->dev_conf.intr_conf;
+
+       fsdev = sdev->fs_dev;
+       rxq = (struct rxq **)fsdev->data->rx_queues;
+       if (intr_conf->rxq == 0)
+               return 0;
+       rc = failsafe_eth_rx_intr_ctl_subdevice(sdev, RTE_INTR_EVENT_ADD);
+       if (rc)
+               return rc;
+       /* enable interrupts on already-enabled queues */
+       for (qid = 0; qid < ETH(sdev)->data->nb_rx_queues; qid++) {
+               if (rxq[qid]->enable_events) {
+                       int ret = rte_eth_dev_rx_intr_enable(PORT_ID(sdev),
+                                                            qid);
+                       if (ret && (ret != -ENOTSUP)) {
+                               ERROR("Failed to enable interrupts on "
+                                     "port %d queue %d", PORT_ID(sdev), qid);
+                               rc = ret;
+                       }
+               }
+       }
+       return rc;
+}
+
+/**
+ * Uninstall Rx interrupts subsystem for a subdevice.
+ * This is a support for dynamically removing subdevices.
+ *
+ * @param sdev
+ *   Pointer to subdevice structure.
+ *
+ * @return
+ *   0 on success, negative errno value otherwise and rte_errno is set.
+ */
+void failsafe_rx_intr_uninstall_subdevice(struct sub_device *sdev)
+{
+       int qid;
+       struct rte_eth_dev *fsdev;
+       struct rxq *fsrxq;
+
+       fsdev = sdev->fs_dev;
+       for (qid = 0; qid < ETH(sdev)->data->nb_rx_queues; qid++) {
+               if (qid < fsdev->data->nb_rx_queues) {
+                       fsrxq = fsdev->data->rx_queues[qid];
+                       if (fsrxq->enable_events)
+                               rte_eth_dev_rx_intr_disable(PORT_ID(sdev),
+                                                           qid);
+               }
+       }
+       failsafe_eth_rx_intr_ctl_subdevice(sdev, RTE_INTR_EVENT_DEL);
+}
+
+/**
+ * Uninstall failsafe Rx event proxy.
+ *
+ * @param priv
+ *   Pointer to failsafe private structure.
+ */
+static void
+fs_rx_event_proxy_uninstall(struct fs_priv *priv)
+{
+       if (priv->rxp.evec != NULL) {
+               free(priv->rxp.evec);
+               priv->rxp.evec = NULL;
+       }
+       if (priv->rxp.efd > 0) {
+               close(priv->rxp.efd);
+               priv->rxp.efd = -1;
+       }
+}
+
 /**
  * Uninstall failsafe interrupt vector.
  *
@@ -107,7 +328,14 @@ fs_rx_intr_vec_install(struct fs_priv *priv)
 void
 failsafe_rx_intr_uninstall(struct rte_eth_dev *dev)
 {
-       fs_rx_intr_vec_uninstall(PRIV(dev));
+       struct fs_priv *priv;
+       struct rte_intr_handle *intr_handle;
+
+       priv = PRIV(dev);
+       intr_handle = &priv->intr_handle;
+       rte_intr_free_epoll_fd(intr_handle);
+       fs_rx_event_proxy_uninstall(priv);
+       fs_rx_intr_vec_uninstall(priv);
        dev->intr_handle = NULL;
 }
 
@@ -131,6 +359,10 @@ failsafe_rx_intr_install(struct rte_eth_dev *dev)
                return 0;
        if (fs_rx_intr_vec_install(priv) < 0)
                return -rte_errno;
+       if (fs_rx_event_proxy_install(priv) < 0) {
+               fs_rx_intr_vec_uninstall(priv);
+               return -rte_errno;
+       }
        dev->intr_handle = &priv->intr_handle;
        return 0;
 }
index 5cbc591..249baea 100644 (file)
@@ -213,6 +213,13 @@ fs_dev_start(struct rte_eth_dev *dev)
                                continue;
                        return ret;
                }
+               ret = failsafe_rx_intr_install_subdevice(sdev);
+               if (ret) {
+                       if (!fs_err(sdev, ret))
+                               continue;
+                       rte_eth_dev_stop(PORT_ID(sdev));
+                       return ret;
+               }
                sdev->state = DEV_STARTED;
        }
        if (PRIV(dev)->state < DEV_STARTED)
@@ -230,6 +237,7 @@ fs_dev_stop(struct rte_eth_dev *dev)
        PRIV(dev)->state = DEV_STARTED - 1;
        FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_STARTED) {
                rte_eth_dev_stop(PORT_ID(sdev));
+               failsafe_rx_intr_uninstall_subdevice(sdev);
                sdev->state = DEV_STARTED - 1;
        }
        failsafe_rx_intr_uninstall(dev);
@@ -412,6 +420,10 @@ static int
 fs_rx_intr_enable(struct rte_eth_dev *dev, uint16_t idx)
 {
        struct rxq *rxq;
+       struct sub_device *sdev;
+       uint8_t i;
+       int ret;
+       int rc = 0;
 
        if (idx >= dev->data->nb_rx_queues) {
                rte_errno = EINVAL;
@@ -423,14 +435,26 @@ fs_rx_intr_enable(struct rte_eth_dev *dev, uint16_t idx)
                return -rte_errno;
        }
        rxq->enable_events = 1;
-       return 0;
+       FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
+               ret = rte_eth_dev_rx_intr_enable(PORT_ID(sdev), idx);
+               ret = fs_err(sdev, ret);
+               if (ret)
+                       rc = ret;
+       }
+       if (rc)
+               rte_errno = -rc;
+       return rc;
 }
 
 static int
 fs_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
 {
        struct rxq *rxq;
+       struct sub_device *sdev;
        uint64_t u64;
+       uint8_t i;
+       int rc = 0;
+       int ret;
 
        if (idx >= dev->data->nb_rx_queues) {
                rte_errno = EINVAL;
@@ -442,10 +466,18 @@ fs_rx_intr_disable(struct rte_eth_dev *dev, uint16_t idx)
                return -rte_errno;
        }
        rxq->enable_events = 0;
+       FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) {
+               ret = rte_eth_dev_rx_intr_disable(PORT_ID(sdev), idx);
+               ret = fs_err(sdev, ret);
+               if (ret)
+                       rc = ret;
+       }
        /* Clear pending events */
        while (read(rxq->event_fd, &u64, sizeof(uint64_t)) >  0)
                ;
-       return 0;
+       if (rc)
+               rte_errno = -rc;
+       return rc;
 }
 
 static bool
index 419e5e7..ff78b9f 100644 (file)
 
 /* TYPES */
 
+struct rx_proxy {
+       /* epoll file descriptor */
+       int efd;
+       /* event vector to be used by epoll */
+       struct rte_epoll_event *evec;
+};
+
 struct rxq {
        struct fs_priv *priv;
        uint16_t qid;
@@ -158,6 +165,13 @@ struct fs_priv {
         */
        enum dev_state state;
        struct rte_eth_stats stats_accumulator;
+       /*
+        * Rx interrupts/events proxy.
+        * The PMD issues Rx events to the EAL on behalf of its subdevices,
+        * it does that by registering an event-fd for each of its queues with
+        * the EAL.
+        */
+       struct rx_proxy rxp;
        unsigned int pending_alarm:1; /* An alarm is pending */
        /* flow isolation state */
        int flow_isolated:1;
@@ -167,6 +181,8 @@ struct fs_priv {
 
 int failsafe_rx_intr_install(struct rte_eth_dev *dev);
 void failsafe_rx_intr_uninstall(struct rte_eth_dev *dev);
+int failsafe_rx_intr_install_subdevice(struct sub_device *sdev);
+void failsafe_rx_intr_uninstall_subdevice(struct sub_device *sdev);
 
 /* MISC */