From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from wes1-so2.wedos.net (wes1-so2.wedos.net [46.28.106.16]) by dpdk.org (Postfix) with ESMTP id 3349A5592 for ; Fri, 6 May 2016 15:50:09 +0200 (CEST) Received: from pcviktorin.fit.vutbr.cz (pcviktorin.fit.vutbr.cz [147.229.13.147]) by wes1-so2.wedos.net (Postfix) with ESMTPSA id 3r1Y7P09Nhz78C; Fri, 6 May 2016 15:50:09 +0200 (CEST) From: Jan Viktorin To: dev@dpdk.org Cc: Jan Viktorin , David Marchand , Thomas Monjalon , Bruce Richardson , Declan Doherty , jianbo.liu@linaro.org, jerin.jacob@caviumnetworks.com, Keith Wiles , Stephen Hemminger Date: Fri, 6 May 2016 15:47:50 +0200 Message-Id: <1462542490-15556-9-git-send-email-viktorin@rehivetech.com> X-Mailer: git-send-email 2.8.0 In-Reply-To: <1462542490-15556-1-git-send-email-viktorin@rehivetech.com> References: <1462542490-15556-1-git-send-email-viktorin@rehivetech.com> In-Reply-To: <1451682326-5834-1-git-send-email-viktorin@rehivetech.com> References: <1451682326-5834-1-git-send-email-viktorin@rehivetech.com> Subject: [dpdk-dev] [PATCH v1 08/28] eal/soc: implement SoC device discovery X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 06 May 2016 13:50:09 -0000 Signed-off-by: Jan Viktorin --- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/bsdapp/eal/eal_soc.c | 40 ++++ lib/librte_eal/bsdapp/eal/rte_eal_version.map | 3 + lib/librte_eal/common/eal_common_soc.c | 45 ++++ lib/librte_eal/common/include/rte_soc.h | 14 ++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/linuxapp/eal/eal_soc.c | 282 ++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/rte_eal_version.map | 4 + 8 files changed, 390 insertions(+) create mode 100644 lib/librte_eal/bsdapp/eal/eal_soc.c create mode 100644 lib/librte_eal/linuxapp/eal/eal_soc.c diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile index d956808..7ac6c94 100644 --- a/lib/librte_eal/bsdapp/eal/Makefile +++ b/lib/librte_eal/bsdapp/eal/Makefile @@ -58,6 +58,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_memory.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_hugepage_info.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_log.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_soc.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_pci.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_debug.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_lcore.c diff --git a/lib/librte_eal/bsdapp/eal/eal_soc.c b/lib/librte_eal/bsdapp/eal/eal_soc.c new file mode 100644 index 0000000..f84aae9 --- /dev/null +++ b/lib/librte_eal/bsdapp/eal/eal_soc.c @@ -0,0 +1,40 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +int +rte_eal_soc_scan(void) +{ + return 0; +} diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index c430b4b..4a2eeaf 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -158,7 +158,10 @@ DPDK_16.07 { rte_eal_dev_attach; rte_eal_dev_detach; + soc_get_sysfs_path; rte_eal_soc_register; rte_eal_soc_unregister; + rte_eal_soc_scan; + rte_eal_soc_dump; } DPDK_16.04; diff --git a/lib/librte_eal/common/eal_common_soc.c b/lib/librte_eal/common/eal_common_soc.c index afeed2f..d8bb6d6 100644 --- a/lib/librte_eal/common/eal_common_soc.c +++ b/lib/librte_eal/common/eal_common_soc.c @@ -31,6 +31,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include #include @@ -39,6 +41,49 @@ struct soc_driver_list soc_driver_list = TAILQ_HEAD_INITIALIZER(soc_driver_list); +struct soc_device_list soc_device_list = + TAILQ_HEAD_INITIALIZER(soc_device_list); + +/** Pathname of SoC devices directory. */ +#define SYSFS_SOC_DEVICES "/sys/bus/platform/devices" + +const char *soc_get_sysfs_path(void) +{ + const char *path = NULL; + + path = getenv("SYSFS_SOC_DEVICES"); + if (path == NULL) + return SYSFS_SOC_DEVICES; + + return path; +} + +/* dump one device */ +static int +soc_dump_one_device(FILE *f, struct rte_soc_device *dev) +{ + int i; + + fprintf(f, "%s", dev->addr.name); + fprintf(f, " - fdt_path: %s\n", + dev->addr.fdt_path? dev->addr.fdt_path : "(none)"); + + for (i = 0; dev->id && dev->id[i].compatible; ++i) + fprintf(f, " %s\n", dev->id[i].compatible); + + return 0; +} + +/* dump devices on the bus */ +void +rte_eal_soc_dump(FILE *f) +{ + struct rte_soc_device *dev = NULL; + + TAILQ_FOREACH(dev, &soc_device_list, next) { + soc_dump_one_device(f, dev); + } +} /* register a driver */ void diff --git a/lib/librte_eal/common/include/rte_soc.h b/lib/librte_eal/common/include/rte_soc.h index 28c1798..6278295 100644 --- a/lib/librte_eal/common/include/rte_soc.h +++ b/lib/librte_eal/common/include/rte_soc.h @@ -55,8 +55,13 @@ extern "C" { #include TAILQ_HEAD(soc_driver_list, rte_soc_driver); /**< SoC drivers in D-linked Q. */ +TAILQ_HEAD(soc_device_list, rte_soc_device); /**< SoC devices in D-linked Q. */ extern struct soc_driver_list soc_driver_list; /**< Global list of SoC drivers. */ +extern struct soc_device_list soc_device_list; /**< Global list of SoC devices. */ + +/** Return SoC scan path of the sysfs root. */ +const char *soc_get_sysfs_path(void); struct rte_soc_id { const char *compatible; /**< OF compatible specification */ @@ -136,6 +141,15 @@ rte_eal_compare_soc_addr(const struct rte_soc_addr *a0, return strcmp(a0->name, a1->name); } +/** + * Scan for new SoC devices. + */ +int rte_eal_soc_scan(void); + +/** + * Dump discovered SoC devices. + */ +void rte_eal_soc_dump(FILE *f); /** * Register a SoC driver. diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile index 37ab8d5..85a892a 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -63,6 +63,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_xen_memory.c endif SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_log.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_soc.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci_uio.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci_vfio.c diff --git a/lib/librte_eal/linuxapp/eal/eal_soc.c b/lib/librte_eal/linuxapp/eal/eal_soc.c new file mode 100644 index 0000000..8dbb367 --- /dev/null +++ b/lib/librte_eal/linuxapp/eal/eal_soc.c @@ -0,0 +1,282 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "eal_private.h" + +static char * +dev_read_uevent(const char *dirname) +{ + char filename[PATH_MAX]; + struct stat st; + char *buf; + ssize_t total = 0; + int fd; + + snprintf(filename, sizeof(filename), "%s/uevent", dirname); + fd = open(filename, O_RDONLY); + if (fd < 0) { + RTE_LOG(WARNING, EAL, "Failed to open file %s\n", filename); + return strdup(""); + } + + if (fstat(fd, &st) < 0) { + RTE_LOG(ERR, EAL, "Failed to stat file %s\n", filename); + close(fd); + return NULL; + } + + if (st.st_size == 0) { + close(fd); + return strdup(""); + } + + buf = malloc(st.st_size + 1); + if (buf == NULL) { + RTE_LOG(ERR, EAL, "Failed to alloc memory to read %s\n", filename); + close(fd); + return NULL; + } + + while (total < st.st_size) { + ssize_t rlen = read(fd, buf + total, st.st_size - total); + if (rlen < 0) { + if (errno == EINTR) + continue; + + RTE_LOG(ERR, EAL, "Failed to read file %s\n", filename); + + free(buf); + close(fd); + return NULL; + } + if (rlen == 0) /* EOF */ + break; + + total += rlen; + } + + buf[total] = '\0'; + close(fd); + + return buf; +} + +static const char * +dev_uevent_find(const char *uevent, const char *key) +{ + const size_t keylen = strlen(key); + const size_t total = strlen(uevent); + const char *p = uevent; + + /* check whether it is the first key */ + if (!strncmp(uevent, key, keylen)) + return uevent + keylen; + + /* check 2nd key or further... */ + do { + p = strstr(p, key); + if (p == NULL) + break; + + if (p[-1] == '\n') /* check we are at a new line */ + return p + keylen; + + p += keylen; /* skip this one */ + } while(p - uevent < (ptrdiff_t) total); + + return NULL; +} + +static char * +strdup_until_nl(const char *p) +{ + const char *nl = strchr(p, '\n'); + if (nl == NULL) + return strdup(p); /* no newline, copy until '\0' */ + + return strndup(p, nl - p); +} + +static int +dev_parse_uevent(struct rte_soc_device *dev, const char *uevent) +{ + const char *of; + + of = dev_uevent_find(uevent, "OF_FULLNAME="); + if (of == NULL) + return 1; /* don't care about this device */ + + dev->addr.fdt_path = strdup_until_nl(of); + if (dev->addr.fdt_path == NULL) { + RTE_LOG(ERR, PMD, + "Failed to alloc memory for fdt_path\n"); + return -1; + } + + RTE_LOG(DEBUG, EAL, "Detected device %s (%s)\n", + dev->addr.name, dev->addr.fdt_path); + + dev->id = calloc(1, sizeof(*dev->id)); + if (dev->id == NULL) { + free(dev->addr.fdt_path); + return -1; + } + + return 0; +} + +static void +dev_content_free(struct rte_soc_device *dev) +{ + if (dev->addr.fdt_path) + free(dev->addr.fdt_path); + + free(dev->id); + dev->id = NULL; +} + +/** + * Scan one SoC sysfs entry, and fill the devices list from it. + * We require to have the uevent file with records: OF_FULLNAME and + * OF_COMPATIBLE array (with at least one entry). Otherwise, such device + * is skipped. + */ +static int +soc_scan_one(const char *dirname, const char *name) +{ + struct rte_soc_device *dev; + char *uevent; + int ret; + + uevent = dev_read_uevent(dirname); + if (uevent == NULL) + return -1; + + if (uevent[0] == '\0') { + /* ignore directory without uevent file */ + free(uevent); + return 1; + } + + dev = malloc(sizeof(*dev) + strlen(name) + 1); + if (dev == NULL) { + RTE_LOG(ERR, PMD, "Failed to alloc memory for %s\n", name); + free(uevent); + return -1; + } + + memset(dev, 0, sizeof(*dev)); + dev->addr.name = (char *) (dev + 1); + strcpy(dev->addr.name, name); + + if ((ret = dev_parse_uevent(dev, uevent))) + goto fail; + free(uevent); /* not needed anymore */ + + /* device is valid, add in list (sorted) */ + if (TAILQ_EMPTY(&soc_device_list)) { + TAILQ_INSERT_TAIL(&soc_device_list, dev, next); + } else { + struct rte_soc_device *dev2; + + TAILQ_FOREACH(dev2, &soc_device_list, next) { + ret = rte_eal_compare_soc_addr(&dev->addr, &dev2->addr); + if (ret > 0) + continue; + + if (ret < 0) { + TAILQ_INSERT_BEFORE(dev2, dev, next); + } else { /* already registered */ + + dev_content_free(dev2); + dev2->addr.fdt_path = dev->addr.fdt_path; + dev2->id = dev->id; + free(dev); + } + return 0; + } + TAILQ_INSERT_TAIL(&soc_device_list, dev, next); + } + + return 0; + +fail: + free(uevent); + dev_content_free(dev); + free(dev); + return ret; +} + +int +rte_eal_soc_scan(void) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + dir = opendir(soc_get_sysfs_path()); + if (dir == NULL) { + RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n", + __func__, strerror(errno)); + return -1; + } + + while ((e = readdir(dir)) != NULL) { + if (e->d_name[0] == '.') + continue; + + snprintf(dirname, sizeof(dirname), "%s/%s", + soc_get_sysfs_path(), e->d_name); + if (soc_scan_one(dirname, e->d_name) < 0) + goto error; + } + closedir(dir); + return 0; + +error: + closedir(dir); + return -1; +} diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index 6ff38b8..280622f 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -162,7 +162,11 @@ DPDK_16.07 { rte_eal_dev_detach; soc_driver_list; + soc_device_list; + soc_get_sysfs_path; rte_eal_soc_register; rte_eal_soc_unregister; + rte_eal_soc_scan; + rte_eal_soc_dump; } DPDK_16.04; -- 2.8.0