[dpdk-dev,v5,2/3] net/failsafe: slaves Rx interrupts registration

Message ID 1516733000-1850-3-git-send-email-motih@mellanox.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Moti Haimovsky Jan. 23, 2018, 6:43 p.m. UTC
  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>
---
V5:
Initial version of this patch in accordance to inputs from Gaetan Rivet
in reply to
1516354344-13495-2-git-send-email-motih@mellanox.com
---
 drivers/net/failsafe/failsafe_ether.c   |   1 +
 drivers/net/failsafe/failsafe_intr.c    | 196 ++++++++++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c     |  36 +++++-
 drivers/net/failsafe/failsafe_private.h |  16 +++
 4 files changed, 247 insertions(+), 2 deletions(-)
  

Comments

Moti Haimovsky Jan. 24, 2018, 4:12 p.m. UTC | #1
These three patches add support for registering and waiting for
Rx interrupts in failsafe PMD. This allows applications to wait
for Rx events from the PMD using the DPDK rte_epoll subsystem.
The failsafe PMD presents to the application a facade of a single
device to be handled by the application while internally it manages
several devices on behalf of the application including packets
transmission and reception.
The Proposed failsafe Rx interrupt scheme follows this approach.
The failsafe PMD will present the application with a single set of
Rx interrupt vectors representing the failsafe Rx queues, while
internally it will serve as an interrupt proxy for its subdevices.
will allow applications to wait for Rx traffic from the failsafe
PMD by registering and waiting for Rx events from its Rx queues.
In order to support this the following is suggested:
  * Every Rx queue in the failsafe (virtual) device will be assigned
  * a Linux event file descriptor (efd) and an enable_interrupts flag.
  * The failsafe PMD will fill in its rte_intr_handle structure with
    the Rx efds assigned previously and register them with the EAL.
  * The failsafe driver will create a private epoll fd (epfd) and
  * will allocate enough space to handle all the Rx events from all its
    subdevices.
  * Acting as an application,
    for each Rx queue in each active subdevice the failsafe will:
      o Register the Rx queue with the EAL.
      o Pass the EAL the failsafe private epoll fd as the epfd to
        register the Rx queue event on.
      o Pass the EAL, as a parameter, the pointer to the failsafe Rx
        queue that handles this Rx queue.
      o Using the DPDK service callbacks, the failsafe PMD will launch
        an Rx proxy service that will Wait on the epoll fd for Rx
        events from the sub-devices.
      o For each Rx event received the proxy service will
          - Retrieve the pointer to failsafe Rx queue that handles
            this subdevice Rx queue from the user info returned by the
            EAL.
          - Trigger a failsafe Rx event on that queue by writing to
            the event fd unless interrupts are disabled for that queue.
  * The failsafe pmd will also implement the rx_queue_intr_enable
  * and rx_queue_intr_disable routines that will enable and disable Rx
    interrupts respectively on both on the failsafe and its subdevices.

Moti Haimovsky (3):
  net/failsafe: register as an Rx interrupt mode PMD
  net/failsafe: slaves Rx interrupts registration
  net/failsafe: add Rx interrupts
---
V6:
* Added a wrapper around epoll_create1 since it is not supported in FreeBSD.
  See: 1516193643-130838-1-git-send-email-motih@mellanox.com
* Separated between routines' variables definition and initialization
  according to guidelines from Gaetan Rivet.

V5:
Modified code and split the patch into three patches in accordance to
inputs from Gaetan Rivet in reply to
1516354344-13495-2-git-send-email-motih@mellanox.com

V4:
Fixed merge conflicts found during integration with other failsafe patches
(See cover letter).

V3:
Fixed build failures in FreeBSD10.3_64

V2:
Modifications according to inputs from Stephen Hemminger:
* Removed unneeded (void *) casting.
Fixed coding style warning.
---
 doc/guides/nics/features/failsafe.ini          |   1 +
 drivers/net/failsafe/Makefile                  |   6 +
 drivers/net/failsafe/failsafe.c                |   4 +
 drivers/net/failsafe/failsafe_epoll.h          |  10 +
 drivers/net/failsafe/failsafe_epoll_bsdapp.c   |  19 +
 drivers/net/failsafe/failsafe_epoll_linuxapp.c |  18 +
 drivers/net/failsafe/failsafe_ether.c          |   1 +
 drivers/net/failsafe/failsafe_intr.c           | 505 +++++++++++++++++++++++++
 drivers/net/failsafe/failsafe_ops.c            | 102 +++++
 drivers/net/failsafe/failsafe_private.h        |  40 ++
 10 files changed, 706 insertions(+)
 create mode 100644 drivers/net/failsafe/failsafe_epoll.h
 create mode 100644 drivers/net/failsafe/failsafe_epoll_bsdapp.c
 create mode 100644 drivers/net/failsafe/failsafe_epoll_linuxapp.c
 create mode 100644 drivers/net/failsafe/failsafe_intr.c
  

Patch

diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c
index 8a4cacf..0f1630e 100644
--- a/drivers/net/failsafe/failsafe_ether.c
+++ b/drivers/net/failsafe/failsafe_ether.c
@@ -283,6 +283,7 @@ 
 		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 */
diff --git a/drivers/net/failsafe/failsafe_intr.c b/drivers/net/failsafe/failsafe_intr.c
index 2c92d95..2f18b3d 100644
--- a/drivers/net/failsafe/failsafe_intr.c
+++ b/drivers/net/failsafe/failsafe_intr.c
@@ -7,10 +7,198 @@ 
  * Interrupts handling for failsafe driver.
  */
 
+#include <sys/epoll.h>
 #include <unistd.h>
 
 #include "failsafe_private.h"
 
+#define NUM_RX_PROXIES (FAILSAFE_MAX_ETHPORTS * RTE_MAX_RXTX_INTR_VEC_ID)
+
+/**
+ * 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 = 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 -EBADFD;
+		} 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 = sdev->fs_dev;
+	struct rxq **rxq = (struct rxq **)fsdev->data->rx_queues;
+	const struct rte_intr_conf *const intr_conf =
+				&ETH(sdev)->data->dev_conf.intr_conf;
+
+	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;
+
+	for (qid = 0; qid < ETH(sdev)->data->nb_rx_queues; qid++)
+		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.
  *
@@ -102,7 +290,11 @@ 
 failsafe_rx_intr_uninstall(struct rte_eth_dev *dev)
 {
 	struct fs_priv *priv = PRIV(dev);
+	struct rte_intr_handle *intr_handle;
 
+	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;
 }
@@ -127,6 +319,10 @@ 
 		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;
 }
diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c
index d6a82b3..2ea9cdd 100644
--- a/drivers/net/failsafe/failsafe_ops.c
+++ b/drivers/net/failsafe/failsafe_ops.c
@@ -214,6 +214,13 @@ 
 				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)
@@ -231,6 +238,7 @@ 
 	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);
@@ -413,6 +421,10 @@ 
 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;
@@ -424,14 +436,26 @@ 
 		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;
@@ -443,10 +467,18 @@ 
 		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
diff --git a/drivers/net/failsafe/failsafe_private.h b/drivers/net/failsafe/failsafe_private.h
index 419e5e7..ff78b9f 100644
--- a/drivers/net/failsafe/failsafe_private.h
+++ b/drivers/net/failsafe/failsafe_private.h
@@ -63,6 +63,13 @@ 
 
 /* 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 */