This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "".
The branch, cloud-dev has been updated via f2a1712bdb379b2eb2c6e470a2f2d9a1302f344f (commit) via 1044bb4d313b092434713597a9ce2f55762e7080 (commit) via d67b84aa7b6a55e4a23f35e1d37e4a43e79c0d41 (commit) via 795e251041fbddb7d7aa711a80818eebf334abf3 (commit) via c80b492e101b22ea91c7e57de9dde18be9f23ccc (commit) via 07282993875a1b499d0d66de410a50570602a9fa (commit) via 3560e872436e9b8cca6876c7c6a5d700688d40b8 (commit) via 37250e4f9a54a8ce4ed2b9e78da77c6d4e1750fe (commit) via 5a99ab755e9eac9e47c299ef8e27f0284edf5855 (commit) via 9746fb9bfb8630336a4599147901ee898097c181 (commit) via b56dd29e0ceb58ea13523b69dc7d87c6edf83de2 (commit) via b53d8eaa4739029a8913bfaecdfb3fa84b3fe335 (commit) via 2bc1b19af71e4b28ba2d97b299491cbf0588069a (commit) via ef2b1db342e9b1ee15a32e2c1ead25f1840bfeff (commit) via 9922327d4f004f1f681816c54772d66458169668 (commit) via 5aff171af28a1de4beaf5caae9161371f9031214 (commit) via ebc4fe8c214d96e7edab2baa3e7c85420bcabc26 (commit) via 5427231909713dc599dc8c9dae95f564142e7f21 (commit) via 0652613e539726deedfe0e74bf028beb8ad6ec38 (commit) via 564b3ab494c4826b201ee8678966daf949052ae0 (commit) via 3f225d4695712b6123497089ad9eb9ea64d98ec3 (commit) via c58d79c4bb8c34bf3a2405dfdaf3b5648fab5965 (commit) via f390ad8a29e1ff4da557ba63d9375f8e744fbe1e (commit) via f15441382809525bea73554ccba9ca44d0337466 (commit) via d2562fb0cb2c2b21b628b265ef24a6c8cbac9608 (commit) via f4386378e466a519d8f97923ba43ea22dec1e933 (commit) via 826ee894aa0ebd09d42a17e1de077c46bc5b366a (commit) via 191ee818e5951e8334ec54d40d5b02065ee33c5c (commit) via 3ca26420f0e06fdb1b2cb9192461dbc32a421de5 (commit) via b50cf14202528e986ae9a41721fae1e746078646 (commit) from f4c213cccc49b4b28557506ad19fba49b872d24f (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit f2a1712bdb379b2eb2c6e470a2f2d9a1302f344f Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:30 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c b/test/common_plat/validation/drv/drvdriver/drvdriver_driver.c index d90aa566..edcb0f43 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);
commit 1044bb4d313b092434713597a9ce2f55762e7080 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:29 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index ca4aed9c..46cbdba9 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;
commit d67b84aa7b6a55e4a23f35e1d37e4a43e79c0d41 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:28 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index ad2b8db2..224baf4f 100644 --- a/include/odp/drv/spec/driver.h +++ b/include/odp/drv/spec/driver.h @@ -450,6 +450,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). * * @return 0 on success, less than zero on error (inconsistency detected)
commit 795e251041fbddb7d7aa711a80818eebf334abf3 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:27 2017 +0100
test: drv: driver registration and probing
Register driver, devios, enumerators, create devices, and check that probing occurs correctely.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 829c8b4d..76bb6baf 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 8e695ba3..88bd828a 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 00000000..d90aa566 --- /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 <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvdriver_driver.h" +#include <stdlib.h> + +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 00000000..d80c6890 --- /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 <odp_cunit_common.h> + +/* 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 00000000..671689c7 --- /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 7e06c8d0..7009c111 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) \
commit c80b492e101b22ea91c7e57de9dde18be9f23ccc Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:26 2017 +0100
linux-gen: driver registration and probing
Driver registration and probing is implemented for linux-gen ODP.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 367141dd..ca4aed9c 100644 --- a/platform/linux-generic/drv_driver.c +++ b/platform/linux-generic/drv_driver.c @@ -12,6 +12,7 @@ #include <odp/api/std_types.h> #include <odp/api/debug.h> #include <odp/api/rwlock_recursive.h> +#include <odp/api/ticketlock.h> #include <odp/drv/driver.h> #include <odp/drv/spec/driver.h> #include <odp_debug_internal.h> @@ -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 : "<none>", + dev->devio ? dev->devio->param.api_name : "<none>", + 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) {
commit 07282993875a1b499d0d66de410a50570602a9fa Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:25 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 394aa920..ad2b8db2 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
commit 3560e872436e9b8cca6876c7c6a5d700688d40b8 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:24 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index f89c282e..394aa920 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 */
commit 37250e4f9a54a8ce4ed2b9e78da77c6d4e1750fe Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:23 2017 +0100
test: drv: devio creation and destruction
Testing that devios can be registered and removed in/from ODP.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 97b4312b..829c8b4d 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 544586cb..8e695ba3 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 00000000..cf7c7c93 --- /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 <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvdriver_devio.h" +#include <stdlib.h> + +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 00000000..eea9623f --- /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 <odp_cunit_common.h> + +/* 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 00000000..10733adf --- /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 d483f9f3..7e06c8d0 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) \
commit 5a99ab755e9eac9e47c299ef8e27f0284edf5855 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:22 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 3a422e14..367141dd 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) {
commit 9746fb9bfb8630336a4599147901ee898097c181 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:21 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index e8613964..f89c282e 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) */
commit b56dd29e0ceb58ea13523b69dc7d87c6edf83de2 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:20 2017 +0100
test: drv: device creation and destruction
Testing that devices can be created and removed from ODP.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index a8424489..97b4312b 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 3476c50e..544586cb 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 00000000..d010026f --- /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 <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvdriver_device.h" +#include <stdlib.h> + +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 00000000..afc04c59 --- /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 <odp_cunit_common.h> + +/* 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 00000000..27de9c5b --- /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 ba8c129a..d483f9f3 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) \
commit b53d8eaa4739029a8913bfaecdfb3fa84b3fe335 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:19 2017 +0100
linux-gen: drv: driver: adding device query function
Implementation of the device query function for the linux-gen ODP.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 6cdae603..3a422e14 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.",
commit 2bc1b19af71e4b28ba2d97b299491cbf0588069a Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:18 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 9643268f..e8613964 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.
commit ef2b1db342e9b1ee15a32e2c1ead25f1840bfeff Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:17 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 8ceea6b1..6cdae603 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();
commit 9922327d4f004f1f681816c54772d66458169668 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:16 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index 8ff856c0..9643268f 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 df6d77d7..8ceea6b1 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)
commit 5aff171af28a1de4beaf5caae9161371f9031214 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:15 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index b08d7fb7..8ff856c0 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.
commit ebc4fe8c214d96e7edab2baa3e7c85420bcabc26 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:14 2017 +0100
test: drv: enumerator registration tests
making sure that enumerators are probed.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/validation/drv/drvdriver/.gitignore b/test/common_plat/validation/drv/drvdriver/.gitignore index 9268315e..a8424489 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 9e941eed..3476c50e 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 00000000..38aac3d0 --- /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 <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvdriver_enumr.h" +#include <stdlib.h> + +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 00000000..afe814ac --- /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 <odp_cunit_common.h> + +/* 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 00000000..53bc192e --- /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 38be049e..ba8c129a 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)
commit 5427231909713dc599dc8c9dae95f564142e7f21 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:13 2017 +0100
linux-gen: drv: enumerator registration
The enumerator registration functions for the linux-gen ODP implementation.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c index 29608210..df6d77d7 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) {
commit 0652613e539726deedfe0e74bf028beb8ad6ec38 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:12 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/test/common_plat/m4/configure.m4 b/test/common_plat/m4/configure.m4 index 13a13bd5..400750c6 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 bcdb92e2..7329a89b 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 00000000..9268315e --- /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 00000000..9e941eed --- /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 00000000..f7dd42cf --- /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 <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvdriver_enumr_class.h" +#include <stdlib.h> + +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 00000000..a4f6cdc7 --- /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 <odp_cunit_common.h> + +/* 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 00000000..45a4c1a1 --- /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 7f2a933e..38be049e 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)
commit 564b3ab494c4826b201ee8678966daf949052ae0 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:11 2017 +0100
linux-gen: drv: enumerator_class registration
The functions to register and probe enumerator classes are added.
Signed-off-by: Christophe Milard christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index bcf1dde9..7cf16dac 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 6bb854e9..b23c81fe 100644 --- a/platform/linux-generic/_modules.c +++ b/platform/linux-generic/_modules.c @@ -9,6 +9,7 @@ #include <odp/api/std_types.h> #include <odp/api/debug.h> #include <odp_debug_internal.h> +#include <drv_driver_internal.h> #include <libconfig.h> #include <dlfcn.h>
@@ -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 529da48f..29608210 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 <string.h> + #include <odp_config_internal.h> +#include <_ishmpool_internal.h>
#include <odp/api/std_types.h> #include <odp/api/debug.h> +#include <odp/api/rwlock_recursive.h> #include <odp/drv/driver.h> +#include <odp/drv/spec/driver.h> #include <odp_debug_internal.h> +#include <drv_driver_internal.h> + +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 00000000..eb06c1b4 --- /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 <sys/types.h> + +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 90e2a629..fa441488 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 685e02fa..c59cc281 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;
commit 3f225d4695712b6123497089ad9eb9ea64d98ec3 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:10 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/driver.h b/include/odp/drv/spec/driver.h index d83e907c..b08d7fb7 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];
commit c58d79c4bb8c34bf3a2405dfdaf3b5648fab5965 Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:09 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp_drv.h b/include/odp_drv.h index 96d81ba6..cdba2262 100644 --- a/include/odp_drv.h +++ b/include/odp_drv.h @@ -24,6 +24,7 @@ extern C { #include <odp/drv/byteorder.h> #include <odp/drv/compiler.h> #include <odp/drv/driver.h> +#include <odp/drv/hints.h> #include <odp/drv/shm.h> #include <odp/drv/spinlock.h> #include <odp/drv/std_types.h> diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 79f0e70c..bcf1dde9 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 00000000..808c22ca --- /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 <odp/drv/spec/hints.h> + +#ifdef __cplusplus +} +#endif + +#endif
commit f390ad8a29e1ff4da557ba63d9375f8e744fbe1e Author: Christophe Milard christophe.milard@linaro.org Date: Wed Mar 22 15:48:08 2017 +0100
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 christophe.milard@linaro.org Reviewed-and-tested-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/include/odp/drv/spec/hints.h b/include/odp/drv/spec/hints.h new file mode 100644 index 00000000..f29dcd88 --- /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 <odp/visibility_begin.h> + +#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 <odp/visibility_end.h> +#endif diff --git a/platform/Makefile.inc b/platform/Makefile.inc index 3d609aa7..2b897093 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 \
-----------------------------------------------------------------------
Summary of changes: .codecov.yml | 14 +- .travis.yml | 31 +- example/generator/odp_generator.c | 20 +- include/odp/drv/spec/driver.h | 132 ++- include/odp/drv/spec/hints.h | 119 +++ include/odp_drv.h | 1 + platform/Makefile.inc | 1 + platform/linux-generic/Makefile.am | 2 + platform/linux-generic/_modules.c | 4 + platform/linux-generic/drv_driver.c | 1057 +++++++++++++++++++- .../cpu_flags.h => include/drv_driver_internal.h} | 8 +- .../include/odp/{api/support.h => drv/hints.h} | 10 +- platform/linux-generic/include/odp_internal.h | 5 + platform/linux-generic/odp_crypto.c | 2 +- platform/linux-generic/odp_init.c | 21 +- scripts/checkpatch.pl | 6 +- scripts/ci-checkpatches.sh | 17 + test/common_plat/m4/configure.m4 | 1 + .../validation/api/crypto/odp_crypto_test_inp.c | 40 + test/common_plat/validation/drv/Makefile.am | 1 + .../validation/drv/drvdriver/.gitignore | 5 + .../validation/drv/drvdriver/Makefile.am | 60 ++ .../validation/drv/drvdriver/drvdriver_device.c | 218 ++++ .../validation/drv/drvdriver/drvdriver_device.h | 24 + .../drvdriver/drvdriver_device_main.c} | 4 +- .../validation/drv/drvdriver/drvdriver_devio.c | 209 ++++ .../validation/drv/drvdriver/drvdriver_devio.h | 24 + .../drvdriver/drvdriver_devio_main.c} | 4 +- .../validation/drv/drvdriver/drvdriver_driver.c | 518 ++++++++++ .../validation/drv/drvdriver/drvdriver_driver.h | 24 + .../drvdriver/drvdriver_driver_main.c} | 4 +- .../validation/drv/drvdriver/drvdriver_enumr.c | 303 ++++++ .../validation/drv/drvdriver/drvdriver_enumr.h | 24 + .../drv/drvdriver/drvdriver_enumr_class.c | 174 ++++ .../drv/drvdriver/drvdriver_enumr_class.h | 24 + .../drvdriver/drvdriver_enumr_class_main.c} | 4 +- .../drvdriver/drvdriver_enumr_main.c} | 4 +- test/linux-generic/Makefile.am | 5 + 38 files changed, 3045 insertions(+), 79 deletions(-) create mode 100644 include/odp/drv/spec/hints.h copy platform/linux-generic/{arch/x86/cpu_flags.h => include/drv_driver_internal.h} (59%) copy platform/linux-generic/include/odp/{api/support.h => drv/hints.h} (59%) create mode 100755 scripts/ci-checkpatches.sh 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_device.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_device.h copy test/common_plat/validation/{api/ipsec/ipsec_main.c => drv/drvdriver/drvdriver_device_main.c} (67%) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_devio.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_devio.h copy test/common_plat/validation/{api/ipsec/ipsec_main.c => drv/drvdriver/drvdriver_devio_main.c} (68%) create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_driver.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_driver.h copy test/common_plat/validation/{api/ipsec/ipsec_main.c => drv/drvdriver/drvdriver_driver_main.c} (67%) 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_class.c create mode 100644 test/common_plat/validation/drv/drvdriver/drvdriver_enumr_class.h copy test/common_plat/validation/{api/ipsec/ipsec_main.c => drv/drvdriver/drvdriver_enumr_class_main.c} (64%) copy test/common_plat/validation/{api/ipsec/ipsec_main.c => drv/drvdriver/drvdriver_enumr_main.c} (68%)
hooks/post-receive