From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gaetan Rivet Subject: [PATCH v2 09/18] eal/dev: implement device iteration Date: Wed, 21 Mar 2018 18:15:30 +0100 Message-ID: <390e98e1afddd5c80ba243efc44b8a047ea68710.1521652453.git.gaetan.rivet@6wind.com> References: Cc: Gaetan Rivet To: dev@dpdk.org Return-path: Received: from mail-wm0-f67.google.com (mail-wm0-f67.google.com [74.125.82.67]) by dpdk.org (Postfix) with ESMTP id 62E3C7CF1 for ; Wed, 21 Mar 2018 18:16:11 +0100 (CET) Received: by mail-wm0-f67.google.com with SMTP id f19so11170953wmc.0 for ; Wed, 21 Mar 2018 10:16:11 -0700 (PDT) In-Reply-To: In-Reply-To: References: List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Use the iteration hooks in the abstraction layers to perform the requested filtering on the internal device lists. Signed-off-by: Gaetan Rivet --- lib/librte_eal/common/eal_common_dev.c | 159 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 25 +++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 185 insertions(+) diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c index bdab1423a..4efc27462 100644 --- a/lib/librte_eal/common/eal_common_dev.c +++ b/lib/librte_eal/common/eal_common_dev.c @@ -19,6 +19,28 @@ #include "eal_private.h" +struct dev_next_ctx { + struct rte_dev_iterator *it; + const char *busstr; + const char *clsstr; +}; + +#define CTX(it, busstr, clsstr) \ + (&(const struct dev_next_ctx){ \ + .it = it, \ + .busstr = busstr, \ + .clsstr = clsstr, \ + }) + +#define ITCTX(ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->it + +#define BUSCTX(ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->busstr + +#define CLSCTX(ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->clsstr + /* EAL-private function. */ int rte_parse_kv(const char *str, struct rte_kvarg *kv) @@ -303,3 +325,140 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str) it->cls = cls; return 0; } + +static char * +dev_str_sane_cpy(const char *str) +{ + struct rte_kvarg kv; + char *end; + char *cpy; + + if (rte_parse_kv(str, &kv)) { + rte_errno = EINVAL; + return NULL; + } + /* copying '\0' is valid. */ + if (kv.next != NULL) + cpy = strdup(kv.next); + else + cpy = strdup(""); + if (cpy == NULL) { + rte_errno = ENOMEM; + return NULL; + } + end = strchr(cpy, '/'); + if (end != NULL) + end[0] = '\0'; + return cpy; +} + +static int +class_next_dev_cmp(const struct rte_class *cls, + const void *ctx) +{ + struct rte_dev_iterator *it; + const char *clsstr = NULL; + void *dev; + + if (cls->dev_iterate == NULL) + return 1; + it = ITCTX(ctx); + clsstr = CLSCTX(ctx); + dev = it->class_device; + /* it->clsstr != NULL means a class + * was specified in the devstr. + */ + if (it->clsstr != NULL && cls != it->cls) + return 1; + dev = cls->dev_iterate(dev, clsstr, it); + it->class_device = dev; + return dev == NULL; +} + +static int +bus_next_dev_cmp(const struct rte_bus *bus, + const void *ctx) +{ + struct rte_device *dev = NULL; + struct rte_class *cls = NULL; + struct rte_dev_iterator *it; + const char *busstr = NULL; + + if (bus->dev_iterate == NULL) + return 1; + it = ITCTX(ctx); + busstr = BUSCTX(ctx); + dev = it->device; + /* it->busstr != NULL means a bus + * was specified in the devstr. + */ + if (it->busstr != NULL && bus != it->bus) + return 1; + if (it->clsstr == NULL) { + dev = bus->dev_iterate(dev, busstr, it); + goto end; + } + /* clsstr != NULL */ + if (dev == NULL) { +next_dev_on_bus: + dev = bus->dev_iterate(dev, busstr, it); + it->device = dev; + } + if (dev == NULL) + return 1; + if (it->cls != NULL) + cls = TAILQ_PREV(it->cls, rte_class_list, next); + cls = rte_class_find(cls, class_next_dev_cmp, ctx); + if (cls != NULL) { + it->cls = cls; + goto end; + } + goto next_dev_on_bus; +end: + it->device = dev; + return dev == NULL; +} +__rte_experimental +struct rte_device * +rte_dev_iterator_next(struct rte_dev_iterator *it) +{ + struct rte_bus *bus = NULL; + int old_errno = rte_errno; + char *busstr = NULL; + char *clsstr = NULL; + + rte_errno = 0; + if (it->busstr == NULL && it->clsstr == NULL) { + /* Invalid iterator. */ + rte_errno = EINVAL; + return NULL; + } + if (it->bus != NULL) + bus = TAILQ_PREV(it->bus, rte_bus_list, next); + if (it->busstr != NULL) { + busstr = dev_str_sane_cpy(it->busstr); + if (busstr == NULL) + goto out; + } + if (it->clsstr != NULL) { + clsstr = dev_str_sane_cpy(it->clsstr); + if (clsstr == NULL) + goto out; + } + while ((bus = rte_bus_find(bus, bus_next_dev_cmp, + CTX(it, busstr, clsstr)))) { + if (it->device != NULL) { + it->bus = bus; + goto out; + } + if (it->busstr != NULL || + rte_errno != 0) + break; + } + if (rte_errno == 0) + rte_errno = old_errno; +out: + free(busstr); + free(clsstr); + return it->device; +} diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h index 7ce13e068..dfb5d696f 100644 --- a/lib/librte_eal/common/include/rte_dev.h +++ b/lib/librte_eal/common/include/rte_dev.h @@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start, int __rte_experimental rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str); +/** + * Iterates on a device iterator. + * + * Generates a new rte_device handle corresponding to the next element + * in the list described in comprehension by the iterator. + * + * The next object is returned, and the iterator is updated. + * + * @param it + * Device iterator handle. + * + * @return + * An rte_device handle if found. + * NULL if an error occurred (rte_errno is set). + * NULL if no device could be found (rte_errno is not set). + */ +struct rte_device * __rte_experimental +rte_dev_iterator_next(struct rte_dev_iterator *it); + +#define RTE_DEV_FOREACH(dev, devstr, it) \ + for (rte_dev_iterator_init(it, devstr), \ + dev = rte_dev_iterator_next(it); \ + dev != NULL; \ + dev = rte_dev_iterator_next(it)) + #ifdef __cplusplus } #endif diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map index 921da3075..925efcb6d 100644 --- a/lib/librte_eal/rte_eal_version.map +++ b/lib/librte_eal/rte_eal_version.map @@ -229,6 +229,7 @@ EXPERIMENTAL { rte_mp_request; rte_mp_reply; rte_dev_iterator_init; + rte_dev_iterator_next; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register; -- 2.11.0