From: Stephen Hemminger <stephen@networkplumber.org>
To: cumming.lian@intel.com
Cc: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 5/5] uio: integrate MSI-X support
Date: Mon, 18 May 2015 10:40:14 -0700 [thread overview]
Message-ID: <1431970814-25951-6-git-send-email-stephen@networkplumber.org> (raw)
In-Reply-To: <1431970814-25951-1-git-send-email-stephen@networkplumber.org>
Add the new uio_msi as a supported driver model.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
lib/librte_eal/common/include/rte_pci.h | 1 +
lib/librte_eal/linuxapp/eal/eal_interrupts.c | 94 +++++++++++++++++++---
lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +
lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 59 ++++++++++++--
lib/librte_eal/linuxapp/eal/eal_uio_msi.h | 26 ++++++
.../linuxapp/eal/include/exec-env/rte_interrupts.h | 1 +
lib/librte_ether/rte_ethdev.c | 1 +
tools/dpdk_nic_bind.py | 2 +-
8 files changed, 166 insertions(+), 22 deletions(-)
create mode 100644 lib/librte_eal/linuxapp/eal/eal_uio_msi.h
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 223d3cd..106f4f7 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -147,6 +147,7 @@ enum rte_kernel_driver {
RTE_KDRV_IGB_UIO,
RTE_KDRV_VFIO,
RTE_KDRV_UIO_GENERIC,
+ RTE_KDRV_UIO_MSIX,
};
/**
diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
index fd97fc4..8cdab58 100644
--- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c
+++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c
@@ -66,6 +66,7 @@
#include "eal_private.h"
#include "eal_vfio.h"
+#include "eal_uio_msi.h"
#define EAL_INTR_EPOLL_WAIT_FOREVER (-1)
@@ -89,9 +90,7 @@ union intr_pipefds{
*/
union rte_intr_read_buffer {
int uio_intr_count; /* for uio device */
-#ifdef VFIO_PRESENT
- uint64_t vfio_intr_count; /* for vfio device */
-#endif
+ uint64_t eventfd_count; /* for vfio and uio-msi */
uint64_t timerfd_num; /* for timerfd */
char charbuf[16]; /* for others */
};
@@ -356,6 +355,67 @@ vfio_disable_msix(struct rte_intr_handle *intr_handle) {
}
#endif
+/* enable MSI-X interrupts */
+static int
+uio_msix_enable(struct rte_intr_handle *intr_handle)
+{
+ int i, max_intr;
+
+ if (!intr_handle->max_intr ||
+ intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
+ max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
+ else
+ max_intr = intr_handle->max_intr;
+
+ /* Actual number of MSI-X interrupts might be less than requested */
+ for (i = 0; i < max_intr; i++) {
+ struct uio_msi_irq_set irqs = {
+ .vec = i,
+ .fd = intr_handle->efds[i],
+ };
+
+ if (i == max_intr - 1)
+ irqs.fd = intr_handle->fd;
+
+ if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {
+ RTE_LOG(ERR, EAL,
+ "Error enabling MSI-X event %u fd %d (%s)\n",
+ irqs.vec, irqs.fd, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* disable MSI-X interrupts */
+static int
+uio_msix_disable(struct rte_intr_handle *intr_handle)
+{
+ int i, max_intr;
+
+ if (!intr_handle->max_intr ||
+ intr_handle->max_intr > RTE_MAX_RXTX_INTR_VEC_ID)
+ max_intr = RTE_MAX_RXTX_INTR_VEC_ID + 1;
+ else
+ max_intr = intr_handle->max_intr;
+
+ for (i = 0; i < max_intr; i++) {
+ struct uio_msi_irq_set irqs = {
+ .vec = i,
+ .fd = -1,
+ };
+
+ if (ioctl(intr_handle->vfio_dev_fd, UIO_MSI_IRQ_SET, &irqs) < 0) {
+ RTE_LOG(ERR, EAL,
+ "Error disabling MSI-X event %u (%s)\n",
+ i, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
static int
uio_intx_intr_disable(struct rte_intr_handle *intr_handle)
{
@@ -584,6 +644,10 @@ rte_intr_enable(struct rte_intr_handle *intr_handle)
if (uio_intx_intr_enable(intr_handle))
return -1;
break;
+ case RTE_INTR_HANDLE_UIO_MSIX:
+ if (uio_msix_enable(intr_handle))
+ return -1;
+ break;
/* not used at this moment */
case RTE_INTR_HANDLE_ALARM:
return -1;
@@ -628,6 +692,10 @@ rte_intr_disable(struct rte_intr_handle *intr_handle)
if (uio_intx_intr_disable(intr_handle))
return -1;
break;
+ case RTE_INTR_HANDLE_UIO_MSIX:
+ if (uio_msix_disable(intr_handle))
+ return -1;
+ break;
/* not used at this moment */
case RTE_INTR_HANDLE_ALARM:
return -1;
@@ -696,16 +764,19 @@ eal_intr_process_interrupts(struct epoll_event *events, int nfds)
case RTE_INTR_HANDLE_UIO:
bytes_read = sizeof(buf.uio_intr_count);
break;
+
case RTE_INTR_HANDLE_ALARM:
bytes_read = sizeof(buf.timerfd_num);
break;
-#ifdef VFIO_PRESENT
+
+ case RTE_INTR_HANDLE_UIO_MSIX:
+#ifdef RTE_EAL_VFIO
case RTE_INTR_HANDLE_VFIO_MSIX:
case RTE_INTR_HANDLE_VFIO_MSI:
case RTE_INTR_HANDLE_VFIO_LEGACY:
- bytes_read = sizeof(buf.vfio_intr_count);
- break;
#endif
+ bytes_read = sizeof(buf.eventfd_count);
+ break;
default:
bytes_read = 1;
break;
@@ -895,17 +966,14 @@ static void
eal_intr_proc_rxtx_intr(int fd, struct rte_intr_handle *intr_handle)
{
union rte_intr_read_buffer buf;
- int bytes_read = 1;
+ int bytes_read = sizeof(buf.eventfd_count);
- if (intr_handle->type != RTE_INTR_HANDLE_VFIO_MSIX) {
- RTE_LOG(ERR, EAL, "intr type should be VFIO_MSIX\n");
+ if (intr_handle->type != RTE_INTR_HANDLE_VFIO_MSIX &&
+ intr_handle->type != RTE_INTR_HANDLE_UIO_MSIX) {
+ RTE_LOG(ERR, EAL, "intr type should be VFIO_MSIX or UIO_MSIX\n");
return;
}
-#ifdef VFIO_PRESENT
- bytes_read = sizeof(buf.vfio_intr_count);
-#endif
-
/**
* read out to clear the ready-to-be-read flag
* for epoll_wait.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index d2adc66..814dc7c 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -345,6 +345,8 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
dev->kdrv = RTE_KDRV_IGB_UIO;
else if (!strcmp(driver, "uio_pci_generic"))
dev->kdrv = RTE_KDRV_UIO_GENERIC;
+ else if (!strcmp(driver, "uio_msi"))
+ dev->kdrv = RTE_KDRV_UIO_MSIX;
else
dev->kdrv = RTE_KDRV_UNKNOWN;
} else if (ret < 0) {
@@ -576,6 +578,7 @@ pci_map_device(struct rte_pci_device *dev)
ret = pci_vfio_map_resource(dev);
#endif
break;
+ case RTE_KDRV_UIO_MSIX:
case RTE_KDRV_IGB_UIO:
case RTE_KDRV_UIO_GENERIC:
/* map resources for devices that use uio */
@@ -603,6 +606,7 @@ pci_unmap_device(struct rte_pci_device *dev)
case RTE_KDRV_VFIO:
RTE_LOG(ERR, EAL, "Hotplug doesn't support vfio yet\n");
break;
+ case RTE_KDRV_UIO_MSIX:
case RTE_KDRV_IGB_UIO:
case RTE_KDRV_UIO_GENERIC:
/* unmap resources for devices that use uio */
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index b5116a7..7eee828 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -38,6 +38,7 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/pci_regs.h>
+#include <sys/eventfd.h>
#include <rte_log.h>
#include <rte_pci.h>
@@ -259,13 +260,42 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
return uio_num;
}
+static int
+pci_uio_msix_init(struct rte_pci_device *dev)
+{
+ int i, fd;
+
+ /* set up an eventfd for interrupts */
+ fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+ if (fd < 0) {
+ RTE_LOG(ERR, EAL, " cannot set up irq eventfd (%s)\n",
+ strerror(errno));
+ return -1;
+ }
+ dev->intr_handle.fd = fd;
+
+ /* an additional eventfd for each vector */
+ for (i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++) {
+ fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
+ if (fd < 0) {
+ RTE_LOG(ERR, EAL,
+ " cannot set up eventfd (%s)\n",
+ strerror(errno));
+ return -1;
+ }
+
+ dev->intr_handle.efds[i] = fd;
+ }
+
+ return 0;
+}
+
/* map the PCI resource of a PCI device in virtual memory */
int
pci_uio_map_resource(struct rte_pci_device *dev)
{
- int i, map_idx;
+ int i, fd, map_idx;
char dirname[PATH_MAX];
- char cfgname[PATH_MAX];
char devname[PATH_MAX]; /* contains the /dev/uioX */
void *mapaddr;
int uio_num;
@@ -274,11 +304,15 @@ pci_uio_map_resource(struct rte_pci_device *dev)
struct mapped_pci_resource *uio_res;
struct mapped_pci_res_list *uio_res_list = RTE_TAILQ_CAST(rte_uio_tailq.head, mapped_pci_res_list);
struct pci_map *maps;
+ char cfgname[PATH_MAX];
dev->intr_handle.fd = -1;
- dev->intr_handle.uio_cfg_fd = -1;
+ dev->intr_handle.vfio_dev_fd = -1;
dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+ for (i = 0; i < RTE_MAX_RXTX_INTR_VEC_ID; i++)
+ dev->intr_handle.efds[i] = -1;
+
/* secondary processes - use already recorded details */
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return pci_uio_map_secondary(dev);
@@ -293,15 +327,15 @@ pci_uio_map_resource(struct rte_pci_device *dev)
snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
/* save fd if in primary process */
- dev->intr_handle.fd = open(devname, O_RDWR);
- if (dev->intr_handle.fd < 0) {
+ fd = open(devname, O_RDWR);
+ if (fd < 0) {
RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
devname, strerror(errno));
return -1;
}
snprintf(cfgname, sizeof(cfgname),
- "/sys/class/uio/uio%u/device/config", uio_num);
+ "/sys/class/uio/uio%u/device/config", uio_num);
dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
if (dev->intr_handle.uio_cfg_fd < 0) {
RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
@@ -309,9 +343,17 @@ pci_uio_map_resource(struct rte_pci_device *dev)
return -1;
}
- if (dev->kdrv == RTE_KDRV_IGB_UIO)
+ if (dev->kdrv == RTE_KDRV_UIO_MSIX) {
+ dev->intr_handle.vfio_dev_fd = fd;
+ dev->intr_handle.type = RTE_INTR_HANDLE_UIO_MSIX;
+ if (pci_uio_msix_init(dev) < 0)
+ return -1;
+ } else if (dev->kdrv == RTE_KDRV_IGB_UIO) {
+ dev->intr_handle.fd = fd;
dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
- else {
+ } else {
+
+ dev->intr_handle.fd = fd;
dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
/* set bus master that is not done by uio_pci_generic */
@@ -460,6 +502,7 @@ pci_uio_unmap_resource(struct rte_pci_device *dev)
/* close fd if in primary process */
close(dev->intr_handle.fd);
+ close(dev->intr_handle.uio_cfg_fd);
dev->intr_handle.fd = -1;
dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
diff --git a/lib/librte_eal/linuxapp/eal/eal_uio_msi.h b/lib/librte_eal/linuxapp/eal/eal_uio_msi.h
new file mode 100644
index 0000000..f01f302
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/eal_uio_msi.h
@@ -0,0 +1,26 @@
+/*
+ * UIO_MSI API definition
+ *
+ * Copyright (c) 2015 by Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef EAL_UIO_MSI_H
+#define EAL_UIO_MSI_H
+
+/* Driver is not upstream yet. */
+
+#include <sys/ioctl.h>
+
+struct uio_msi_irq_set {
+ uint32_t vec;
+ int fd;
+};
+
+#define UIO_MSI_BASE 0x86
+#define UIO_MSI_IRQ_SET _IOW('I', UIO_MSI_BASE+1, struct uio_msi_irq_set)
+
+#endif
diff --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
index 9843001..d3cf680 100644
--- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h
@@ -44,6 +44,7 @@ enum rte_intr_handle_type {
RTE_INTR_HANDLE_UNKNOWN = 0,
RTE_INTR_HANDLE_UIO, /**< uio device handle */
RTE_INTR_HANDLE_UIO_INTX, /**< uio generic handle */
+ RTE_INTR_HANDLE_UIO_MSIX, /**< uio with MSI-X support */
RTE_INTR_HANDLE_VFIO_LEGACY, /**< vfio device handle (legacy) */
RTE_INTR_HANDLE_VFIO_MSI, /**< vfio device handle (MSI) */
RTE_INTR_HANDLE_VFIO_MSIX, /**< vfio device handle (MSIX) */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index cf9a79a..3fbc4a1 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -515,6 +515,7 @@ rte_eth_dev_is_detachable(uint8_t port_id)
switch (rte_eth_devices[port_id].pci_dev->kdrv) {
case RTE_KDRV_IGB_UIO:
case RTE_KDRV_UIO_GENERIC:
+ case RTE_KDRV_UIO_MSIX:
break;
case RTE_KDRV_VFIO:
default:
diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py
index 8523f82..20b4b06 100755
--- a/tools/dpdk_nic_bind.py
+++ b/tools/dpdk_nic_bind.py
@@ -43,7 +43,7 @@ ETHERNET_CLASS = "0200"
# Each device within this is itself a dictionary of device properties
devices = {}
# list of supported DPDK drivers
-dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic" ]
+dpdk_drivers = [ "igb_uio", "vfio-pci", "uio_pci_generic", "uio_msi" ]
# command-line arg flags
b_flag = None
--
2.1.4
next prev parent reply other threads:[~2015-05-18 17:40 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-18 17:40 [dpdk-dev] [PATCH 0/5] receive IRQ related patches Stephen Hemminger
2015-05-18 17:40 ` [dpdk-dev] [PATCH 1/5] ethdev: check for rxq interrupt support Stephen Hemminger
2015-05-18 17:40 ` [dpdk-dev] [PATCH 2/5] ethdev: remove unnecessary checks Stephen Hemminger
2015-05-18 17:40 ` [dpdk-dev] [PATCH 3/5] ethdev: fix errors if RTE_ETHDEV_DEBUG enabled Stephen Hemminger
2015-05-18 17:40 ` [dpdk-dev] [PATCH 4/5] uio: new driver with MSI-X support Stephen Hemminger
2015-05-25 6:01 ` Liang, Cunming
2015-05-25 17:41 ` Stephen Hemminger
2015-05-18 17:40 ` Stephen Hemminger [this message]
2015-05-25 8:55 ` [dpdk-dev] [PATCH 5/5] uio: integrate " Liang, Cunming
2015-05-25 17:42 ` Stephen Hemminger
2015-07-09 0:28 ` [dpdk-dev] [PATCH 0/5] receive IRQ related patches Thomas Monjalon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1431970814-25951-6-git-send-email-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=cumming.lian@intel.com \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).