From: David Marchand <david.marchand@6wind.com>
To: dev@dpdk.org
Cc: viktorin@rehivetech.com
Subject: [dpdk-dev] [PATCH v2 9/9] pci: implement automatic bind/unbind
Date: Fri, 29 Jan 2016 15:49:13 +0100 [thread overview]
Message-ID: <1454078953-23744-10-git-send-email-david.marchand@6wind.com> (raw)
In-Reply-To: <1454078953-23744-1-git-send-email-david.marchand@6wind.com>
Reuse pci hook to implement automatic bind / unbind.
The more I look at this, the more I think this should go to the PMDs
themselves (with options per devices to control this), with EAL offering
helpers to achieve this.
Signed-off-by: David Marchand <david.marchand@6wind.com>
---
lib/librte_eal/bsdapp/eal/eal_pci.c | 25 ++++
lib/librte_eal/common/eal_common_options.c | 8 ++
lib/librte_eal/common/eal_common_pci.c | 79 +++++++++++
lib/librte_eal/common/eal_options.h | 2 +
lib/librte_eal/common/eal_private.h | 38 ++++++
lib/librte_eal/common/include/rte_pci.h | 7 +-
lib/librte_eal/linuxapp/eal/eal_pci.c | 210 +++++++++++++++++++++++++++++
7 files changed, 367 insertions(+), 2 deletions(-)
diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index e95249b..130f7e9 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -91,6 +91,31 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
return -ENOTSUP;
}
+int
+pci_rebind_device(const struct rte_pci_device *dev __rte_unused,
+ const char *driver __rte_unused)
+{
+ RTE_LOG(ERR, EAL, "Rebinding device to pci kernel drivers is not implemented for BSD\n");
+ return -ENOTSUP;
+}
+
+int
+pci_mapping_driver_bound(const struct rte_pci_device *dev)
+{
+ int ret;
+
+ switch (dev->kdrv) {
+ case RTE_KDRV_NIC_UIO:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
/* Map pci device */
int
pci_map_device(struct rte_pci_device *dev)
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 29942ea..b646abd 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -54,6 +54,7 @@
#include "eal_internal_cfg.h"
#include "eal_options.h"
#include "eal_filesystem.h"
+#include "eal_private.h"
#define BITS_PER_HEX 4
@@ -95,6 +96,7 @@ eal_long_options[] = {
{OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
{OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
{OPT_XEN_DOM0, 0, NULL, OPT_XEN_DOM0_NUM },
+ {OPT_PCI_UIO_AUTOBIND, 1, NULL, OPT_PCI_UIO_AUTOBIND_NUM },
{0, 0, NULL, 0 }
};
@@ -897,6 +899,10 @@ eal_parse_common_option(int opt, const char *optarg,
}
break;
+ case OPT_PCI_UIO_AUTOBIND_NUM:
+ pci_init_autobind(optarg);
+ break;
+
/* don't know what to do, leave this to caller */
default:
return 1;
@@ -1019,5 +1025,7 @@ eal_common_usage(void)
" --"OPT_NO_PCI" Disable PCI\n"
" --"OPT_NO_HPET" Disable HPET\n"
" --"OPT_NO_SHCONF" No shared config (mmap'd files)\n"
+ " --"OPT_PCI_UIO_AUTOBIND" Set default kernel driver to bind pci devices,\n"
+ " when their associated pmd requires uio\n"
"\n", RTE_MAX_LCORE);
}
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index 4a0ec73..04a2490 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -89,6 +89,8 @@ struct pci_device_list pci_device_list =
enum rte_eal_pci_hook {
RTE_EAL_PCI_SCAN,
+ RTE_EAL_PCI_ATTACH,
+ RTE_EAL_PCI_DETACH,
};
enum rte_eal_pci_hook_return {
@@ -132,6 +134,8 @@ blacklist_pci_hook(enum rte_eal_pci_hook h,
ret = RTE_EAL_PCI_HOOK_OK;
break;
}
+ case RTE_EAL_PCI_ATTACH:
+ case RTE_EAL_PCI_DETACH:
default:
/* nothing to do here, just say ok */
ret = RTE_EAL_PCI_HOOK_OK;
@@ -141,6 +145,61 @@ blacklist_pci_hook(enum rte_eal_pci_hook h,
return ret;
}
+static char *uio_default_driver;
+
+static int
+autobind_uio_pci_hook(enum rte_eal_pci_hook h,
+ struct rte_pci_driver *dr,
+ struct rte_pci_device *dev)
+{
+ int ret;
+
+ /* stack with blacklist_pci_hook */
+ ret = blacklist_pci_hook(h, dr, dev);
+ if (ret != RTE_EAL_PCI_HOOK_OK)
+ goto exit;
+
+ switch (h) {
+ case RTE_EAL_PCI_ATTACH:
+ {
+ /* either nothing needed, or already bound */
+ if (!(dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) ||
+ pci_mapping_driver_bound(dev)) {
+ ret = RTE_EAL_PCI_HOOK_OK;
+ goto exit;
+ }
+
+ if (pci_rebind_device(dev, uio_default_driver) < 0 ||
+ pci_refresh_device(&dev->addr) < 0)
+ ret = RTE_EAL_PCI_HOOK_ERROR;
+ else
+ ret = RTE_EAL_PCI_HOOK_OK;
+
+ break;
+ }
+ case RTE_EAL_PCI_DETACH:
+ {
+ if (!(dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)) {
+ ret = RTE_EAL_PCI_HOOK_OK;
+ goto exit;
+ }
+
+ pci_rebind_device(dev, "");
+ ret = RTE_EAL_PCI_HOOK_OK;
+
+ break;
+ }
+ case RTE_EAL_PCI_SCAN:
+ default:
+ /* nothing to do here, just say ok */
+ ret = RTE_EAL_PCI_HOOK_OK;
+ break;
+ }
+
+exit:
+ return ret;
+}
+
static rte_eal_pci_hook_t *pci_hook = &blacklist_pci_hook;
static struct rte_devargs *pci_devargs_lookup(struct rte_pci_device *dev)
@@ -269,6 +328,12 @@ pci_probe_device(struct rte_pci_driver *dr, struct rte_pci_device *dev)
RTE_LOG(DEBUG, EAL, " probe driver: %x:%x %s\n", dev->id.vendor_id,
dev->id.device_id, dr->name);
+ ret = pci_hook(RTE_EAL_PCI_ATTACH, dr, dev);
+ if (ret != RTE_EAL_PCI_HOOK_OK) {
+ RTE_LOG(DEBUG, EAL, " attach hook refused dev, err=%d\n", ret);
+ return -1;
+ }
+
if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) {
#ifdef RTE_PCI_CONFIG
/*
@@ -332,6 +397,15 @@ pci_find_driver(struct rte_pci_device *dev)
return dr;
}
+void pci_init_autobind(const char *name)
+{
+ if (uio_default_driver)
+ free(uio_default_driver);
+ uio_default_driver = strdup(name);
+ if (uio_default_driver)
+ pci_hook = &autobind_uio_pci_hook;
+}
+
/*
* Find the pci device specified by pci address, then invoke probe function of
* the driver of the devive.
@@ -382,6 +456,7 @@ int
rte_eal_pci_detach(const struct rte_pci_addr *addr)
{
struct rte_pci_device *dev;
+ struct rte_pci_driver *dr;
if (addr == NULL)
return -1;
@@ -394,9 +469,13 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
dev->addr.domain, dev->addr.bus, dev->addr.devid,
dev->addr.function, dev->numa_node);
+ dr = dev->driver;
+
if (pci_detach_device(dev) < 0)
goto err_return;
+ pci_hook(RTE_EAL_PCI_DETACH, dr, dev);
+
TAILQ_REMOVE(&pci_device_list, dev, next);
return 0;
diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
index a881c62..182bc3d 100644
--- a/lib/librte_eal/common/eal_options.h
+++ b/lib/librte_eal/common/eal_options.h
@@ -83,6 +83,8 @@ enum {
OPT_VMWARE_TSC_MAP_NUM,
#define OPT_XEN_DOM0 "xen-dom0"
OPT_XEN_DOM0_NUM,
+#define OPT_PCI_UIO_AUTOBIND "pci-uio-autobind"
+ OPT_PCI_UIO_AUTOBIND_NUM,
OPT_LONG_MAX_NUM
};
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index e44a448..9019144 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -215,6 +215,44 @@ int pci_unbind_kernel_driver(struct rte_pci_device *dev);
int pci_map_device(struct rte_pci_device *dev);
/**
+ * Tell to the autobind system which driver to bind to.
+ *
+ * This function is private to EAL.
+ *
+ * @param name
+ * The kernel driver to bind to.
+ */
+void pci_init_autobind(const char *name);
+
+/**
+ * Helper used by autobind system to check if device is already bound
+ * to an adequate driver.
+ *
+ * This function is private to EAL.
+ *
+ * @param dev
+ * The PCI device object.
+ * @return
+ * 0 on success, positive if device is bound.
+ */
+int pci_mapping_driver_bound(const struct rte_pci_device *dev);
+
+/**
+ * Rebind a pci device to a kernel driver.
+ *
+ * This function is private to EAL.
+ *
+ * @param dev
+ * The PCI device object.
+ * @param name
+ * The kernel driver to bind to, passing an empty name tries to rebind
+ * the device to original kernel driver.
+ * @return
+ * 0 on success, negative on error
+ */
+int pci_rebind_device(const struct rte_pci_device *dev, const char *name);
+
+/**
* Unmap this device
*
* This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 9edd5f5..75cab50 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -90,8 +90,11 @@ TAILQ_HEAD(pci_driver_list, rte_pci_driver); /**< PCI drivers in D-linked Q. */
extern struct pci_driver_list pci_driver_list; /**< Global list of PCI drivers. */
extern struct pci_device_list pci_device_list; /**< Global list of PCI devices. */
-/** Pathname of PCI devices directory. */
-#define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
+/* FIXME: this is linux stuff, should not be in common/ */
+/** Pathname of PCI directories. */
+#define SYSFS_PCI "/sys/bus/pci"
+#define SYSFS_PCI_DEVICES SYSFS_PCI"/devices"
+#define SYSFS_PCI_DRIVERS SYSFS_PCI"/drivers"
/** Formatting string for PCI device identifier: Ex: 0000:00:01.0 */
#define PCI_PRI_FMT "%.4" PRIx16 ":%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index c3118fc..e711eea 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -94,6 +94,197 @@ error:
}
static int
+pci_rebind_device_override(const struct rte_pci_device *dev, const char *driver)
+{
+ int n;
+ FILE *f = NULL;
+ char filename[PATH_MAX];
+ char buf[BUFSIZ];
+ const struct rte_pci_addr *loc = &dev->addr;
+
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/driver_override",
+ loc->domain, loc->bus, loc->devid, loc->function);
+
+ n = snprintf(buf, sizeof(buf), "%s\n", driver);
+ if (n < 0 || n >= (int)sizeof(buf)) {
+ RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
+ goto error;
+ }
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+
+ fclose(f);
+
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/driver/unbind",
+ loc->domain, loc->bus, loc->devid, loc->function);
+
+ n = snprintf(buf, sizeof(buf), PCI_PRI_FMT "\n",
+ loc->domain, loc->bus, loc->devid, loc->function);
+ if (n < 0 || n >= (int)sizeof(buf)) {
+ RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
+ goto error;
+ }
+
+ f = fopen(filename, "w");
+ /* device might be bound to nothing ? */
+ if (f) {
+ if (fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+ fclose(f);
+ }
+
+ snprintf(filename, sizeof(filename), SYSFS_PCI "/drivers_probe");
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n", __func__,
+ filename);
+ goto error;
+ }
+
+ fclose(f);
+
+ return 0;
+error:
+ if (f)
+ fclose(f);
+ return -1;
+}
+
+static int
+pci_rebind_device_legacy(const struct rte_pci_device *dev, const char *driver)
+{
+ int n;
+ FILE *f = NULL;
+ char filename[PATH_MAX];
+ char buf[BUFSIZ];
+ const struct rte_pci_addr *loc = &dev->addr;
+
+ if (driver[0] != '\0') {
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DRIVERS "/%s/new_id", driver);
+
+ n = snprintf(buf, sizeof(buf), "%4.4x %4.4x\n",
+ dev->id.vendor_id, dev->id.device_id);
+ if (n < 0 || n >= (int)sizeof(buf)) {
+ RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
+ goto error;
+ }
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+
+ fclose(f);
+ }
+
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/driver/unbind",
+ loc->domain, loc->bus, loc->devid, loc->function);
+
+ n = snprintf(buf, sizeof(buf), PCI_PRI_FMT "\n",
+ loc->domain, loc->bus, loc->devid, loc->function);
+ if (n < 0 || n >= (int)sizeof(buf)) {
+ RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
+ goto error;
+ }
+
+ f = fopen(filename, "w");
+ /* device might be bound to nothing ? */
+ if (f) {
+ if (fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+ fclose(f);
+ }
+
+ if (driver[0] != '\0') {
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DRIVERS "/%s/bind", driver);
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+
+ fclose(f);
+
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DRIVERS "/%s/remove_id", driver);
+
+ n = snprintf(buf, sizeof(buf), "%4.4x %4.4x\n",
+ dev->id.vendor_id, dev->id.device_id);
+ if (n < 0 || n >= (int)sizeof(buf)) {
+ RTE_LOG(ERR, EAL, "%s(): snprintf failed\n", __func__);
+ goto error;
+ }
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+
+ fclose(f);
+ } else {
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI "/drivers_probe");
+
+ f = fopen(filename, "w");
+ if (!f || fwrite(buf, n, 1, f) == 0) {
+ RTE_LOG(ERR, EAL, "%s(): could not write to %s\n",
+ __func__, filename);
+ goto error;
+ }
+
+ fclose(f);
+ }
+
+ return 0;
+error:
+ if (f)
+ fclose(f);
+ return -1;
+}
+
+int pci_rebind_device(const struct rte_pci_device *dev, const char *driver)
+{
+ FILE *f;
+ char filename[PATH_MAX];
+ const struct rte_pci_addr *loc = &dev->addr;
+
+ snprintf(filename, sizeof(filename),
+ SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/driver_override",
+ loc->domain, loc->bus, loc->devid, loc->function);
+
+ f = fopen(filename, "w");
+ if (f) {
+ fclose(f);
+ return pci_rebind_device_override(dev, driver);
+ } else {
+ return pci_rebind_device_legacy(dev, driver);
+ }
+}
+
+static int
pci_parse_sysfs_driver(const char *filename, struct rte_pci_device *dev)
{
int count;
@@ -127,6 +318,25 @@ pci_parse_sysfs_driver(const char *filename, struct rte_pci_device *dev)
return 0;
}
+int
+pci_mapping_driver_bound(const struct rte_pci_device *dev)
+{
+ int ret;
+
+ switch (dev->kdrv) {
+ case RTE_KDRV_VFIO:
+ case RTE_KDRV_IGB_UIO:
+ case RTE_KDRV_UIO_GENERIC:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
/* Map pci device */
int
pci_map_device(struct rte_pci_device *dev)
--
1.9.1
next prev parent reply other threads:[~2016-01-29 14:49 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-22 15:27 [dpdk-dev] [PATCH 0/9] pci cleanup and blacklist rework David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 1/9] pci: no need for dynamic tailq init David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 2/9] pci: add internal device list helpers David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 3/9] pci: minor cleanup David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 4/9] pci: rework sysfs parsing for driver David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 5/9] pci: factorize probe/detach code David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 6/9] pci: cosmetic change David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 7/9] pci: factorize driver search David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 8/9] pci: remove driver lookup from detach David Marchand
2016-01-22 15:27 ` [dpdk-dev] [PATCH 9/9] pci: blacklist only in global probe function David Marchand
2016-01-27 13:07 ` [dpdk-dev] [PATCH 0/9] pci cleanup and blacklist rework David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 " David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 1/9] pci: add internal device list helpers David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 2/9] pci/linux: minor cleanup David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 3/9] pci/linux: rework sysfs parsing for driver David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 4/9] pci: factorize probe/detach code David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 5/9] pci: cosmetic change David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 6/9] pci: factorize driver search David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 7/9] pci: remove driver lookup from detach David Marchand
2016-01-29 14:49 ` [dpdk-dev] [PATCH v2 8/9] pci: implement blacklist using a hook David Marchand
2016-01-29 14:49 ` David Marchand [this message]
2016-02-03 9:26 ` [dpdk-dev] [PATCH v2 9/9] pci: implement automatic bind/unbind Ivan Boule
2016-02-08 13:31 ` [dpdk-dev] [PATCH v2 0/9] pci cleanup and blacklist rework Jan Viktorin
2016-02-09 8:39 ` David Marchand
2016-03-16 16:07 ` Jan Viktorin
2016-03-22 10:24 ` David Marchand
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=1454078953-23744-10-git-send-email-david.marchand@6wind.com \
--to=david.marchand@6wind.com \
--cc=dev@dpdk.org \
--cc=viktorin@rehivetech.com \
/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).