From cea82d8fd1697132be6d28a6db10a23dff50e782 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:08 +0100 Subject: [PATCH 01/23] drv: adding compiler hints in the driver interface Largely inspired from its north api counterpart, the drv/spec/hint.h file is added. Also includes the __constructor__ attributes that many driver interface items will need. Signed-off-by: Christophe Milard --- include/odp/drv/spec/hints.h | 119 +++++++++++++++++++++++++++++++++++ platform/Makefile.inc | 1 + 2 files changed, 120 insertions(+) create mode 100644 include/odp/drv/spec/hints.h diff --git a/include/odp/drv/spec/hints.h b/include/odp/drv/spec/hints.h new file mode 100644 index 0000000000..f29dcd8865 --- /dev/null +++ b/include/odp/drv/spec/hints.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODPDRV compiler hints + */ + +#ifndef ODPDRV_API_HINTS_H_ +#define ODPDRV_API_HINTS_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup odpdrv_compiler_optim + * Macros that will give hints to the compiler. + * @{ + */ + +#ifdef __GNUC__ + +/** Define a function that should be run at early init (constructor) + */ +#define ODPDRV_CONSTRUCTOR __attribute__((__constructor__)) + +/** Define a function that does not return + */ +#define ODPDRV_NORETURN __attribute__((__noreturn__)) + +/** Define a weak symbol + * This is primarily useful in defining library functions that can be + * overridden in user code. + */ +#define ODPDRV_WEAK_SYMBOL __attribute__((__weak__)) + +/** + * Hot code section + */ +#define ODPDRV_HOT_CODE __attribute__((__hot__)) + +/** + * Cold code section + */ +#define ODPDRV_COLD_CODE __attribute__((__cold__)) + +/** + * Printf format attribute + */ +#define ODPDRV_PRINTF_FORMAT(x, y) __attribute__((format(printf, (x), (y)))) + +/** + * Indicate deprecated variables, functions or types + */ +#define ODPDRV_DEPRECATED __attribute__((__deprecated__)) + +/** + * Intentionally unused variables of functions + */ +#define ODPDRV_UNUSED __attribute__((__unused__)) + +/** + * Branch likely taken + */ +#define odpdrv_likely(x) __builtin_expect((x), 1) + +/** + * Branch unlikely taken + */ +#define odpdrv_unlikely(x) __builtin_expect((x), 0) + +/* + * __builtin_prefetch (const void *addr, rw, locality) + * + * rw 0..1 (0: read, 1: write) + * locality 0..3 (0: don't leave to cache, 3: leave on all cache levels) + */ + +/** + * Cache prefetch address + */ +#define odpdrv_prefetch(x) __builtin_prefetch((x), 0, 3) + +/** + * Cache prefetch address for storing + */ +#define odpdrv_prefetch_store(x) __builtin_prefetch((x), 1, 3) + +#else + +#define ODPDRV_CONSTRUCTOR +#define ODPDRV_NORETURN +#define ODPDRV_WEAK_SYMBOL +#define ODPDRV_HOT_CODE +#define ODPDRV_COLD_CODE +#define ODPDRV_DEPRECATED +#define ODPDRV_UNUSED +#define odpdrv_likely(x) (x) +#define odpdrv_unlikely(x) (x) +#define odpdrv_prefetch(x) +#define odpdrv_prefetch_store(x) + +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include +#endif diff --git a/platform/Makefile.inc b/platform/Makefile.inc index 3d609aa71a..2b89709381 100644 --- a/platform/Makefile.inc +++ b/platform/Makefile.inc @@ -71,6 +71,7 @@ odpdrvspecinclude_HEADERS = \ $(top_srcdir)/include/odp/drv/spec/byteorder.h \ $(top_srcdir)/include/odp/drv/spec/compiler.h \ $(top_srcdir)/include/odp/drv/spec/driver.h \ + $(top_srcdir)/include/odp/drv/spec/hints.h \ $(top_srcdir)/include/odp/drv/spec/shm.h \ $(top_srcdir)/include/odp/drv/spec/spinlock.h \ $(top_srcdir)/include/odp/drv/spec/std_types.h \ From 65f2f6313487bbdd96ac1c3c859dd3eb27d4dd98 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:09 +0100 Subject: [PATCH 02/23] linux-gen: adding compiler hints in the driver interface Just including the spec file from the linux-generic side, as usual. Signed-off-by: Christophe Milard --- include/odp_drv.h | 1 + platform/linux-generic/Makefile.am | 1 + .../linux-generic/include/odp/drv/hints.h | 34 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 platform/linux-generic/include/odp/drv/hints.h diff --git a/include/odp_drv.h b/include/odp_drv.h index 96d81ba6e5..cdba2262c5 100644 --- a/include/odp_drv.h +++ b/include/odp_drv.h @@ -24,6 +24,7 @@ extern C { #include #include #include +#include #include #include #include diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 79f0e70c18..bcf1dde9fe 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -120,6 +120,7 @@ odpdrvinclude_HEADERS = \ $(srcdir)/include/odp/drv/byteorder.h \ $(srcdir)/include/odp/drv/compiler.h \ $(srcdir)/include/odp/drv/driver.h \ + $(srcdir)/include/odp/drv/hints.h \ $(srcdir)/include/odp/drv/shm.h \ $(srcdir)/include/odp/drv/spinlock.h \ $(srcdir)/include/odp/drv/std_types.h \ diff --git a/platform/linux-generic/include/odp/drv/hints.h b/platform/linux-generic/include/odp/drv/hints.h new file mode 100644 index 0000000000..808c22ca30 --- /dev/null +++ b/platform/linux-generic/include/odp/drv/hints.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODPDRV compiler hints + */ + +#ifndef ODPDRV_PLAT_HINTS_H_ +#define ODPDRV_PLAT_HINTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @ingroup odpdrv_compiler_optim + * @{ + */ + +/** + * @} + */ + +#include + +#ifdef __cplusplus +} +#endif + +#endif From f8be78804e51de4d34bfb2211d0198e727474d3e Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:10 +0100 Subject: [PATCH 03/23] drv: making parameter strings dynamically computable Declaring strings as const in the driver API prevents dynamic calculation of these strings, which is a drawback. For instance, the device addresses (string) are typically calculated by enumerators, and should therefore not be const... Other strings may also be the result of a computation. This change is made to allow this. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index d83e907cde..b08d7fb7c0 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -170,7 +170,7 @@ struct odpdrv_enumr_class_param_t { /** Enumerator name: mostly used for debug purpose. * Name must be unique (e.g. "PCI-DPAA2") */ - const char name[ODPDRV_NAME_SIZE]; + char name[ODPDRV_NAME_SIZE]; /** Probe function: * Called by ODP to get the enumerator class instances registered @@ -198,7 +198,7 @@ struct odpdrv_enumr_param_t { * The format of the enum_dev part for the odpdrv_device_param_t * structure is identified by the api-name and version below */ - const char api_name[ODPDRV_NAME_SIZE]; + char api_name[ODPDRV_NAME_SIZE]; uint32_t api_version; /**<< the version of the provided API */ /** Probe function: @@ -240,7 +240,7 @@ struct odpdrv_device_param_t { * e.g. "0000.23.12.1" for PCI domain 0, bus 23, device 12, function 1. * This string identifies the device uniquely. */ - const char address[ODPDRV_NAME_ADDR_SZ]; + char address[ODPDRV_NAME_ADDR_SZ]; /** Enumerator dependent part * This part is allocated by the enumerator and is enumerator dependent @@ -260,13 +260,13 @@ struct odpdrv_devio_param_t { * with same provided interface should refer to a common enumerator * class) */ - const char api_name[ODPDRV_NAME_SIZE]; + char api_name[ODPDRV_NAME_SIZE]; uint32_t api_version; /**<< the version of the provided API */ /** Enumerator interface name and version * The enumerator interface this devio needs. */ - const char enumr_api_name[ODPDRV_NAME_SIZE]; + char enumr_api_name[ODPDRV_NAME_SIZE]; uint32_t enumr_api_version; /**<< required enumerator API version */ /** Ops @@ -283,14 +283,14 @@ struct odpdrv_driver_param_t { * The driver name (the pair {driver-name, enum-api-name} must * be unique) */ - const char name[ODPDRV_NAME_SIZE]; + char name[ODPDRV_NAME_SIZE]; /** Supported devios: * The list of supported devio: one of the following devio * (with correct version) must be available for the driver to work: */ struct { - const char api_name[ODPDRV_NAME_SIZE]; /**<< devio API name */ + char api_name[ODPDRV_NAME_SIZE]; /**<< devio API name */ uint32_t api_version; /**<< devio API version */ } devios[ODPDRV_MAX_DEVIOS]; From d1c2abf1d45b0c3862dea7c1891ae827df1ca059 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:11 +0100 Subject: [PATCH 04/23] linux-gen: drv: enumerator_class registration The functions to register and probe enumerator classes are added. Signed-off-by: Christophe Milard --- platform/linux-generic/Makefile.am | 1 + platform/linux-generic/_modules.c | 4 + platform/linux-generic/drv_driver.c | 213 +++++++++++++++++- .../include/drv_driver_internal.h | 22 ++ platform/linux-generic/include/odp_internal.h | 5 + platform/linux-generic/odp_init.c | 21 +- 6 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 platform/linux-generic/include/drv_driver_internal.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index bcf1dde9fe..7cf16dac88 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -142,6 +142,7 @@ noinst_HEADERS = \ ${srcdir}/include/_ishm_internal.h \ ${srcdir}/include/_ishmphy_internal.h \ ${srcdir}/include/_ishmpool_internal.h \ + ${srcdir}/include/drv_driver_internal.h\ ${srcdir}/include/odp_align_internal.h \ ${srcdir}/include/odp_atomic_internal.h \ ${srcdir}/include/odp_buffer_inlines.h \ diff --git a/platform/linux-generic/_modules.c b/platform/linux-generic/_modules.c index 6bb854e9c8..b23c81fec4 100644 --- a/platform/linux-generic/_modules.c +++ b/platform/linux-generic/_modules.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,9 @@ static int load_modules(void) ODP_DBG("module %s loaded.\n", module_name); } + /* give a chance top the driver interface to probe for new things: */ + _odpdrv_driver_probe_drv_items(); + return 0; } diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 529da48fe3..29608210ad 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -4,20 +4,132 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include + #include +#include <_ishmpool_internal.h> #include #include +#include #include +#include #include +#include + +static enum {UNDONE, IN_PROGRESS, DONE} init_global_status; + +/* pool from which different list elements are alocated: */ +#define ELT_POOL_SIZE (1 << 20) /* 1Mb */ +static _odp_ishm_pool_t *list_elt_pool; + +typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; + +/* an enumerator class (list element) */ +struct _odpdrv_enumr_class_s { + odpdrv_enumr_class_param_t param; + int probed; + _odp_ishm_pool_t *pool; + struct _odpdrv_enumr_class_s *next; +}; + +/* the enumerator class list: */ +typedef struct _odpdrv_enumr_class_lst_t { + odp_rwlock_recursive_t lock; + _odpdrv_enumr_class_t *head; +} _odpdrv_enumr_class_lst_t; +static struct _odpdrv_enumr_class_lst_t enumr_class_lst; + +/* some driver elements (such as enumeraor classes, drivers, devio) may + * register before init_global and init_local complete. Mutex will fail + * in this cases but should be used later on. + * These functions disable the usage of Mutex while it is global init i.e. + * while single threaded*/ +static void enumr_class_list_read_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_lock(&enumr_class_lst.lock); +} + +static void enumr_class_list_read_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_unlock(&enumr_class_lst.lock); +} + +static void enumr_class_list_write_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_lock(&enumr_class_lst.lock); +} + +static void enumr_class_list_write_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_unlock(&enumr_class_lst.lock); +} + odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t *param) { - ODP_ERR("NOT Supported yet! Enumerator Class %s Registration!\n.", - param->name); + _odpdrv_enumr_class_t *enumr_c; - return ODPDRV_ENUMR_CLASS_INVALID; + /* parse the list of already registered enumerator class to make + * sure no enumerator with identical name already exists: + */ + enumr_class_list_write_lock(); + enumr_c = enumr_class_lst.head; + while (enumr_c) { + if (strncmp(param->name, enumr_c->param.name, + ODPDRV_NAME_SIZE) == 0) { + ODP_ERR("enumerator class %s already exists!\n", + param->name); + enumr_class_list_write_unlock(); + return ODPDRV_ENUMR_CLASS_INVALID; + } + enumr_c = enumr_c->next; + } + + /* allocate memory for the new enumerator class: + * If init_global has not been done yet, then, we cannot allocate + * from any _ishm pool (ishm has not even been initialised at this + * stage...this happens when statically linked enumerator classes + * register: their __constructor__ function is run before main() + * is called). But any malloc performed here(before init_global) + * will be inherited by any odpthreads (process or pthreads) as we + * are still running in the ODP instantiation processes and all + * other processes are guaranteed to be descendent of this one... + * If init_global has been done, then we allocate from the _ishm pool + * to guarantee visibility from any ODP thread. + */ + + if (init_global_status == UNDONE) { + enumr_c = malloc(sizeof(_odpdrv_enumr_class_t)); + if (!enumr_c) { + enumr_class_list_write_unlock(); + return ODPDRV_ENUMR_CLASS_INVALID; + } + enumr_c->pool = NULL; + } else { + enumr_c = _odp_ishm_pool_alloc(list_elt_pool, + sizeof(_odpdrv_enumr_class_t)); + if (!enumr_c) { + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); + enumr_class_list_write_unlock(); + return ODPDRV_ENUMR_CLASS_INVALID; + } + enumr_c->pool = list_elt_pool; + } + + /* save init parameters and insert enumerator class in list */ + enumr_c->param = *param; + enumr_c->probed = 0; + enumr_c->next = enumr_class_lst.head; + enumr_class_lst.head = enumr_c; + enumr_class_list_write_unlock(); + + return (odpdrv_enumr_class_t)enumr_c; } odpdrv_enumr_t odpdrv_enumr_register(odpdrv_enumr_param_t *param) @@ -57,8 +169,101 @@ odpdrv_driver_t odpdrv_driver_register(odpdrv_driver_param_t *param) return ODPDRV_DRIVER_INVALID; } +/* the following function is called each time probing is needed, i.e. + * at init or after loading a new module as a module can be anything, + * including enumerators or drivers */ +void _odpdrv_driver_probe_drv_items(void) +{ + _odpdrv_enumr_class_t *enumr_c; + + /* probe unprobed enumerators: */ + enumr_class_list_write_lock(); + enumr_c = enumr_class_lst.head; + while (enumr_c) { + if (!enumr_c->probed) { + enumr_c->param.probe(); + enumr_c->probed = 1; + } + enumr_c = enumr_c->next; + } + enumr_class_list_write_unlock(); +} + int odpdrv_print_all(void) { - ODP_ERR("odpdrv_print_all not Supported yet!\n."); + _odpdrv_enumr_class_t *enumr_c; + + /* we cannot use ODP_DBG before ODP init... */ + if (init_global_status == UNDONE) + return 0; + + ODP_DBG("ODP Driver status:\n"); + + /* print the list of registered enumerator classes: */ + enumr_class_list_read_lock(); + enumr_c = enumr_class_lst.head; + ODP_DBG("The following enumerator classes have been registered:\n"); + while (enumr_c) { + ODP_DBG(" class: %s\n", enumr_c->param.name); + enumr_c = enumr_c->next; + } + enumr_class_list_read_unlock(); + return 0; +} + +int _odpdrv_driver_init_global(void) +{ + /* create a memory pool to for list elements: */ + list_elt_pool = _odp_ishm_pool_create(NULL, ELT_POOL_SIZE, + 0, ELT_POOL_SIZE, 0); + + /* remember that init global is being done so the further list allocs + * are made from the list_elt_pool: */ + init_global_status = IN_PROGRESS; + + /* from now, we want to ensure mutex on the list: init lock: */ + odp_rwlock_recursive_init(&enumr_class_lst.lock); + + /* probe things... */ + _odpdrv_driver_probe_drv_items(); + + return 0; +} + +int _odpdrv_driver_init_local(void) +{ + /* remember that init global is done, so list mutexes are used from + * now */ + init_global_status = DONE; + return 0; +} + +int _odpdrv_driver_term_global(void) +{ + _odpdrv_enumr_class_t *enumr_c; + + if (init_global_status == UNDONE) + return 0; + + /* remove all enumerator classes which are registered: */ + enumr_class_list_write_lock(); + while (enumr_class_lst.head) { + enumr_c = enumr_class_lst.head; + if (enumr_c->param.remove) { /* run remove callback, if any */ + if (enumr_c->param.remove()) + ODP_ERR("Enumerator class %s removal failed.\n", + enumr_c->param.name); + } + enumr_class_lst.head = enumr_c->next; + if (enumr_c->pool) + _odp_ishm_pool_free(list_elt_pool, enumr_c); + else + free(enumr_c); + } + enumr_class_list_write_unlock(); + + /* destroy the list element pool: */ + _odp_ishm_pool_destroy(list_elt_pool); + return 0; } diff --git a/platform/linux-generic/include/drv_driver_internal.h b/platform/linux-generic/include/drv_driver_internal.h new file mode 100644 index 0000000000..eb06c1b476 --- /dev/null +++ b/platform/linux-generic/include/drv_driver_internal.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DRV_DRIVER_INTERNAL_H_ +#define DRV_DRIVER_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void _odpdrv_driver_probe_drv_items(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h index 90e2a629ff..fa4414888d 100644 --- a/platform/linux-generic/include/odp_internal.h +++ b/platform/linux-generic/include/odp_internal.h @@ -70,6 +70,7 @@ enum init_stage { CLASSIFICATION_INIT, TRAFFIC_MNGR_INIT, NAME_TABLE_INIT, + DRIVER_INIT, MODULES_INIT, ALL_INIT /* All init stages completed */ }; @@ -129,6 +130,10 @@ int _odp_ishm_init_local(void); int _odp_ishm_term_global(void); int _odp_ishm_term_local(void); +int _odpdrv_driver_init_global(void); +int _odpdrv_driver_init_local(void); +int _odpdrv_driver_term_global(void); + int _odp_modules_init_global(void); int cpuinfo_parser(FILE *file, system_info_t *sysinfo); diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c index 685e02fad6..c59cc2818d 100644 --- a/platform/linux-generic/odp_init.c +++ b/platform/linux-generic/odp_init.c @@ -266,6 +266,12 @@ int odp_init_global(odp_instance_t *instance, } stage = NAME_TABLE_INIT; + if (_odpdrv_driver_init_global()) { + ODP_ERR("ODP drivers init failed\n"); + goto init_failed; + } + stage = DRIVER_INIT; + if (_odp_modules_init_global()) { ODP_ERR("ODP modules init failed\n"); goto init_failed; @@ -296,6 +302,13 @@ int _odp_term_global(enum init_stage stage) switch (stage) { case ALL_INIT: case MODULES_INIT: + case DRIVER_INIT: + if (_odpdrv_driver_term_global()) { + ODP_ERR("driver term failed.\n"); + rc = -1; + } + /* Fall through */ + case NAME_TABLE_INIT: if (_odp_int_name_tbl_term_global()) { ODP_ERR("Name table term failed.\n"); @@ -445,7 +458,13 @@ int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type) ODP_ERR("ODP schedule local init failed.\n"); goto init_fail; } - /* stage = SCHED_INIT; */ + stage = SCHED_INIT; + + if (_odpdrv_driver_init_local()) { + ODP_ERR("ODP driver local init failed.\n"); + goto init_fail; + } + /* stage = DRIVER_INIT; */ return 0; From 42d93be224cb9c1e987b7ad96f7c496aa8654abe Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:12 +0100 Subject: [PATCH 05/23] test: drv: enumerator_class registration tests Testing that enumerators classes can register properly. Saddly restricted to statically linked enumerators classes, as testing with modules in autotools seems to be an issue so far. Signed-off-by: Christophe Milard --- test/common_plat/m4/configure.m4 | 1 + test/common_plat/validation/drv/Makefile.am | 1 + .../validation/drv/drvdriver/.gitignore | 1 + .../validation/drv/drvdriver/Makefile.am | 16 ++ .../drv/drvdriver/drvdriver_enumr_class.c | 174 ++++++++++++++++++ .../drv/drvdriver/drvdriver_enumr_class.h | 24 +++ .../drvdriver/drvdriver_enumr_class_main.c | 12 ++ test/linux-generic/Makefile.am | 1 + 8 files changed, 230 insertions(+) create mode 100644 test/common_plat/validation/drv/drvdriver/.gitignore create mode 100644 test/common_plat/validation/drv/drvdriver/Makefile.am create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.h create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class_main.c diff --git a/test/common_plat/m4/configure.m4 b/test/common_plat/m4/configure.m4 index 13a13bd503..400750c65e 100644 --- a/test/common_plat/m4/configure.m4 +++ b/test/common_plat/m4/configure.m4 @@ -34,4 +34,5 @@ AC_CONFIG_FILES([test/common_plat/Makefile test/common_plat/validation/api/traffic_mngr/Makefile test/common_plat/validation/drv/Makefile test/common_plat/validation/drv/drvatomic/Makefile + test/common_plat/validation/drv/drvdriver/Makefile test/common_plat/validation/drv/drvshmem/Makefile]) diff --git a/test/common_plat/validation/drv/Makefile.am b/test/common_plat/validation/drv/Makefile.am index bcdb92e2d3..7329a89bcb 100644 --- a/test/common_plat/validation/drv/Makefile.am +++ b/test/common_plat/validation/drv/Makefile.am @@ -1,4 +1,5 @@ ODPDRV_MODULES = drvatomic \ + drvdriver \ drvshmem SUBDIRS = $(ODPDRV_MODULES) diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore new file mode 100644 index 0000000000..9268315ef1 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/.gitignore @@ -0,0 +1 @@ +drvdriver_enumr_class_main diff --git a/test/common_plat/validation/drv/drvdriver/Makefile.am b/test/common_plat/validation/drv/drvdriver/Makefile.am new file mode 100644 index 0000000000..9e941eedf5 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/Makefile.am @@ -0,0 +1,16 @@ +include ../Makefile.inc + +# because most of driver activity occurs at init time, and due to the +# fact that many sequential ODP runs are not allowed from the same process, +# we need different binaries for each things being tested (as API init) + +#tests for enumerator class registration: +noinst_LTLIBRARIES = libtestdrvdriverenumrclass.la +libtestdrvdriverenumrclass_la_SOURCES = drvdriver_enumr_class.c + +test_PROGRAMS = drvdriver_enumr_class_main$(EXEEXT) +dist_drvdriver_enumr_class_main_SOURCES = drvdriver_enumr_class_main.c +drvdriver_enumr_class_main_LDADD = libtestdrvdriverenumrclass.la \ + $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST = drvdriver_enumr_class.h diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.c b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.c new file mode 100644 index 0000000000..f7dd42cf25 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include "drvdriver_enumr_class.h" +#include + +static odp_instance_t odp_instance; + +static int enumr_class1_probed; +static int enumr_class2_probed; + +/* forward declaration */ +static int enumr_class1_probe(void); +static int enumr_class2_probe(void); + +static int enumr_class1_remove(void); +static int enumr_class2_remove(void); + +/* because many things to be checked are performed during ODP initialisation, + * the initialisation functions have to be a part of the test + */ +static int tests_global_init(void) +{ + if (0 != odp_init_global(&odp_instance, NULL, NULL)) { + fprintf(stderr, "error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(odp_instance, ODP_THREAD_CONTROL)) { + fprintf(stderr, "error: odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +static int tests_global_term(void) +{ + if (0 != odp_term_local()) { + fprintf(stderr, "error: odp_term_local() failed.\n"); + return -1; + } + + if (0 != odp_term_global(odp_instance)) { + fprintf(stderr, "error: odp_term_global() failed.\n"); + return -1; + } + + return 0; +} + +/*enumerator class register functions, all "statically linked" + *(i.e. directely run at start), due to the fact that platorm independent + * shared lib loading in autotools is a mess */ +static void ODPDRV_CONSTRUCTOR enumr_class1_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class1", + .probe = enumr_class1_probe, + .remove = enumr_class1_remove + }; + + odpdrv_enumr_class_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR enumr_class2_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class2", + .probe = enumr_class2_probe, + .remove = enumr_class2_remove + }; + + odpdrv_enumr_class_register(¶m); +} + +static odpdrv_enumr_class_t enumr_class2_register_retry(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class2", + .probe = enumr_class2_probe, + .remove = enumr_class2_remove + }; + + return odpdrv_enumr_class_register(¶m); +} + +/*enumerator class probe functions, just making sure they have been run: */ +static int enumr_class1_probe(void) +{ + enumr_class1_probed = 1; + return 0; +} + +static int enumr_class2_probe(void) +{ + enumr_class2_probed = 1; + return 0; +} + +/*enumerator class remove functions, just making sure they have been run: */ +static int enumr_class1_remove(void) +{ + enumr_class1_probed = -1; + return 0; +} + +static int enumr_class2_remove(void) +{ + enumr_class2_probed = -1; + return 0; +} + +void drvdriver_test_enumr_class_register(void) +{ + CU_ASSERT(enumr_class1_probed == 0); + CU_ASSERT(enumr_class2_probed == 0); + + CU_ASSERT(tests_global_init() == 0); + + /* at this point (after odp init), the constructor + * enumerator classes should have registered and been probed: + */ + CU_ASSERT(odpdrv_print_all() == 0); + + CU_ASSERT(enumr_class1_probed == 1); + CU_ASSERT(enumr_class2_probed == 1); + CU_ASSERT(odpdrv_print_all() == 0); + + /* re-register enumr_class2: this should be kicked-out! */ + CU_ASSERT(enumr_class2_register_retry() == ODPDRV_ENUMR_CLASS_INVALID); + + CU_ASSERT(tests_global_term() == 0); + + /* after ODP termination completion, all enumerators should be removed*/ + CU_ASSERT(enumr_class1_probed == -1); + CU_ASSERT(enumr_class2_probed == -1); +} + +odp_testinfo_t drvdriver_suite_enumr_class[] = { + ODP_TEST_INFO(drvdriver_test_enumr_class_register), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvdriver_suites_enumr_class[] = { + {"Enumerator registration", NULL, NULL, drvdriver_suite_enumr_class}, + ODP_SUITE_INFO_NULL, +}; + +int drvdriver_enumr_class_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + /* prevent default ODP init: */ + odp_cunit_register_global_init(NULL); + odp_cunit_register_global_term(NULL); + + /* register the tests: */ + ret = odp_cunit_register(drvdriver_suites_enumr_class); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.h b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.h new file mode 100644 index 0000000000..a4f6cdc784 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVDRIVER_ENUMR_CLASS_H_ +#define _ODP_TEST_DRVDRIVER_ENUMR_CLASS_H_ + +#include + +/* test functions: */ +void drvdriver_test_enumr_class_register(void); + +/* test arrays: */ +extern odp_testinfo_t drvdriver_suite_enumr_class[]; + +/* test registry: */ +extern odp_suiteinfo_t drvdriver_suites_enumr_class[]; + +/* main test program: */ +int drvdriver_enumr_class_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class_main.c b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class_main.c new file mode 100644 index 0000000000..45a4c1a152 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvdriver_enumr_class.h" + +int main(int argc, char *argv[]) +{ + return drvdriver_enumr_class_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index 7f2a933e27..38be049e10 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -36,6 +36,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_API_VALIDATION_DIR)/shmem/shmem_main$(EXEEXT) \ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ + $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_class_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ ring/ring_main$(EXEEXT) From 8168d9e13e2c89bef4413c517a3df8199f404f84 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:13 +0100 Subject: [PATCH 06/23] linux-gen: drv: enumerator registration The enumerator registration functions for the linux-gen ODP implementation. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 139 +++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 29608210ad..df6d77d762 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -24,6 +24,7 @@ static enum {UNDONE, IN_PROGRESS, DONE} init_global_status; static _odp_ishm_pool_t *list_elt_pool; typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; +typedef struct _odpdrv_enumr_s _odpdrv_enumr_t; /* an enumerator class (list element) */ struct _odpdrv_enumr_class_s { @@ -40,6 +41,20 @@ typedef struct _odpdrv_enumr_class_lst_t { } _odpdrv_enumr_class_lst_t; static struct _odpdrv_enumr_class_lst_t enumr_class_lst; +/* an enumerator (list element) */ +struct _odpdrv_enumr_s { + odpdrv_enumr_param_t param; + int probed; + struct _odpdrv_enumr_s *next; +}; + +/* the enumerator list: */ +typedef struct _odpdrv_enumr_lst_t { + odp_rwlock_recursive_t lock; + _odpdrv_enumr_t *head; +} _odpdrv_enumr_lst_t; +static struct _odpdrv_enumr_lst_t enumr_lst; + /* some driver elements (such as enumeraor classes, drivers, devio) may * register before init_global and init_local complete. Mutex will fail * in this cases but should be used later on. @@ -69,6 +84,35 @@ static void enumr_class_list_write_unlock(void) odp_rwlock_recursive_write_unlock(&enumr_class_lst.lock); } +static void enumr_list_read_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_lock(&enumr_lst.lock); +} + +static void enumr_list_read_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_unlock(&enumr_lst.lock); +} + +static void enumr_list_write_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_lock(&enumr_lst.lock); +} + +static void enumr_list_write_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_unlock(&enumr_lst.lock); +} + +/* some functions to get internal pointers from handles... */ +static inline _odpdrv_enumr_class_t *get_enumr_class(odpdrv_enumr_class_t class) +{ + return (_odpdrv_enumr_class_t *)(void *)class; +} odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t *param) @@ -134,10 +178,51 @@ odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t odpdrv_enumr_t odpdrv_enumr_register(odpdrv_enumr_param_t *param) { - ODP_ERR("NOT Supported yet! Enumerator API %s Registration!\n.", - param->api_name); + _odpdrv_enumr_t *enumr; + _odpdrv_enumr_class_t *enumr_c; + int found_class = 0; - return ODPDRV_ENUMR_INVALID; + /* If init_global has not been done yet, we have a big issue, + * as none of the enumerator classes have been probed before that! + * We cannot even issue an error as ODP_* functions have not been + * initialised yet, but this is no good... + */ + if (init_global_status == UNDONE) + return ODPDRV_ENUMR_INVALID; + + /* make sure that the provided enumerator_class does indeed exist: */ + enumr_class_list_read_lock(); + enumr_c = enumr_class_lst.head; + while (enumr_c) { + if (get_enumr_class(param->enumr_class) == enumr_c) { + found_class = 1; + break; + } + enumr_c = enumr_c->next; + } + enumr_class_list_read_unlock(); + if (!found_class) { + ODP_ERR("invalid enumerator class provided!\n"); + return ODPDRV_ENUMR_INVALID; + } + + /* allocate memory for the new enumerator */ + enumr = _odp_ishm_pool_alloc(list_elt_pool, + sizeof(_odpdrv_enumr_t)); + if (!enumr) { + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); + return ODPDRV_ENUMR_INVALID; + } + + /* save init parameters and insert enumerator in list */ + enumr->param = *param; + enumr->probed = 0; + enumr_list_write_lock(); + enumr->next = enumr_lst.head; + enumr_lst.head = enumr; + enumr_list_write_unlock(); + + return (odpdrv_enumr_t)enumr; } odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param) @@ -175,6 +260,7 @@ odpdrv_driver_t odpdrv_driver_register(odpdrv_driver_param_t *param) void _odpdrv_driver_probe_drv_items(void) { _odpdrv_enumr_class_t *enumr_c; + _odpdrv_enumr_t *enumr; /* probe unprobed enumerators: */ enumr_class_list_write_lock(); @@ -187,11 +273,26 @@ void _odpdrv_driver_probe_drv_items(void) enumr_c = enumr_c->next; } enumr_class_list_write_unlock(); + + /* go through the list of registered enumerator probing the new + * (never probed) ones: + */ + enumr_list_write_lock(); + enumr = enumr_lst.head; + while (enumr) { + if (!enumr->probed) { + enumr->param.probe(); + enumr->probed = 1; + } + enumr = enumr->next; + } + enumr_list_write_unlock(); } int odpdrv_print_all(void) { _odpdrv_enumr_class_t *enumr_c; + _odpdrv_enumr_t *enumr; /* we cannot use ODP_DBG before ODP init... */ if (init_global_status == UNDONE) @@ -208,6 +309,22 @@ int odpdrv_print_all(void) enumr_c = enumr_c->next; } enumr_class_list_read_unlock(); + + /* print the list of registered enumerators: */ + enumr_list_read_lock(); + enumr = enumr_lst.head; + ODP_DBG("The following enumerators have been registered:\n"); + while (enumr) { + enumr_c = get_enumr_class(enumr->param.enumr_class); + ODP_DBG(" enumerator: class: %s," + " API: %s, Version: %" PRIu32 "\n", + enumr_c->param.name, + enumr->param.api_name, + enumr->param.api_version); + enumr = enumr->next; + } + enumr_list_read_unlock(); + return 0; } @@ -223,6 +340,7 @@ int _odpdrv_driver_init_global(void) /* from now, we want to ensure mutex on the list: init lock: */ odp_rwlock_recursive_init(&enumr_class_lst.lock); + odp_rwlock_recursive_init(&enumr_lst.lock); /* probe things... */ _odpdrv_driver_probe_drv_items(); @@ -241,10 +359,25 @@ int _odpdrv_driver_init_local(void) int _odpdrv_driver_term_global(void) { _odpdrv_enumr_class_t *enumr_c; + _odpdrv_enumr_t *enumr; if (init_global_status == UNDONE) return 0; + /* remove all enumerators which are registered: */ + enumr_list_write_lock(); + while (enumr_lst.head) { + enumr = enumr_lst.head; + if (enumr->param.remove) { /* run remove callback, if any */ + if (enumr->param.remove()) + ODP_ERR("Enumerator (API %s) removal failed.\n", + enumr->param.api_name); + } + enumr_lst.head = enumr->next; + _odp_ishm_pool_free(list_elt_pool, enumr); + } + enumr_list_write_unlock(); + /* remove all enumerator classes which are registered: */ enumr_class_list_write_lock(); while (enumr_class_lst.head) { From 933c1215adb8e6fc51af970e012a87116a6dee73 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:14 +0100 Subject: [PATCH 07/23] test: drv: enumerator registration tests making sure that enumerators are probed. Signed-off-by: Christophe Milard --- .../validation/drv/drvdriver/.gitignore | 1 + .../validation/drv/drvdriver/Makefile.am | 11 + .../drv/drvdriver/drvdriver_enumr.c | 303 ++++++++++++++++++ .../drv/drvdriver/drvdriver_enumr.h | 24 ++ .../drv/drvdriver/drvdriver_enumr_main.c | 12 + test/linux-generic/Makefile.am | 1 + 6 files changed, 352 insertions(+) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr.h create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr_main.c diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 9268315ef1..a842448979 100644 --- a/test/common_plat/validation/drv/drvdriver/.gitignore +++ b/test/common_plat/validation/drv/drvdriver/.gitignore @@ -1 +1,2 @@ drvdriver_enumr_class_main +drvdriver_enumr_main diff --git a/test/common_plat/validation/drv/drvdriver/Makefile.am b/test/common_plat/validation/drv/drvdriver/Makefile.am index 9e941eedf5..3476c50e9d 100644 --- a/test/common_plat/validation/drv/drvdriver/Makefile.am +++ b/test/common_plat/validation/drv/drvdriver/Makefile.am @@ -14,3 +14,14 @@ drvdriver_enumr_class_main_LDADD = libtestdrvdriverenumrclass.la \ $(LIBCUNIT_COMMON) $(LIBODP) EXTRA_DIST = drvdriver_enumr_class.h + +#tests for enumerator registration: +noinst_LTLIBRARIES += libtestdrvdriverenumr.la +libtestdrvdriverenumr_la_SOURCES = drvdriver_enumr.c + +test_PROGRAMS += drvdriver_enumr_main$(EXEEXT) +dist_drvdriver_enumr_main_SOURCES = drvdriver_enumr_main.c +drvdriver_enumr_main_LDADD = libtestdrvdriverenumr.la \ + $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST += drvdriver_enumr.h diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.c b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.c new file mode 100644 index 0000000000..38aac3d032 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.c @@ -0,0 +1,303 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include "drvdriver_enumr.h" +#include + +static odp_instance_t odp_instance; +static odpdrv_enumr_class_t enumr_class1, enumr_class2; + +/* markers showing that different stages have been run */ +static int enumr1_probed; +static int enumr2_probed; +static int enumr3_probed; +static int enumr4_probed; + +/* forward declaration */ +static int enumr1_probe(void); +static int enumr2_probe(void); +static int enumr3_probe(void); +static int enumr4_probe(void); + +static int enumr1_remove(void); +static int enumr2_remove(void); +static int enumr3_remove(void); +static int enumr4_remove(void); + +static int enumr_class1_probe(void); +static int enumr_class2_probe(void); + +static int enumr_class1_remove(void); +static int enumr_class2_remove(void); + +/* because many things to be checked are performed during ODP initialisation, + * the initialisation functions have to be a part of the test + */ +static int tests_global_init(void) +{ + if (0 != odp_init_global(&odp_instance, NULL, NULL)) { + fprintf(stderr, "error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(odp_instance, ODP_THREAD_CONTROL)) { + fprintf(stderr, "error: odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +static int tests_global_term(void) +{ + if (0 != odp_term_local()) { + fprintf(stderr, "error: odp_term_local() failed.\n"); + return -1; + } + + if (0 != odp_term_global(odp_instance)) { + fprintf(stderr, "error: odp_term_global() failed.\n"); + return -1; + } + + return 0; +} + +/*enumerator register functions */ +static odpdrv_enumr_t enumr1_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class1, + .api_name = "Enumerator_interface_1", + .api_version = 1, + .probe = enumr1_probe, + .remove = enumr1_remove, + .register_notifier = NULL + }; + + return odpdrv_enumr_register(¶m); +} + +static odpdrv_enumr_t enumr2_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class1, + .api_name = "Enumerator_interface_2", + .api_version = 1, + .probe = enumr2_probe, + .remove = enumr2_remove, + .register_notifier = NULL + }; + + return odpdrv_enumr_register(¶m); +} + +static odpdrv_enumr_t enumr3_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class1, + .api_name = "Enumerator_interface_3", + .api_version = 1, + .probe = enumr3_probe, + .remove = enumr3_remove, + .register_notifier = NULL + }; + + return odpdrv_enumr_register(¶m); +} + +static odpdrv_enumr_t enumr4_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class2, + .api_name = "Enumerator_interface_4", + .api_version = 1, + .probe = enumr4_probe, + .remove = enumr4_remove, + .register_notifier = NULL + }; + + return odpdrv_enumr_register(¶m); +} + +static odpdrv_enumr_t enumr_invalid_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = NULL, + .api_name = "Enumerator_interface_invalid", + .api_version = 1, + .probe = enumr4_probe, + .remove = enumr4_remove, + .register_notifier = NULL + }; + + return odpdrv_enumr_register(¶m); +} + +/*enumerator probe functions, just making sure they have been run: */ +static int enumr1_probe(void) +{ + enumr1_probed = 1; + return 0; +} + +static int enumr2_probe(void) +{ + enumr2_probed = 1; + return 0; +} + +static int enumr3_probe(void) +{ + enumr3_probed = 1; + return 0; +} + +static int enumr4_probe(void) +{ + enumr4_probed = 1; + return 0; +} + +/*enumerator remove functions, just making sure they have been run: */ +static int enumr1_remove(void) +{ + enumr1_probed = -1; + return 0; +} + +static int enumr2_remove(void) +{ + enumr2_probed = -1; + return 0; +} + +static int enumr3_remove(void) +{ + enumr3_probed = -1; + return 0; +} + +static int enumr4_remove(void) +{ + enumr4_probed = -1; + return 0; +} + +/*enumerator class register functions, all "statically linked" + *(i.e. directely run at start), due to the fact that platorm independent + * shared lib loading in autotools is a mess */ +static void ODPDRV_CONSTRUCTOR enumr_class1_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class1", + .probe = enumr_class1_probe, + .remove = enumr_class1_remove + }; + + enumr_class1 = odpdrv_enumr_class_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR enumr_class2_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class2", + .probe = enumr_class2_probe, + .remove = enumr_class2_remove + }; + + enumr_class2 = odpdrv_enumr_class_register(¶m); +} + +/*enumerator class probe functions, registering enumerators: */ +static int enumr_class1_probe(void) +{ + CU_ASSERT(enumr1_register() != ODPDRV_ENUMR_INVALID); + CU_ASSERT(enumr2_register() != ODPDRV_ENUMR_INVALID); + CU_ASSERT(enumr3_register() != ODPDRV_ENUMR_INVALID); + + CU_ASSERT(enumr_invalid_register() == ODPDRV_ENUMR_INVALID); + + return 0; +} + +static int enumr_class2_probe(void) +{ + CU_ASSERT(enumr4_register() != ODPDRV_ENUMR_INVALID); + return 0; +} + +/*enumerator class remove functions, just making sure they have been run: */ +static int enumr_class1_remove(void) +{ + return 0; +} + +static int enumr_class2_remove(void) +{ + return 0; +} + +void drvdriver_test_enumr_register(void) +{ + CU_ASSERT(enumr1_probed == 0); + CU_ASSERT(enumr2_probed == 0); + CU_ASSERT(enumr3_probed == 0); + CU_ASSERT(enumr4_probed == 0); + + CU_ASSERT(tests_global_init() == 0); + + /* at this point (after odp init), the constructor + * enumerator classes should have registered and been probed: + */ + CU_ASSERT(odpdrv_print_all() == 0); + + CU_ASSERT(enumr1_probed == 1); + CU_ASSERT(enumr2_probed == 1); + CU_ASSERT(enumr3_probed == 1); + CU_ASSERT(enumr4_probed == 1); + + CU_ASSERT(tests_global_term() == 0); + + /* after ODP termination completion, all enumerators should be removed*/ + CU_ASSERT(enumr1_probed == -1); + CU_ASSERT(enumr2_probed == -1); + CU_ASSERT(enumr3_probed == -1); + CU_ASSERT(enumr4_probed == -1); +} + +odp_testinfo_t drvdriver_suite_enumr[] = { + ODP_TEST_INFO(drvdriver_test_enumr_register), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvdriver_suites_enumr[] = { + {"Enumerator registration", NULL, NULL, drvdriver_suite_enumr}, + ODP_SUITE_INFO_NULL, +}; + +int drvdriver_enumr_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + /* prevent default ODP init: */ + odp_cunit_register_global_init(NULL); + odp_cunit_register_global_term(NULL); + + /* register the tests: */ + ret = odp_cunit_register(drvdriver_suites_enumr); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.h b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.h new file mode 100644 index 0000000000..afe814ac3d --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVDRIVER_ENUMR_H_ +#define _ODP_TEST_DRVDRIVER_ENUMR_H_ + +#include + +/* test functions: */ +void drvdriver_test_enumr_register(void); + +/* test arrays: */ +extern odp_testinfo_t drvdriver_suite_enumr[]; + +/* test registry: */ +extern odp_suiteinfo_t drvdriver_suites_enumr[]; + +/* main test program: */ +int drvdriver_enumr_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_main.c b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_main.c new file mode 100644 index 0000000000..53bc192e44 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_enumr_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvdriver_enumr.h" + +int main(int argc, char *argv[]) +{ + return drvdriver_enumr_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index 38be049e10..ba8c129ae8 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -37,6 +37,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_class_main$(EXEEXT)\ + $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ ring/ring_main$(EXEEXT) From 03d2fdec6bb7ca3e3f1a9db64e88b35b86dd0cce Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:15 +0100 Subject: [PATCH 08/23] drv: driver: change drv unbind function name and pass correct parameter The driver removal function expects a device, of course... Also unbind seems a better name to disconnect from a device since remove has been used for removing the object itself for enumerators. Some extra parameters to allow for graceful unbinding are also added. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index b08d7fb7c0..8ff856c0f5 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -300,14 +300,29 @@ struct odpdrv_driver_param_t { */ int (*probe)(odpdrv_device_t *dev); - /** Remove function: + /** unbind function: * Only called with devices whose probe() returned true * + * dev: the device to unbind + * callback: if flag ODPDRV_DRV_UNBIND_IMMEDIATE is not specified, + * unbind should be attempted gracefully, meaning that some IO may need + * to terminate before the driver is really unbound from the device: + * In this case (when the flag is not set), the driver is due to call + * the callback function when the driver is unbound from the device. + * This callback may occurs within the unbind() call if the driver + * does unbind immediately. + * If the ODPDRV_DRV_UNBIND_IMMEDIATE is specified, the driver is due + * to release the device immediately (poosibly less gracefully). + * The callback must be called immediately in this case. */ - int (*remove)(odpdrv_device_param_t *dev); - + int (*unbind)(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags); }; +/** The callback function must be called mmediately by the current ODP thread */ +#define ODPDRV_DRV_UNBIND_IMMEDIATE 0x00000001 + /** * Register an enumerator class. * Each enumerator class calls this function at init time. From 462d68fdb784c1816444d977808ae6d8da1bd899 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:16 +0100 Subject: [PATCH 09/23] drv: driver: add callback function for device destruction When a device is destroyed by an enumerator, odpdrv_device_destroy() is called. However, the complete device destruction may require waiting for IO to be completed: the device destruction is therefore divided in 2 steps: odpdrv_device_destroy() starts the device destruction, and the provided callback function is called when the device can be fully removed, i.e. when it no longer has any driver bound to it. An extra flag is also added to select the destruction type: The default is a graceful destruction, letting the time for any attached driver to terminate. This may imply that the callback function is called from another ODP thread, later on. ODPDRV_DEV_DESTROY_IMMEDIATE forces an immediate device destruction, possibly terminating things abrubtly, but it guarantees that the callback is performed by the same ODP thread. This is to be used at ODP terminaison time. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 31 +++++++++++++++++++++++++---- platform/linux-generic/drv_driver.c | 9 ++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 8ff856c0f5..9643268faa 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -357,12 +357,35 @@ odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param); /** * Destroy a device -* Called by each enumerator at probe time, or anytime later, for each -* destroyed created device +* Called by each enumerator after probe time, for each device to be +* destroyed. +* Destroying a device may require tearing down a driver and waiting for some IO +* to terminate: The device destruction is therefore done in 2 steps: +* Calling this function starts the device destruction: when the device has +* no driver attached any longer, ODP calls the provided callback() +* function which should free the enumerator-allocated resources for +* this device. +* If the flag ODPDRV_DEV_DESTROY_IMMEDIATE is given, the device destruction +* is immediate, i.e. the callback function is guaranteed to be called by the +* same ODP thread: This might however not let the time for the bound driver +* (if any) to terminate gracefully. This would typically be used at ODP +* terminaison. By default, the callback may be called later, when the driver +* has gracefully terminated, hence possibly from another ODP thread. * @param dev A odpdrv device handle as returned by odpdrv_device_create. -* @return 0 on success or a negative value on error. +* @param callback a pointer to a function to be called when the device is +* freed (no more driver). The parameter to the callback function is +* the pointer to the enumerator specific part of the device as provided +* at device creation time (void *enum_dev). The callback function +* should release these resources. +* @param flags 0 or ODPDRV_DEV_DESTROY_IMMEDIATE for immediate shut down +* @return 0 on success or a negative value on error. On error, the callback +* function is not called. */ -void odpdrv_device_destroy(odpdrv_device_t dev); +int odpdrv_device_destroy(odpdrv_device_t dev, + void (*callback)(void *enum_dev), uint32_t flags); + +/** The callback function must be called by the current ODP thread */ +#define ODPDRV_DEV_DESTROY_IMMEDIATE 0x00000001 /** * Register an devio. diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index df6d77d762..8ceea6b1ee 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -232,10 +232,17 @@ odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param) return ODPDRV_DEVICE_INVALID; } -void odpdrv_device_destroy(odpdrv_device_t dev) +int odpdrv_device_destroy(odpdrv_device_t dev, + void (*callback)(void *enum_dev), uint32_t flags) { if (dev == ODPDRV_DEVICE_INVALID) ODP_ERR("Invalid device\n"); + if (callback != NULL) + ODP_ERR("Callback not supported yet\n"); + if (flags != 0) + ODP_ERR("flags not supported yet\n"); + + return 0; } odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param) From f63a3270ff46c776c700c0342ce4cf10aa9263e6 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:17 +0100 Subject: [PATCH 10/23] linux-gen: drv: device creation and deletion Functions to create and remove devices are populated to do more proper things. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 181 ++++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 8 deletions(-) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 8ceea6b1ee..6cdae603bb 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -19,12 +19,15 @@ static enum {UNDONE, IN_PROGRESS, DONE} init_global_status; +static void device_destroy_terminate(odpdrv_device_t device); + /* pool from which different list elements are alocated: */ #define ELT_POOL_SIZE (1 << 20) /* 1Mb */ static _odp_ishm_pool_t *list_elt_pool; typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; typedef struct _odpdrv_enumr_s _odpdrv_enumr_t; +typedef struct _odpdrv_device_s _odpdrv_device_t; /* an enumerator class (list element) */ struct _odpdrv_enumr_class_s { @@ -55,6 +58,20 @@ typedef struct _odpdrv_enumr_lst_t { } _odpdrv_enumr_lst_t; static struct _odpdrv_enumr_lst_t enumr_lst; +/* a device (list element) */ +struct _odpdrv_device_s { + odpdrv_device_param_t param; + void (*enumr_destroy_callback)(void *enum_dev);/*dev destroy callback */ + struct _odpdrv_device_s *next; +} _odpdrv_device_s; + +/* the device list (all devices, from all enumerators): */ +typedef struct _odpdrv_device_lst_t { + odp_rwlock_recursive_t lock; + _odpdrv_device_t *head; +} _odpdrv_device_lst_t; +static struct _odpdrv_device_lst_t device_lst; + /* some driver elements (such as enumeraor classes, drivers, devio) may * register before init_global and init_local complete. Mutex will fail * in this cases but should be used later on. @@ -108,12 +125,46 @@ static void enumr_list_write_unlock(void) odp_rwlock_recursive_write_unlock(&enumr_lst.lock); } +static void dev_list_read_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_lock(&device_lst.lock); +} + +static void dev_list_read_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_unlock(&device_lst.lock); +} + +static void dev_list_write_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_lock(&device_lst.lock); +} + +static void dev_list_write_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_unlock(&device_lst.lock); +} + /* some functions to get internal pointers from handles... */ static inline _odpdrv_enumr_class_t *get_enumr_class(odpdrv_enumr_class_t class) { return (_odpdrv_enumr_class_t *)(void *)class; } +static inline _odpdrv_enumr_t *get_enumr(odpdrv_enumr_t enumr) +{ + return (_odpdrv_enumr_t *)(void *)enumr; +} + +static inline _odpdrv_device_t *get_device(odpdrv_device_t dev) +{ + return (_odpdrv_device_t *)(void *)dev; +} + odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t *param) { @@ -227,24 +278,119 @@ odpdrv_enumr_t odpdrv_enumr_register(odpdrv_enumr_param_t *param) odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param) { - ODP_ERR("odpdrv_device_create not Supported yet! devaddress: %s\n.", - param->address); - return ODPDRV_DEVICE_INVALID; + _odpdrv_device_t *dev; + + /* If init_global has not been done yet, we have a big issue. */ + if (init_global_status == UNDONE) + return ODPDRV_DEVICE_INVALID; + + /* make sure that the provided device address does not already exist: */ + dev_list_read_lock(); + dev = device_lst.head; + while (dev) { + if (strcmp(param->address, dev->param.address) == 0) { + ODP_ERR("device already exists!\n"); + dev_list_read_unlock(); + return ODPDRV_DEVICE_INVALID; + } + dev = dev->next; + } + dev_list_read_unlock(); + + dev = _odp_ishm_pool_alloc(list_elt_pool, + sizeof(_odpdrv_device_t)); + if (!dev) { + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); + return ODPDRV_DEVICE_INVALID; + } + + /* save and set dev init parameters and insert new device in list */ + dev->param = *param; + dev->enumr_destroy_callback = NULL; + dev_list_write_lock(); + dev->next = device_lst.head; + device_lst.head = dev; + dev_list_write_unlock(); + + /* todo: probe for drivers */ + + return (odpdrv_device_t)dev; } int odpdrv_device_destroy(odpdrv_device_t dev, void (*callback)(void *enum_dev), uint32_t flags) { - if (dev == ODPDRV_DEVICE_INVALID) + _odpdrv_device_t *device = get_device(dev); + _odpdrv_device_t *_dev; + _odpdrv_device_t *target = NULL; + + if (dev == ODPDRV_DEVICE_INVALID) { ODP_ERR("Invalid device\n"); - if (callback != NULL) - ODP_ERR("Callback not supported yet\n"); - if (flags != 0) - ODP_ERR("flags not supported yet\n"); + return -1; + } + + if (flags & ODPDRV_DEV_DESTROY_IMMEDIATE) + ODP_ERR("ODPDRV_DEV_DESTROY_IMMEDIATE not supported yet\n"); + + /* remove the device from the device list (but keep the device): */ + dev_list_write_lock(); + if (device == device_lst.head) { + target = device; + device_lst.head = device_lst.head->next; + } else { + _dev = device_lst.head; + while (_dev) { + if (_dev->next == device) { + target = device; + _dev->next = _dev->next->next; + break; + } + _dev = _dev->next; + } + } + dev_list_write_unlock(); + + if (!target) { + ODP_ERR("Unknown device (cannot be removed)!\n"); + return -1; + } + + /* save the enumerator callback function which should be called + * when the driver is unbound (for gracious removal): + */ + target->enumr_destroy_callback = callback; + + /* TODO: if a driver is bound to the device, unbind it! + * passing the flag andf device_destroy_terminate() as a callback */ + + /* no driver is handling this device, or no callback was + * provided: continue removing the device: */ + device_destroy_terminate(dev); return 0; } +/* This function is called as a callback from the driver, when unbindind + * a device, or directely from odpdrv_device_destroy() if no driver + * was bound to the device. + * just call the enumerator callback to cleanup the enumerator part + * and free device memory */ +static void device_destroy_terminate(odpdrv_device_t drv_device) +{ + _odpdrv_device_t *device = get_device(drv_device); + void (*callback)(void *enum_dev); + + /* get the enumerator callback function */ + callback = device->enumr_destroy_callback; + + /* let the enumerator cleanup his part: */ + if (callback != NULL) + callback(device->param.enum_dev); + + /* free device memory: */ + _odp_ishm_pool_free(list_elt_pool, device); +} + odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param) { ODP_ERR("NOT Supported yet! Driver %s Registration!\n.", @@ -300,6 +446,7 @@ int odpdrv_print_all(void) { _odpdrv_enumr_class_t *enumr_c; _odpdrv_enumr_t *enumr; + _odpdrv_device_t *dev; /* we cannot use ODP_DBG before ODP init... */ if (init_global_status == UNDONE) @@ -332,6 +479,23 @@ int odpdrv_print_all(void) } enumr_list_read_unlock(); + /* print the list of registered devices: */ + dev_list_read_lock(); + dev = device_lst.head; + ODP_DBG("The following devices have been registered:\n"); + while (dev) { + enumr = get_enumr(dev->param.enumerator); + enumr_c = get_enumr_class(enumr->param.enumr_class); + ODP_DBG(" device: address: %s, from enumerator class: %s " + " API: %s, Version: %d\n", + dev->param.address, + enumr_c->param.name, + enumr->param.api_name, + enumr->param.api_version); + dev = dev->next; + } + dev_list_read_unlock(); + return 0; } @@ -348,6 +512,7 @@ int _odpdrv_driver_init_global(void) /* from now, we want to ensure mutex on the list: init lock: */ odp_rwlock_recursive_init(&enumr_class_lst.lock); odp_rwlock_recursive_init(&enumr_lst.lock); + odp_rwlock_recursive_init(&device_lst.lock); /* probe things... */ _odpdrv_driver_probe_drv_items(); From dd65fc1fb4aad80fa9186229391f325f69be3629 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:18 +0100 Subject: [PATCH 11/23] drv: driver: adding device query function Adding a function for querying a list of devices: this function may be used by enumerators to query for the list of their registered devices or for a subset of them. Note that this function returns a malloc'd list of devices which is to be freed by the caller. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 9643268faa..e8613964d5 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -387,6 +387,18 @@ int odpdrv_device_destroy(odpdrv_device_t dev, /** The callback function must be called by the current ODP thread */ #define ODPDRV_DEV_DESTROY_IMMEDIATE 0x00000001 +/** query for a list of devices + * Enumerators are responsable for device creation and destruction. + * Upon request, ODP can build a list of devices belonging to a given enumerator + * and possibly having a specific address. + * This function builds this list. + * @param enumr The enumerator which created the device + * @param address The device address (or NULL if don't care) + * @return A malloc'd ODPDRV_DEVICE_INVALID terminated array of odpdrv_device_t + * This array MUST BE FREED by the caller! + */ +odpdrv_device_t *odpdrv_device_query(odpdrv_enumr_t enumr, const char *address); + /** * Register an devio. * Each devio calls this function at init time. From b942ef3ae52e2ecbce87878ba0947952b5aca166 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:19 +0100 Subject: [PATCH 12/23] linux-gen: drv: driver: adding device query function Implementation of the device query function for the linux-gen ODP. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 6cdae603bb..3a422e141b 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -391,6 +391,46 @@ static void device_destroy_terminate(odpdrv_device_t drv_device) _odp_ishm_pool_free(list_elt_pool, device); } +odpdrv_device_t *odpdrv_device_query(odpdrv_enumr_t enumr, const char *address) +{ + _odpdrv_device_t *dev; + odpdrv_device_t *res; + int index = 0; + + int size = sizeof(odpdrv_device_t); /* for the ODPDRV_DEVICE_INVALID */ + + /* parse the list of device a first time to determine the size of + * the memory to be allocated: + */ + dev_list_read_lock(); + dev = device_lst.head; + while (dev) { + if ((dev->param.enumerator == enumr) && + ((address == NULL) || + (strcmp(dev->param.address, address) == 0))) + size += sizeof(odpdrv_device_t); + dev = dev->next; + } + + /* then fill the list: */ + res = (odpdrv_device_t *)malloc(size); + if (res == NULL) + return NULL; + + dev = device_lst.head; + while (dev) { + if ((dev->param.enumerator == enumr) && + ((address == NULL) || + (strcmp(dev->param.address, address) == 0))) + res[index++] = (odpdrv_device_t)dev; + dev = dev->next; + } + dev_list_read_unlock(); + res[index] = ODPDRV_DEVICE_INVALID; + + return res; /* must be freed by caller! */ +} + odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param) { ODP_ERR("NOT Supported yet! Driver %s Registration!\n.", From 6118db08424af6562b2eb8ee06db29418de03f0a Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:20 +0100 Subject: [PATCH 13/23] test: drv: device creation and destruction Testing that devices can be created and removed from ODP. Signed-off-by: Christophe Milard --- .../validation/drv/drvdriver/.gitignore | 1 + .../validation/drv/drvdriver/Makefile.am | 11 + .../drv/drvdriver/drvdriver_device.c | 218 ++++++++++++++++++ .../drv/drvdriver/drvdriver_device.h | 24 ++ .../drv/drvdriver/drvdriver_device_main.c | 12 + test/linux-generic/Makefile.am | 1 + 6 files changed, 267 insertions(+) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_device.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_device.h create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_device_main.c diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index a842448979..97b4312b5f 100644 --- a/test/common_plat/validation/drv/drvdriver/.gitignore +++ b/test/common_plat/validation/drv/drvdriver/.gitignore @@ -1,2 +1,3 @@ drvdriver_enumr_class_main drvdriver_enumr_main +drvdriver_device_main diff --git a/test/common_plat/validation/drv/drvdriver/Makefile.am b/test/common_plat/validation/drv/drvdriver/Makefile.am index 3476c50e9d..544586cb1a 100644 --- a/test/common_plat/validation/drv/drvdriver/Makefile.am +++ b/test/common_plat/validation/drv/drvdriver/Makefile.am @@ -25,3 +25,14 @@ drvdriver_enumr_main_LDADD = libtestdrvdriverenumr.la \ $(LIBCUNIT_COMMON) $(LIBODP) EXTRA_DIST += drvdriver_enumr.h + +#tests for device creation: +noinst_LTLIBRARIES += libtestdrvdriverdevice.la +libtestdrvdriverdevice_la_SOURCES = drvdriver_device.c + +test_PROGRAMS += drvdriver_device_main$(EXEEXT) +dist_drvdriver_device_main_SOURCES = drvdriver_device_main.c +drvdriver_device_main_LDADD = libtestdrvdriverdevice.la \ + $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST += drvdriver_device.h diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_device.c b/test/common_plat/validation/drv/drvdriver/drvdriver_device.c new file mode 100644 index 0000000000..d010026ff0 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_device.c @@ -0,0 +1,218 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include "drvdriver_device.h" +#include + +static odp_instance_t odp_instance; +static odpdrv_enumr_class_t enumr_class1; +static odpdrv_enumr_t enumr1; + +typedef struct dev_enumr_data_t { /* enumerator data for registered devices */ + odpdrv_shm_t shm_handle; + int device_number; +} dev_enumr_data_t; + +#define NB_DEVICES 5 + +/* forward declaration */ +static int enumr1_probe(void); +static int enumr1_remove(void); +static int enumr_class1_probe(void); +static int enumr_class1_remove(void); + +/* because many things to be checked are performed during ODP initialisation, + * the initialisation functions have to be a part of the test + */ +static int tests_global_init(void) +{ + if (0 != odp_init_global(&odp_instance, NULL, NULL)) { + fprintf(stderr, "error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(odp_instance, ODP_THREAD_CONTROL)) { + fprintf(stderr, "error: odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +static int tests_global_term(void) +{ + if (0 != odp_term_local()) { + fprintf(stderr, "error: odp_term_local() failed.\n"); + return -1; + } + + if (0 != odp_term_global(odp_instance)) { + fprintf(stderr, "error: odp_term_global() failed.\n"); + return -1; + } + + return 0; +} + +/*enumerator register functions */ +static odpdrv_enumr_t enumr1_register(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class1, + .api_name = "Enumerator_interface_1", + .api_version = 1, + .probe = enumr1_probe, + .remove = enumr1_remove, + .register_notifier = NULL + }; + + enumr1 = odpdrv_enumr_register(¶m); + return enumr1; +} + +/*enumerator probe functions, just making sure they have been run: */ +static int enumr1_probe(void) +{ + int dev; + odpdrv_shm_t shm; + dev_enumr_data_t *dev_data; + + odpdrv_device_param_t param = { + .enumerator = enumr1, + .address = "00:00:0X", + .enum_dev = NULL + }; + + /* create 5 devices: */ + for (dev = 0; dev < NB_DEVICES; dev++) { + shm = odpdrv_shm_reserve(NULL, sizeof(dev_enumr_data_t), + 0, ODPDRV_SHM_SINGLE_VA); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + dev_data = odpdrv_shm_addr(shm); + CU_ASSERT_PTR_NOT_NULL(dev_data); + + dev_data->shm_handle = shm; + dev_data->device_number = dev; + + param.address[7] = '0' + dev; /* change X in the address */ + param.enum_dev = dev_data; + + CU_ASSERT(odpdrv_device_create(¶m) != + ODPDRV_DEVICE_INVALID); + } + + CU_ASSERT(odpdrv_print_all() == 0); + + return 0; +} + +/* enumerator device removal callback function: */ +static void enumr5_device_destroy_terminate(void *priv_data) +{ + dev_enumr_data_t *dev_data; + int dev_nb; + odpdrv_shm_t shm; + + dev_data = (dev_enumr_data_t *)priv_data; + dev_nb = dev_data->device_number; + printf("removing device number: %d\n", dev_nb); + CU_ASSERT(dev_nb < NB_DEVICES); + CU_ASSERT(dev_nb >= 0); + shm = dev_data->shm_handle; + CU_ASSERT(!odpdrv_shm_free_by_handle(shm)); +} + +/*enumerator remove functions, to remove the enumerated devices: */ +static int enumr1_remove(void) +{ + odpdrv_device_t *my_devices; + odpdrv_device_t *dev; + int count = 0; + + /* destroy all devices created by enumerator 5: */ + my_devices = odpdrv_device_query(enumr1, NULL); + + for (dev = my_devices; *dev != ODPDRV_DEVICE_INVALID; dev++) { + odpdrv_device_destroy(*dev, enumr5_device_destroy_terminate, 0); + count++; + } + + CU_ASSERT(count == NB_DEVICES); + + free(my_devices); + return 0; +} + +/*enumerator class register functions, all "statically linked" + *(i.e. directely run at start), due to the fact that platorm independent + * shared lib loading in autotools is a mess */ +static void ODPDRV_CONSTRUCTOR enumr_class1_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "Enumerator_class1", + .probe = enumr_class1_probe, + .remove = enumr_class1_remove + }; + + enumr_class1 = odpdrv_enumr_class_register(¶m); +} + +/*enumerator class probe functions, registering enumerators: */ +static int enumr_class1_probe(void) +{ + CU_ASSERT(enumr1_register() != ODPDRV_ENUMR_INVALID); + return 0; +} + +/*enumerator class remove functions, just making sure they have been run: */ +static int enumr_class1_remove(void) +{ + return 0; +} + +void drvdriver_test_device_register(void) +{ + CU_ASSERT(tests_global_init() == 0); + + /* at this point (after odp init), the 5 devices should be there: + */ + CU_ASSERT(odpdrv_print_all() == 0); + + CU_ASSERT(tests_global_term() == 0); +} + +odp_testinfo_t drvdriver_suite_device[] = { + ODP_TEST_INFO(drvdriver_test_device_register), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvdriver_suites_device[] = { + {"Enumerator registration", NULL, NULL, drvdriver_suite_device}, + ODP_SUITE_INFO_NULL, +}; + +int drvdriver_device_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + /* prevent default ODP init: */ + odp_cunit_register_global_init(NULL); + odp_cunit_register_global_term(NULL); + + /* register the tests: */ + ret = odp_cunit_register(drvdriver_suites_device); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_device.h b/test/common_plat/validation/drv/drvdriver/drvdriver_device.h new file mode 100644 index 0000000000..afc04c59bf --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_device.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVDRIVER_DEVICE_H_ +#define _ODP_TEST_DRVDRIVER_DEVICE_H_ + +#include + +/* test functions: */ +void drvdriver_test_device_register(void); + +/* test arrays: */ +extern odp_testinfo_t drvdriver_suite_device[]; + +/* test registry: */ +extern odp_suiteinfo_t drvdriver_suites_device[]; + +/* main test program: */ +int drvdriver_device_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_device_main.c b/test/common_plat/validation/drv/drvdriver/drvdriver_device_main.c new file mode 100644 index 0000000000..27de9c5ba2 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_device_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvdriver_device.h" + +int main(int argc, char *argv[]) +{ + return drvdriver_device_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index ba8c129ae8..d483f9f3c3 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -36,6 +36,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_API_VALIDATION_DIR)/shmem/shmem_main$(EXEEXT) \ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ + $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_device_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_class_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ From 07ca1697b308a9714ab197ef6b278108e0c16ebd Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:21 +0100 Subject: [PATCH 14/23] drv: driver: adding a probe and remove callback for devio Needed to delete the resources needed for the devio. That is possibly the memory allocated for its "ops" part if it was allocated. May be NULL if nothing needs to be done at devio deletion time. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index e8613964d5..f89c282ee4 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -269,6 +269,24 @@ struct odpdrv_devio_param_t { char enumr_api_name[ODPDRV_NAME_SIZE]; uint32_t enumr_api_version; /**<< required enumerator API version */ + /** Probe function: + * Tell whether this devio can handle the given device. + * The devio is hence given a chance to reject a given device for + * any reason. No binding occurs here. binding occurs when the + * driver is probed. + * returns 0 if this devio can handle the given device, or a negative + * value if not. + * If left to NULL, a 0 returned value is assumed + */ + int (*probe)(odpdrv_device_t dev); + + /** Remove function: + * Should destroy the memory allocated for ops and anything else + * under it, or any resource for this devio. + * Returns 0 on success or a negative value on error. + */ + int (*remove)(void); + /** Ops * Pointer to a devio ops structure (specific to each devio) */ From a432cc904b1d750f29562dbfaf44665dd4a5b363 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:22 +0100 Subject: [PATCH 15/23] linux-gen: drv: devio registration devios (dev IO) provide a interface for drivers to access a device: Devices enumerated by enumerators may be accessed in by different mechanisms (depending on iommu presence or other factors). This extra abstraction is provided by devios, which provide a sets of methods to access the devices of a given type (i.e. registred enumerator(s) enumerating devices of the same kind (e.g. PCI)). This patch just implements the devio registration method provided by the driver API. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 134 +++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 3 deletions(-) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 3a422e141b..367141ddd4 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -28,6 +28,7 @@ static _odp_ishm_pool_t *list_elt_pool; typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; typedef struct _odpdrv_enumr_s _odpdrv_enumr_t; typedef struct _odpdrv_device_s _odpdrv_device_t; +typedef struct _odpdrv_devio_s _odpdrv_devio_t; /* an enumerator class (list element) */ struct _odpdrv_enumr_class_s { @@ -72,6 +73,20 @@ typedef struct _odpdrv_device_lst_t { } _odpdrv_device_lst_t; static struct _odpdrv_device_lst_t device_lst; +/* a devio (list element) */ +struct _odpdrv_devio_s { + odpdrv_devio_param_t param; + _odp_ishm_pool_t *pool; + struct _odpdrv_devio_s *next; +} _odpdrv_devio_s; + +/* the devio list: */ +typedef struct _odpdrv_devio_lst_t { + odp_rwlock_recursive_t lock; + _odpdrv_devio_t *head; +} _odpdrv_devio_lst_t; +static struct _odpdrv_devio_lst_t devio_lst; + /* some driver elements (such as enumeraor classes, drivers, devio) may * register before init_global and init_local complete. Mutex will fail * in this cases but should be used later on. @@ -149,6 +164,30 @@ static void dev_list_write_unlock(void) odp_rwlock_recursive_write_unlock(&device_lst.lock); } +static void devio_list_read_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_lock(&devio_lst.lock); +} + +static void devio_list_read_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_unlock(&devio_lst.lock); +} + +static void devio_list_write_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_lock(&devio_lst.lock); +} + +static void devio_list_write_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_unlock(&devio_lst.lock); +} + /* some functions to get internal pointers from handles... */ static inline _odpdrv_enumr_class_t *get_enumr_class(odpdrv_enumr_class_t class) { @@ -433,10 +472,65 @@ odpdrv_device_t *odpdrv_device_query(odpdrv_enumr_t enumr, const char *address) odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param) { - ODP_ERR("NOT Supported yet! Driver %s Registration!\n.", - param->api_name); + _odpdrv_devio_t *devio; + + /* parse the list of already registered devios to make + * sure no devio providing the same interface using th esame enumerator + * already exists: + */ + devio_list_read_lock(); + devio = devio_lst.head; + while (devio) { + if ((strncmp(param->api_name, devio->param.api_name, + ODPDRV_NAME_SIZE) == 0) && + (strncmp(param->enumr_api_name, devio->param.enumr_api_name, + ODPDRV_NAME_SIZE) == 0)) { + ODP_ERR("a devio providing interface '%s' for devices " + "of type '%s' is already registered\n!", + param->api_name, param->enumr_api_name); + devio_list_read_unlock(); + return ODPDRV_DEVIO_INVALID; + } + devio = devio->next; + } + devio_list_read_unlock(); - return ODPDRV_DEVIO_INVALID; + /* allocate memory for the new devio: + * If init_global has not been done yet, then, we cannot allocate + * from any _ishm pool (ishm has not even been initialised at this + * stage...this happens when statically linked devios + * register: their __constructor__ function is run before main() + * is called). But any malloc performed here(before init_global) + * will be inherited by any odpthreads (process or pthreads) as we + * are still running in the ODP instantiation processes and all + * other processes are guaranteed to be descendent of this one... + * If init_global has been done, then we allocate from the _ishm pool + * to guarantee visibility from any ODP thread. + */ + + if (init_global_status == UNDONE) { + devio = malloc(sizeof(_odpdrv_devio_t)); + if (!devio) + return ODPDRV_DEVIO_INVALID; + devio->pool = NULL; + } else { + devio = _odp_ishm_pool_alloc(list_elt_pool, + sizeof(_odpdrv_devio_t)); + if (!devio) { + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); + return ODPDRV_DEVIO_INVALID; + } + devio->pool = list_elt_pool; + } + + /* save init parameters and insert devio in list */ + devio->param = *param; + devio_list_write_lock(); + devio->next = devio_lst.head; + devio_lst.head = devio; + devio_list_write_unlock(); + + return (odpdrv_devio_t)devio; } odpdrv_driver_t odpdrv_driver_register(odpdrv_driver_param_t *param) @@ -487,6 +581,7 @@ int odpdrv_print_all(void) _odpdrv_enumr_class_t *enumr_c; _odpdrv_enumr_t *enumr; _odpdrv_device_t *dev; + _odpdrv_devio_t *devio; /* we cannot use ODP_DBG before ODP init... */ if (init_global_status == UNDONE) @@ -536,6 +631,21 @@ int odpdrv_print_all(void) } dev_list_read_unlock(); + /* print the list of registered devios: */ + devio_list_read_lock(); + devio = devio_lst.head; + ODP_DBG("The following dev IOs have been registered:\n"); + while (devio) { + ODP_DBG(" devio providing interface: '%s' (version %d) for " + " devices of type '%s' (version %d)\n", + devio->param.api_name, + devio->param.api_version, + devio->param.enumr_api_name, + devio->param.enumr_api_version); + devio = devio->next; + } + devio_list_read_unlock(); + return 0; } @@ -553,6 +663,7 @@ int _odpdrv_driver_init_global(void) odp_rwlock_recursive_init(&enumr_class_lst.lock); odp_rwlock_recursive_init(&enumr_lst.lock); odp_rwlock_recursive_init(&device_lst.lock); + odp_rwlock_recursive_init(&devio_lst.lock); /* probe things... */ _odpdrv_driver_probe_drv_items(); @@ -570,12 +681,29 @@ int _odpdrv_driver_init_local(void) int _odpdrv_driver_term_global(void) { + _odpdrv_devio_t *devio; _odpdrv_enumr_class_t *enumr_c; _odpdrv_enumr_t *enumr; if (init_global_status == UNDONE) return 0; + /* remove all devios which are registered: */ + devio_list_write_lock(); + while (devio_lst.head) { + devio = devio_lst.head; /* run removal function, if any */ + if (devio->param.remove) { + if (devio->param.remove()) + ODP_ERR("devio removal indicated failure!\n"); + } + devio_lst.head = devio->next; + if (devio->pool) + _odp_ishm_pool_free(list_elt_pool, devio); + else + free(devio); + } + devio_list_write_unlock(); + /* remove all enumerators which are registered: */ enumr_list_write_lock(); while (enumr_lst.head) { From eae052ff6e4c3b840018fc47fadc6fa445d642ff Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:23 +0100 Subject: [PATCH 16/23] test: drv: devio creation and destruction Testing that devios can be registered and removed in/from ODP. Signed-off-by: Christophe Milard --- .../validation/drv/drvdriver/.gitignore | 1 + .../validation/drv/drvdriver/Makefile.am | 11 + .../drv/drvdriver/drvdriver_devio.c | 209 ++++++++++++++++++ .../drv/drvdriver/drvdriver_devio.h | 24 ++ .../drv/drvdriver/drvdriver_devio_main.c | 12 + test/linux-generic/Makefile.am | 1 + 6 files changed, 258 insertions(+) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_devio.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_devio.h create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_devio_main.c diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 97b4312b5f..829c8b4d88 100644 --- a/test/common_plat/validation/drv/drvdriver/.gitignore +++ b/test/common_plat/validation/drv/drvdriver/.gitignore @@ -1,3 +1,4 @@ drvdriver_enumr_class_main drvdriver_enumr_main drvdriver_device_main +drvdriver_devio_main diff --git a/test/common_plat/validation/drv/drvdriver/Makefile.am b/test/common_plat/validation/drv/drvdriver/Makefile.am index 544586cb1a..8e695ba316 100644 --- a/test/common_plat/validation/drv/drvdriver/Makefile.am +++ b/test/common_plat/validation/drv/drvdriver/Makefile.am @@ -36,3 +36,14 @@ drvdriver_device_main_LDADD = libtestdrvdriverdevice.la \ $(LIBCUNIT_COMMON) $(LIBODP) EXTRA_DIST += drvdriver_device.h + +#tests for devio creation: +noinst_LTLIBRARIES += libtestdrvdriverdevio.la +libtestdrvdriverdevio_la_SOURCES = drvdriver_devio.c + +test_PROGRAMS += drvdriver_devio_main$(EXEEXT) +dist_drvdriver_devio_main_SOURCES = drvdriver_devio_main.c +drvdriver_devio_main_LDADD = libtestdrvdriverdevio.la \ + $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST += drvdriver_devio.h diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_devio.c b/test/common_plat/validation/drv/drvdriver/drvdriver_devio.c new file mode 100644 index 0000000000..cf7c7c9363 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_devio.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include "drvdriver_devio.h" +#include + +static odp_instance_t odp_instance; + +static int devio1_removed; +static int devio2_removed; +static int devio3_removed; +static int devio4_removed; + +static int devio1_remove(void); +static int devio2_remove(void); +static int devio3_remove(void); + +/* because many things to be checked are performed during ODP initialisation, + * the initialisation functions have to be a part of the test + */ +static int tests_global_init(void) +{ + if (0 != odp_init_global(&odp_instance, NULL, NULL)) { + fprintf(stderr, "error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(odp_instance, ODP_THREAD_CONTROL)) { + fprintf(stderr, "error: odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +static int tests_global_term(void) +{ + if (0 != odp_term_local()) { + fprintf(stderr, "error: odp_term_local() failed.\n"); + return -1; + } + + if (0 != odp_term_global(odp_instance)) { + fprintf(stderr, "error: odp_term_global() failed.\n"); + return -1; + } + + return 0; +} + +/*devio register functions, all "statically linked" + *(i.e. directely run at start), due to the fact that platorm independent + * shared lib loading in autotools is a mess */ +static void ODPDRV_CONSTRUCTOR devio1_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "devio_api_1", + .api_version = 1, + .enumr_api_name = "Enumerator_interface_1", + .enumr_api_version = 1, + .remove = devio1_remove, + .ops = NULL, + }; + + odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio2_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "devio_api_2", + .api_version = 1, + .enumr_api_name = "Enumerator_interface_1", + .enumr_api_version = 1, + .probe = NULL, + .remove = devio2_remove, + .ops = NULL, + }; + + odpdrv_devio_register(¶m); +} + +static odpdrv_devio_t devio2_register_retry(void) +{ + odpdrv_devio_param_t param = { + .api_name = "devio_api_2", + .api_version = 1, + .enumr_api_name = "Enumerator_interface_1", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + return odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio3_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "devio_api_2", + .api_version = 1, + .enumr_api_name = "Enumerator_interface_2", + .enumr_api_version = 1, + .probe = NULL, + .remove = devio3_remove, + .ops = NULL, + }; + + odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio4_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "devio_api_3", + .api_version = 1, + .enumr_api_name = "Enumerator_interface_3", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + odpdrv_devio_register(¶m); +} + +/*devio remove functions, just making sure they have been run: */ +static int devio1_remove(void) +{ + devio1_removed = 1; + return 0; +} + +/*devio remove functions, just making sure they have been run: */ +static int devio2_remove(void) +{ + devio2_removed = 1; + return 0; +} + +/*devio remove functions, just making sure they have been run: */ +static int devio3_remove(void) +{ + devio3_removed = 1; + return 0; +} + +void drvdriver_test_devio_register(void) +{ + CU_ASSERT(devio1_removed == 0); + CU_ASSERT(devio2_removed == 0); + CU_ASSERT(devio3_removed == 0); + CU_ASSERT(devio4_removed == 0); + + CU_ASSERT(tests_global_init() == 0); + + /* at this point (after odp init), the constructor + * devios should have registered. just print them: + */ + CU_ASSERT(odpdrv_print_all() == 0); + + /* re-register devio2: this should be kicked-out! */ + CU_ASSERT(devio2_register_retry() == ODPDRV_DEVIO_INVALID); + + CU_ASSERT(tests_global_term() == 0); + + /* after ODP termination completion, all devios have been removed*/ + CU_ASSERT(devio1_removed == 1); + CU_ASSERT(devio2_removed == 1); + CU_ASSERT(devio3_removed == 1); + CU_ASSERT(devio4_removed == 0); /* has no remove function */ +} + +odp_testinfo_t drvdriver_suite_devio[] = { + ODP_TEST_INFO(drvdriver_test_devio_register), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvdriver_suites_devio[] = { + {"Devio registration", NULL, NULL, drvdriver_suite_devio}, + ODP_SUITE_INFO_NULL, +}; + +int drvdriver_devio_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + /* prevent default ODP init: */ + odp_cunit_register_global_init(NULL); + odp_cunit_register_global_term(NULL); + + /* register the tests: */ + ret = odp_cunit_register(drvdriver_suites_devio); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_devio.h b/test/common_plat/validation/drv/drvdriver/drvdriver_devio.h new file mode 100644 index 0000000000..eea9623f0b --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_devio.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVDRIVER_DEVIO_H_ +#define _ODP_TEST_DRVDRIVER_DEVIO_H_ + +#include + +/* test functions: */ +void drvdriver_test_devio_register(void); + +/* test arrays: */ +extern odp_testinfo_t drvdriver_suite_devio[]; + +/* test registry: */ +extern odp_suiteinfo_t drvdriver_suites_devio[]; + +/* main test program: */ +int drvdriver_devio_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_devio_main.c b/test/common_plat/validation/drv/drvdriver/drvdriver_devio_main.c new file mode 100644 index 0000000000..10733adf81 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_devio_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvdriver_devio.h" + +int main(int argc, char *argv[]) +{ + return drvdriver_devio_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index d483f9f3c3..7e06c8d050 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -37,6 +37,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_device_main$(EXEEXT)\ + $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_devio_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_class_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ From f4ac1d8b887c792871bd9f59e80884e64bcd39be Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:24 +0100 Subject: [PATCH 17/23] drv: adding driver remove function The remove function, as for other driver items (such as enumerators...) is called before the driver is to be removed, i.e. after all devices have been unbound from the driver. remove() should release any resources held by the driver. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index f89c282ee4..394aa9207f 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -336,6 +336,14 @@ struct odpdrv_driver_param_t { int (*unbind)(odpdrv_device_t dev, void (*callback)(odpdrv_device_t dev), uint32_t flags); + + /** remove function: + * remove any resource taken by the driver. Called when the driver + * itself is to be removed, i.e. after all devices are unbound + * Can be set to NULL if the driver has nothing to release. + * + */ + int (*remove)(void); }; /** The callback function must be called mmediately by the current ODP thread */ From ef792499c54ed68ef90b196bd728112107284fd6 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:25 +0100 Subject: [PATCH 18/23] drv: complement parameters to the driver probe() function Of course, when probing a driver, the latter should be given the devio handle to be used. This is what this patch adds. It also adds the index of the devio, hence telling the driver which of the possible ODPDRV_MAX_DEVIOS devios was selected, as this is going to be the first thing the driver needs to know. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 394aa9207f..ad2b8db2dc 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -314,9 +314,12 @@ struct odpdrv_driver_param_t { /** Probe function: * Called by ODP to see if the driver can drive a given device - * + * -dev the device to be probed + * -devio is the devio to be used. + * -devio_idx actually tells which devio was selected: it is the + * index in the devios array above. */ - int (*probe)(odpdrv_device_t *dev); + int (*probe)(odpdrv_device_t dev, odpdrv_devio_t devio, int devio_idx); /** unbind function: * Only called with devices whose probe() returned true From f2392b762671f73d3249f9f881d06a489fadb3c6 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:26 +0100 Subject: [PATCH 19/23] linux-gen: driver registration and probing Driver registration and probing is implemented for linux-gen ODP. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 351 ++++++++++++++++++++++++++-- 1 file changed, 338 insertions(+), 13 deletions(-) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 367141ddd4..ca4aed9cfe 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,11 @@ typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; typedef struct _odpdrv_enumr_s _odpdrv_enumr_t; typedef struct _odpdrv_device_s _odpdrv_device_t; typedef struct _odpdrv_devio_s _odpdrv_devio_t; +typedef struct _odpdrv_driver_s _odpdrv_driver_t; + +static int unbind_device_driver(_odpdrv_device_t *dev, + void (*callback)(odpdrv_device_t odpdrv_dev), + uint32_t flags); /* an enumerator class (list element) */ struct _odpdrv_enumr_class_s { @@ -62,6 +68,8 @@ static struct _odpdrv_enumr_lst_t enumr_lst; /* a device (list element) */ struct _odpdrv_device_s { odpdrv_device_param_t param; + _odpdrv_driver_t *driver; /* driver for the device (if bound), or NULL*/ + _odpdrv_devio_t *devio; /* devio used for device (if bound), or NULL*/ void (*enumr_destroy_callback)(void *enum_dev);/*dev destroy callback */ struct _odpdrv_device_s *next; } _odpdrv_device_s; @@ -87,6 +95,21 @@ typedef struct _odpdrv_devio_lst_t { } _odpdrv_devio_lst_t; static struct _odpdrv_devio_lst_t devio_lst; +/* a driver (list element) */ +struct _odpdrv_driver_s { + odpdrv_driver_param_t param; + _odp_ishm_pool_t *pool; + odp_ticketlock_t probelock; /* to avoid concurrent probe on same drv*/ + struct _odpdrv_driver_s *next; +}; + +/* the driver list: */ +typedef struct _odpdrv_driver_lst_t { + odp_rwlock_recursive_t lock; + _odpdrv_driver_t *head; +} _odpdrv_driver_lst_t; +static struct _odpdrv_driver_lst_t driver_lst; + /* some driver elements (such as enumeraor classes, drivers, devio) may * register before init_global and init_local complete. Mutex will fail * in this cases but should be used later on. @@ -188,6 +211,30 @@ static void devio_list_write_unlock(void) odp_rwlock_recursive_write_unlock(&devio_lst.lock); } +static void driver_list_read_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_lock(&driver_lst.lock); +} + +static void driver_list_read_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_read_unlock(&driver_lst.lock); +} + +static void driver_list_write_lock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_lock(&driver_lst.lock); +} + +static void driver_list_write_unlock(void) +{ + if (init_global_status == DONE) + odp_rwlock_recursive_write_unlock(&driver_lst.lock); +} + /* some functions to get internal pointers from handles... */ static inline _odpdrv_enumr_class_t *get_enumr_class(odpdrv_enumr_class_t class) { @@ -346,6 +393,8 @@ odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param) /* save and set dev init parameters and insert new device in list */ dev->param = *param; dev->enumr_destroy_callback = NULL; + dev->driver = NULL; + dev->devio = NULL; dev_list_write_lock(); dev->next = device_lst.head; device_lst.head = dev; @@ -399,19 +448,19 @@ int odpdrv_device_destroy(odpdrv_device_t dev, */ target->enumr_destroy_callback = callback; - /* TODO: if a driver is bound to the device, unbind it! - * passing the flag andf device_destroy_terminate() as a callback */ - - /* no driver is handling this device, or no callback was - * provided: continue removing the device: */ - device_destroy_terminate(dev); + /* unbind the driver from the device (if bound). + * The callback is always called, and only cares + * about IMMEDIATE flag. + */ + unbind_device_driver(target, + device_destroy_terminate, + (flags & ODPDRV_DEV_DESTROY_IMMEDIATE)); return 0; } /* This function is called as a callback from the driver, when unbindind - * a device, or directely from odpdrv_device_destroy() if no driver - * was bound to the device. + * a device from odpdrv_device_destroy() * just call the enumerator callback to cleanup the enumerator part * and free device memory */ static void device_destroy_terminate(odpdrv_device_t drv_device) @@ -535,10 +584,239 @@ odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param) odpdrv_driver_t odpdrv_driver_register(odpdrv_driver_param_t *param) { - ODP_ERR("NOT Supported yet! Driver %s Registration!\n.", - param->name); + _odpdrv_driver_t *driver; + + /* check for a few compulsory things: */ + if ((param->probe == NULL) || + (param->unbind == NULL)) + return ODPDRV_DRIVER_INVALID; + + /* parse the list of already registered drivers to make + * sure no driver with same name already exists: + */ + driver_list_write_lock(); + driver = driver_lst.head; + while (driver) { + if ((strncmp(param->name, driver->param.name, + ODPDRV_NAME_SIZE) == 0)) { + ODP_ERR("driver %s already registered!\n", + param->name); + driver_list_write_unlock(); + return ODPDRV_DRIVER_INVALID; + } + driver = driver->next; + } + + /* allocate memory for the new driver: + * If init_global has not been done yet, then, we cannot allocate + * from any _ishm pool (ishm has not even been initialised at this + * stage...this happens when statically linked drivers + * register: their __constructor__ function is run before main() + * is called). But any malloc performed here(before init_global) + * will be inherited by any odpthreads (process or pthreads) as we + * are still running in the ODP instantiation processes and all + * other processes are guaranteed to be descendent of this one... + * If init_global has been done, then we allocate from the _ishm pool + * to guarantee visibility from any ODP thread. + */ + + if (init_global_status == UNDONE) { + driver = malloc(sizeof(_odpdrv_driver_t)); + if (!driver) { + driver_list_write_unlock(); + return ODPDRV_DRIVER_INVALID; + } + driver->pool = NULL; + } else { + driver = _odp_ishm_pool_alloc(list_elt_pool, + sizeof(_odpdrv_driver_t)); + if (!driver) { + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); + driver_list_write_unlock(); + return ODPDRV_DRIVER_INVALID; + } + driver->pool = list_elt_pool; + } + + /* save init parameters and insert driver in list */ + driver->param = *param; + odp_ticketlock_init(&driver->probelock); + driver->next = driver_lst.head; + driver_lst.head = driver; + driver_list_write_unlock(); + + return (odpdrv_driver_t)driver; +} + +/* Probe, if possible, the given driver with the given device: + * The driver is probed if: + * There exist a devio D such as + * -The name and version of the API provided by D matches one of the requested + * devio {name,version} requested by the driver + * -The enumerator's API (name and version) requested by D is provided + * by the enumerator which enumerated the device. + * This function will return zero if the above conditions where met by some + * devio D and the driver probe function returns 0 (success). + * The function will return -1 if some devio D were found, but the driver + * returned a non-zero value when probed (for all of them). + * The function will return -2 if no devio matching the above requirement was + * found. + * The function will return -3 if the device was already bound to a driver */ +static int probe_device_driver(_odpdrv_device_t *dev, _odpdrv_driver_t *drv) +{ + int i; + int ret = -2; + _odpdrv_devio_t *devio; + _odpdrv_enumr_t *enumr; + _odpdrv_enumr_class_t *enumr_c; + + /* the device already has a driver?: end of story... */ + if (dev->driver) + return -3; + + /* look at the different devio this driver can work with: */ + for (i = 0; i < ODPDRV_MAX_DEVIOS; i++) { + /* look at each registered devios: */ + devio_list_read_lock(); + for (devio = devio_lst.head; devio; devio = devio->next) { + /* if devio is no good for this driver, keep searching*/ + if ((strncmp(drv->param.devios[i].api_name, + devio->param.api_name, + ODPDRV_NAME_SIZE) != 0) || + (drv->param.devios[i].api_version != + devio->param.api_version)) + continue; + + /* give a chance to the devio to reject the device + * if it feels it should do so: */ + if (devio->param.probe && + devio->param.probe((odpdrv_device_t)dev)) + continue; + + /* grab the device enumerator and its class: */ + enumr = get_enumr(dev->param.enumerator); + enumr_c = get_enumr_class(enumr->param.enumr_class); + + /* if devio is no good for this dev, keep searching */ + if ((strncmp(devio->param.enumr_api_name, + enumr->param.api_name, + ODPDRV_NAME_SIZE) != 0) || + (devio->param.enumr_api_version != + enumr->param.api_version)) + continue; + + /* seems we are good to probe the driver: */ + odp_ticketlock_lock(&drv->probelock); + if (drv->param.probe((odpdrv_device_t)dev, + (odpdrv_devio_t)devio, i) == 0) { + /* the driver accepts this device */ + odp_ticketlock_unlock(&drv->probelock); + devio_list_read_unlock(); + ODP_DBG("driver %s will handle device %s(%s)\n", + drv->param.name, + dev->param.address, + enumr_c->param.name); + dev->driver = drv; + dev->devio = devio; + return 0; + } + odp_ticketlock_unlock(&drv->probelock); + + /* driver did not accept the device: keep searching */ + ret = -1; + } + devio_list_read_unlock(); + } + return ret; +} + +/* an empty callback is given to the driver on unprobe, if no real callback is + * needed */ +static void empty_unbind_callback(odpdrv_device_t odpdrv_dev ODP_UNUSED) +{ +} + +/* unbind the device driver from the device (i.e. "unprobe") + * if the immediate flag is set, the unbind is requested to be immediate, + * i.e. the driver is due to call the callback within its unbind function. + * (if the flag is not set, the callback can be called later on from + * another context. Immediate unbinding may be less graceful than + * non immediate unbinding) + * The callback function is called in all cases (even if the device was not + * bound) + */ +static int unbind_device_driver(_odpdrv_device_t *dev, + void (*callback)(odpdrv_device_t odpdrv_dev), + uint32_t flags) +{ + _odpdrv_driver_t *drv; + odpdrv_device_t odpdrv_dev = (odpdrv_device_t)dev; + + if (!callback) + callback = empty_unbind_callback; + + drv = dev->driver; + if (!drv) { /* nothing to do */ + callback(odpdrv_dev); + return 0; + } + + /* note that we assure that a given driver will not be bound/unbound + * concurrentely - but this does not cover the callback */ + odp_ticketlock_lock(&drv->probelock); + if (drv->param.unbind(odpdrv_dev, callback, flags)) { + ODP_DBG("driver %s could not release device %s\n", + drv->param.name, + dev->param.address); + odp_ticketlock_unlock(&drv->probelock); + return -1; + } + + /* unbind succeeded */ + dev->driver = NULL; + dev->devio = NULL; + odp_ticketlock_unlock(&drv->probelock); + return 0; +} + +/* try to find a driver for the given device, trying all possible registered + * drivers against it: + * returns 0 on success or -1 on error + */ +static int probe_device(_odpdrv_device_t *dev) +{ + _odpdrv_driver_t *driver; + int ret = -1; + + /* go through the list of registered drivers: */ + driver_list_read_lock(); + driver = driver_lst.head; + while (driver) { + if (probe_device_driver(dev, driver) == 0) { + ret = 0; + break; + } + driver = driver->next; + } + driver_list_read_unlock(); - return ODPDRV_DRIVER_INVALID; + return ret; +} + +/* try to find a driver for all the registered devices, trying all possible + * drivers-devices combination + */ +static void probe_all(void) +{ + _odpdrv_device_t *dev; + + dev_list_read_lock(); + dev = device_lst.head; + while (dev) { + (void)probe_device(dev); + dev = dev->next; + } + dev_list_read_unlock(); } /* the following function is called each time probing is needed, i.e. @@ -574,6 +852,9 @@ void _odpdrv_driver_probe_drv_items(void) enumr = enumr->next; } enumr_list_write_unlock(); + + /* probe drivers for all devices */ + probe_all(); } int odpdrv_print_all(void) @@ -582,6 +863,7 @@ int odpdrv_print_all(void) _odpdrv_enumr_t *enumr; _odpdrv_device_t *dev; _odpdrv_devio_t *devio; + _odpdrv_driver_t *driver; /* we cannot use ODP_DBG before ODP init... */ if (init_global_status == UNDONE) @@ -622,11 +904,16 @@ int odpdrv_print_all(void) enumr = get_enumr(dev->param.enumerator); enumr_c = get_enumr_class(enumr->param.enumr_class); ODP_DBG(" device: address: %s, from enumerator class: %s " - " API: %s, Version: %d\n", + " API: %s, Version: %" PRIu32 ", " + " handled by driver %s, with devio API: %s " + " (version %" PRIu32 ")\n", dev->param.address, enumr_c->param.name, enumr->param.api_name, - enumr->param.api_version); + enumr->param.api_version, + dev->driver ? dev->driver->param.name : "", + dev->devio ? dev->devio->param.api_name : "", + dev->devio ? dev->devio->param.api_version : 0); dev = dev->next; } dev_list_read_unlock(); @@ -646,6 +933,17 @@ int odpdrv_print_all(void) } devio_list_read_unlock(); + /* print the list of registered drivers: */ + driver_list_read_lock(); + driver = driver_lst.head; + ODP_DBG("The following dev drivers have been registered:\n"); + while (driver) { + ODP_DBG(" driver: '%s'\n", + driver->param.name); + driver = driver->next; + } + driver_list_read_unlock(); + return 0; } @@ -664,6 +962,7 @@ int _odpdrv_driver_init_global(void) odp_rwlock_recursive_init(&enumr_lst.lock); odp_rwlock_recursive_init(&device_lst.lock); odp_rwlock_recursive_init(&devio_lst.lock); + odp_rwlock_recursive_init(&driver_lst.lock); /* probe things... */ _odpdrv_driver_probe_drv_items(); @@ -684,10 +983,36 @@ int _odpdrv_driver_term_global(void) _odpdrv_devio_t *devio; _odpdrv_enumr_class_t *enumr_c; _odpdrv_enumr_t *enumr; + _odpdrv_device_t *dev; + _odpdrv_driver_t *driver; if (init_global_status == UNDONE) return 0; + /* unbind any driver from any device: */ + dev_list_read_lock(); + dev = device_lst.head; + while (dev) { + unbind_device_driver(dev, NULL, ODPDRV_DEV_DESTROY_IMMEDIATE); + dev = dev->next; + } + dev_list_read_unlock(); + + /* and remove all registered drivers: */ + driver_list_read_lock(); + while (driver_lst.head) { + driver = driver_lst.head; + if (driver->param.remove) { + if (driver->param.remove()) + ODP_ERR("driver removal indicated failure!\n"); + } + driver_lst.head = driver->next; + if (driver->pool) + _odp_ishm_pool_free(list_elt_pool, driver); + else + free(driver); + } + /* remove all devios which are registered: */ devio_list_write_lock(); while (devio_lst.head) { From eb494349babf89a0cd1e87731685783c5643d30c Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:27 +0100 Subject: [PATCH 20/23] test: drv: driver registration and probing Register driver, devios, enumerators, create devices, and check that probing occurs correctely. Signed-off-by: Christophe Milard --- .../validation/drv/drvdriver/.gitignore | 1 + .../validation/drv/drvdriver/Makefile.am | 11 + .../drv/drvdriver/drvdriver_driver.c | 515 ++++++++++++++++++ .../drv/drvdriver/drvdriver_driver.h | 24 + .../drv/drvdriver/drvdriver_driver_main.c | 12 + test/linux-generic/Makefile.am | 1 + 6 files changed, 564 insertions(+) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_driver.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_driver.h create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_driver_main.c diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 829c8b4d88..76bb6baf2f 100644 --- a/test/common_plat/validation/drv/drvdriver/.gitignore +++ b/test/common_plat/validation/drv/drvdriver/.gitignore @@ -2,3 +2,4 @@ drvdriver_enumr_class_main drvdriver_enumr_main drvdriver_device_main drvdriver_devio_main +drvdriver_driver_main diff --git a/test/common_plat/validation/drv/drvdriver/Makefile.am b/test/common_plat/validation/drv/drvdriver/Makefile.am index 8e695ba316..88bd828aff 100644 --- a/test/common_plat/validation/drv/drvdriver/Makefile.am +++ b/test/common_plat/validation/drv/drvdriver/Makefile.am @@ -47,3 +47,14 @@ drvdriver_devio_main_LDADD = libtestdrvdriverdevio.la \ $(LIBCUNIT_COMMON) $(LIBODP) EXTRA_DIST += drvdriver_devio.h + +#tests for driver registration and probing: +noinst_LTLIBRARIES += libtestdrvdriverdriver.la +libtestdrvdriverdriver_la_SOURCES = drvdriver_driver.c + +test_PROGRAMS += drvdriver_driver_main$(EXEEXT) +dist_drvdriver_driver_main_SOURCES = drvdriver_driver_main.c +drvdriver_driver_main_LDADD = libtestdrvdriverdriver.la \ + $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST += drvdriver_driver.h diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c new file mode 100644 index 0000000000..d90aa566dd --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c @@ -0,0 +1,515 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* This file is a bit long as it tries to simulate the presence of 2 + * enumerator classes, 2 enumerators, and 3 drivers in one go to + * see how things are handled by the driver framework. + * The following is done: + * - create 2 enumerator classes, + * - each with its own enumerator providing interfaces: E1 and E2. + * - E1 and E2 create 4 devices each. + * - the following devio are created: + * devio1 enabling device handling from DRVIF-1 to E1 + * devio2 enabling device handling from DRVIF-2 to E2 + * devio3 enabling device handling from DRVIF-3 to E2 + * devio4 enabling device handling from DRVIF-3 to E3 (does not exist) + * devio5 enabling device handling from DRVIF-4 to E3 (does not exist) + * + * -then the following driver are created: + * driver1, requiring devio DRVIF-1 + * driver2, requiring devio DRVIF-2 (preferred) and DRVIF-3 + * driver3, requiring devio DRVIF-4 + * + * The test amkes sure that: + * driver 1 is probed (and accepts) the 4 devices of E1 with devio1 + * driver 2 is probed (and rejects) the 4 devices of E2 with devio2 and devio4 + * driver3 is never probed. + */ + +#include +#include +#include +#include "drvdriver_driver.h" +#include + +static odp_instance_t odp_instance; +static odpdrv_enumr_class_t enumr_class1; +static odpdrv_enumr_class_t enumr_class2; +static odpdrv_enumr_t enumr1; +static odpdrv_enumr_t enumr2; +#define NB_DEVICES 4 +static odpdrv_device_t E1_devs[NB_DEVICES]; +static odpdrv_device_t E2_devs[NB_DEVICES]; +static odpdrv_devio_t devio1; +static odpdrv_devio_t devio2; +static odpdrv_devio_t devio3; +static odpdrv_devio_t devio4; +static odpdrv_devio_t devio5; +static odpdrv_driver_t driver1; +static odpdrv_driver_t driver2; +static odpdrv_driver_t driver3; + +static int driver1_probed_index; +static int driver2_probed_index; + +/* forward declaration */ +static int enumr1_probe(void); +static int enumr2_probe(void); +static int enumr1_remove(void); +static int enumr2_remove(void); +static int enumr_class1_probe(void); +static int enumr_class2_probe(void); +static int driver1_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx); +static int driver2_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx); +static int driver3_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx); +static int driver1_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags); +static int driver2_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags); +static int driver3_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags); + +/* because many things to be checked are performed during ODP initialisation, + * the initialisation functions have to be a part of the test + */ +static int tests_global_init(void) +{ + if (0 != odp_init_global(&odp_instance, NULL, NULL)) { + fprintf(stderr, "error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(odp_instance, ODP_THREAD_CONTROL)) { + fprintf(stderr, "error: odp_init_local() failed.\n"); + return -1; + } + + return 0; +} + +static int tests_global_term(void) +{ + if (0 != odp_term_local()) { + fprintf(stderr, "error: odp_term_local() failed.\n"); + return -1; + } + + if (0 != odp_term_global(odp_instance)) { + fprintf(stderr, "error: odp_term_global() failed.\n"); + return -1; + } + + return 0; +} + +/*enumerator class register functions, all "statically linked" + *(i.e. directely run at start), due to the fact that platorm independent + * shared lib loading in autotools is a mess */ +static void ODPDRV_CONSTRUCTOR enumr_class1_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "C1", + .probe = enumr_class1_probe, + .remove = NULL + }; + + enumr_class1 = odpdrv_enumr_class_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR enumr_class2_register(void) +{ + odpdrv_enumr_class_param_t param = { + .name = "C2", + .probe = enumr_class2_probe, + .remove = NULL + }; + + enumr_class2 = odpdrv_enumr_class_register(¶m); +} + +/*enumerator class probe functions, registering enumerators E1 and E2: */ +static int enumr_class1_probe(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class1, + .api_name = "E1", + .api_version = 1, + .probe = enumr1_probe, + .remove = enumr1_remove, + .register_notifier = NULL + }; + + enumr1 = odpdrv_enumr_register(¶m); + CU_ASSERT(enumr1 != ODPDRV_ENUMR_INVALID); + + return 0; +} + +static int enumr_class2_probe(void) +{ + odpdrv_enumr_param_t param = { + .enumr_class = enumr_class2, + .api_name = "E2", + .api_version = 1, + .probe = enumr2_probe, + .remove = enumr2_remove, + .register_notifier = NULL + }; + + enumr2 = odpdrv_enumr_register(¶m); + CU_ASSERT(enumr2 != ODPDRV_ENUMR_INVALID); + + return 0; +} + +/*enumerator probe functions, creating four devices each: */ +static int enumr1_probe(void) +{ + int dev; + + odpdrv_device_param_t param = { + .enumerator = enumr1, + .address = "E1:00:0X", + .enum_dev = NULL + }; + + /* create devices: */ + for (dev = 0; dev < NB_DEVICES; dev++) { + param.address[7] = '0' + dev; /* change X in the address */ + param.enum_dev = NULL; + E1_devs[dev] = odpdrv_device_create(¶m); + CU_ASSERT(E1_devs[dev] != ODPDRV_DEVICE_INVALID); + } + + return 0; +} + +static int enumr2_probe(void) +{ + int dev; + + odpdrv_device_param_t param = { + .enumerator = enumr2, + .address = "E2:00:0X", + .enum_dev = NULL + }; + + /* create devices: */ + for (dev = 0; dev < NB_DEVICES; dev++) { + param.address[7] = '0' + dev; /* change X in the address */ + param.enum_dev = NULL; + E2_devs[dev] = odpdrv_device_create(¶m); + CU_ASSERT(E1_devs[dev] != ODPDRV_DEVICE_INVALID); + } + + return 0; +} + +/*enumerator remove functions, to remove the enumerated devices: */ +static int enumr1_remove(void) +{ + odpdrv_device_t *my_devices; + odpdrv_device_t *dev; + int count = 0; + + /* destroy all devices created by enumerator 5: */ + my_devices = odpdrv_device_query(enumr1, NULL); + + for (dev = my_devices; *dev != ODPDRV_DEVICE_INVALID; dev++) { + odpdrv_device_destroy(*dev, NULL, 0); + count++; + } + + CU_ASSERT(count == NB_DEVICES); + + free(my_devices); + return 0; +} + +static int enumr2_remove(void) +{ + odpdrv_device_t *my_devices; + odpdrv_device_t *dev; + int count = 0; + + /* destroy all devices created by enumerator 5: */ + my_devices = odpdrv_device_query(enumr2, NULL); + + for (dev = my_devices; *dev != ODPDRV_DEVICE_INVALID; dev++) { + odpdrv_device_destroy(*dev, NULL, 0); + count++; + } + + CU_ASSERT(count == NB_DEVICES); + + free(my_devices); + return 0; +} + +/* devios: */ +static void ODPDRV_CONSTRUCTOR devio1_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "DRVIF-1", + .api_version = 1, + .enumr_api_name = "E1", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + devio1 = odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio2_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "DRVIF-2", + .api_version = 1, + .enumr_api_name = "E2", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + devio2 = odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio3_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "DRVIF-3", + .api_version = 1, + .enumr_api_name = "E2", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + devio3 = odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio4_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "DRVIF-3", + .api_version = 1, + .enumr_api_name = "E3", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + devio4 = odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR devio5_register(void) +{ + odpdrv_devio_param_t param = { + .api_name = "DRVIF-4", + .api_version = 1, + .enumr_api_name = "E3", + .enumr_api_version = 1, + .probe = NULL, + .remove = NULL, + .ops = NULL, + }; + + devio5 = odpdrv_devio_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR driver1_register(void) +{ + odpdrv_driver_param_t param = { + .name = "driver1", + .devios = { {"DRVIF-1", 1}, {"", -1}, {"", -1} }, + .probe = driver1_probe, + .unbind = driver1_unbind, + .remove = NULL, + }; + + driver1 = odpdrv_driver_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR driver2_register(void) +{ + odpdrv_driver_param_t param = { + .name = "driver2", + .devios = { {"DRVIF-2", 1}, {"DRVIF-3", 1}, {"", -1} }, + .probe = driver2_probe, + .unbind = driver2_unbind, + .remove = NULL, + }; + + driver2 = odpdrv_driver_register(¶m); +} + +static void ODPDRV_CONSTRUCTOR driver3_register(void) +{ + odpdrv_driver_param_t param = { + .name = "driver3", + .devios = { {"DRVIF-4", 1}, {"", -1}, {"", -1} }, + .probe = driver3_probe, + .unbind = driver3_unbind, + .remove = NULL, + }; + + driver3 = odpdrv_driver_register(¶m); +} + +static int driver1_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx) +{ + int i; + int dev_found = 0; + + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + CU_ASSERT(devio == devio1); + CU_ASSERT(idx < 1); + + /*makes sure the device is from E1 */ + for (i = 0; i < NB_DEVICES; i++) { + if (dev == E1_devs[i]) { + driver1_probed_index |= (1 << i); + dev_found = 1; + } + } + CU_ASSERT(dev_found); + return 0; /* accept the device */ +} + +static int driver2_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx) +{ + int i; + int dev_found = 0; + + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + + /* check that we are probed with one of the required deviios */ + CU_ASSERT(((devio == devio2) && (idx == 0)) || + ((devio == devio3) && (idx == 1))); + + /*make sure the device is from E2, and probed twice */ + for (i = 0; i < NB_DEVICES; i++) { + if (dev == E2_devs[i]) { + /* check that device was probed with idx=0 first */ + if (idx > 0) + CU_ASSERT(driver2_probed_index & (1 << i)); + /* marked as probed: */ + driver2_probed_index |= (1 << (i + idx * NB_DEVICES)); + dev_found = 1; + } + } + CU_ASSERT(dev_found); + if (idx == 0) + return -1; /* reject the device, when probed with idx = 0 */ + return 0; /* accept second probe*/ +} + +static int driver3_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx) +{ + /* we can look for some strangeness here ... */ + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + CU_ASSERT(devio != ODPDRV_DEVIO_INVALID); + CU_ASSERT(idx >= 0); + + /* but we should not be probing this driver anyway! */ + CU_FAIL("This driver should not be probed"); + return -1; /* reject the device */ +} + +static int driver1_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags) +{ + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + CU_ASSERT(flags == ODPDRV_DRV_UNBIND_IMMEDIATE); + callback(dev); + + return 0; +} + +static int driver2_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags) +{ + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + CU_ASSERT(flags == ODPDRV_DRV_UNBIND_IMMEDIATE); + callback(dev); + + return 0; +} + +static int driver3_unbind(odpdrv_device_t dev, + void (*callback)(odpdrv_device_t dev), + uint32_t flags) +{ + CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); + CU_ASSERT(flags == ODPDRV_DRV_UNBIND_IMMEDIATE); + callback(dev); + + return 0; +} + +void drvdriver_test_driver_register(void) +{ + CU_ASSERT(enumr_class1 != ODPDRV_ENUMR_CLASS_INVALID); + CU_ASSERT(enumr_class2 != ODPDRV_ENUMR_CLASS_INVALID); + CU_ASSERT(devio1 != ODPDRV_DEVIO_INVALID); + CU_ASSERT(devio2 != ODPDRV_DEVIO_INVALID); + CU_ASSERT(devio3 != ODPDRV_DEVIO_INVALID); + CU_ASSERT(devio4 != ODPDRV_DEVIO_INVALID); + CU_ASSERT(devio5 != ODPDRV_DEVIO_INVALID); + CU_ASSERT(driver1 != ODPDRV_DRIVER_INVALID); + CU_ASSERT(driver2 != ODPDRV_DRIVER_INVALID); + CU_ASSERT(driver3 != ODPDRV_DRIVER_INVALID); + + CU_ASSERT(tests_global_init() == 0); + + CU_ASSERT(odpdrv_print_all() == 0); + + /* check that expected probing occurred: */ + CU_ASSERT(driver1_probed_index == (1 << NB_DEVICES) - 1); + CU_ASSERT(driver2_probed_index == (1 << (NB_DEVICES * 2)) - 1); + + CU_ASSERT(tests_global_term() == 0); +} + +odp_testinfo_t drvdriver_suite_driver[] = { + ODP_TEST_INFO(drvdriver_test_driver_register), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvdriver_suites_driver[] = { + {"Enumerator registration", NULL, NULL, drvdriver_suite_driver}, + ODP_SUITE_INFO_NULL, +}; + +int drvdriver_driver_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + /* prevent default ODP init: */ + odp_cunit_register_global_init(NULL); + odp_cunit_register_global_term(NULL); + + /* register the tests: */ + ret = odp_cunit_register(drvdriver_suites_driver); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_driver.h b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.h new file mode 100644 index 0000000000..d80c689002 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVDRIVER_DRIVER_H_ +#define _ODP_TEST_DRVDRIVER_DRIVER_H_ + +#include + +/* test functions: */ +void drvdriver_test_driver_register(void); + +/* test arrays: */ +extern odp_testinfo_t drvdriver_suite_driver[]; + +/* test registry: */ +extern odp_suiteinfo_t drvdriver_suites_driver[]; + +/* main test program: */ +int drvdriver_driver_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_driver_main.c b/test/common_plat/validation/drv/drvdriver/drvdriver_driver_main.c new file mode 100644 index 0000000000..671689c7a3 --- /dev/null +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_driver_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvdriver_driver.h" + +int main(int argc, char *argv[]) +{ + return drvdriver_driver_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index 7e06c8d050..7009c1110c 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -38,6 +38,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_device_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_devio_main$(EXEEXT)\ + $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_driver_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_class_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvdriver/drvdriver_enumr_main$(EXEEXT)\ $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ From 551996a6cd9be382d37a91e1b2a1be823343468c Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:28 +0100 Subject: [PATCH 21/23] drv: driver: adding functions to attach driver's data to the device Driver will need to attach their data to devices when bound. The patch introduce a data setter and a data getter function to do so. Signed-off-by: Christophe Milard --- include/odp/drv/spec/driver.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index ad2b8db2dc..224baf4fee 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -449,6 +449,27 @@ odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param); */ odpdrv_driver_t odpdrv_driver_register(odpdrv_driver_param_t *param); +/** +* Sets the device driver data, i.e. the driver data which should be attached to +* the device. +* After a driver is bound to a device, this driver will need to keep +* data attached to this device. This data is, of course, driver dependent. +* +* @param dev: the device to which data should be attached. +* @param data Pointer to whatever thre driver want to keep attached to the +* device +*/ +void odpdrv_device_set_data(odpdrv_device_t dev, void *data); + +/** +* Gets the device driver data, i.e. the driver data which should be attached to +* the device. +* Retrieve the pointer which was set with odpdrv_device_set_data() +* @param dev: the device from which the driver data should be retrieved. +* @return the driver data pointer (as set by odpdrv_device_set_data()) or NULL. +*/ +void *odpdrv_device_get_data(odpdrv_device_t dev); + /** * Print (ODP_DBG) the driver interface status (debug). * From 302bc60f0889f5815f66c54204c71af62803bf30 Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:29 +0100 Subject: [PATCH 22/23] linux-gen: adding functions to attach driver's data to the device Implementation of the functions to set/retrieve driver's data to/from a bound device. Signed-off-by: Christophe Milard --- platform/linux-generic/drv_driver.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index ca4aed9cfe..46cbdba91b 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -70,6 +70,7 @@ struct _odpdrv_device_s { odpdrv_device_param_t param; _odpdrv_driver_t *driver; /* driver for the device (if bound), or NULL*/ _odpdrv_devio_t *devio; /* devio used for device (if bound), or NULL*/ + void *driver_data; /* anything that the driver need to attach. */ void (*enumr_destroy_callback)(void *enum_dev);/*dev destroy callback */ struct _odpdrv_device_s *next; } _odpdrv_device_s; @@ -395,6 +396,7 @@ odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param) dev->enumr_destroy_callback = NULL; dev->driver = NULL; dev->devio = NULL; + dev->driver_data = NULL; dev_list_write_lock(); dev->next = device_lst.head; device_lst.head = dev; @@ -857,6 +859,22 @@ void _odpdrv_driver_probe_drv_items(void) probe_all(); } +void odpdrv_device_set_data(odpdrv_device_t dev, void *data) +{ + _odpdrv_device_t *_dev; + + _dev = get_device(dev); + _dev->driver_data = data; +} + +void *odpdrv_device_get_data(odpdrv_device_t dev) +{ + _odpdrv_device_t *_dev; + + _dev = get_device(dev); + return _dev->driver_data; +} + int odpdrv_print_all(void) { _odpdrv_enumr_class_t *enumr_c; From ba7c56a0860cd49360acfeb5967b1a92c8ad510d Mon Sep 17 00:00:00 2001 From: Christophe Milard Date: Wed, 22 Mar 2017 15:48:30 +0100 Subject: [PATCH 23/23] test: drv: test for setting and retrieving driver's data trivial tests for function odpdrv_device_set_data() and odpdrv_device_get_data(). Signed-off-by: Christophe Milard --- test/common_plat/validation/drv/drvdriver/drvdriver_driver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c index d90aa566dd..edcb0f43fd 100644 --- a/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c +++ b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c @@ -380,6 +380,8 @@ static int driver1_probe(odpdrv_device_t dev, odpdrv_devio_t devio, int idx) if (dev == E1_devs[i]) { driver1_probed_index |= (1 << i); dev_found = 1; + /* just set dev index as driver data */ + odpdrv_device_set_data(dev, (void *)(uintptr_t)i); } } CU_ASSERT(dev_found); @@ -430,6 +432,7 @@ static int driver1_unbind(odpdrv_device_t dev, void (*callback)(odpdrv_device_t dev), uint32_t flags) { + CU_ASSERT(E1_devs[(uintptr_t)odpdrv_device_get_data(dev)] == dev); CU_ASSERT(dev != ODPDRV_DEVICE_INVALID); CU_ASSERT(flags == ODPDRV_DRV_UNBIND_IMMEDIATE); callback(dev);