[API-NEXT,13/21] linux-gen: drv: devio registration

Message ID 1487768164-43184-14-git-send-email-christophe.milard@linaro.org
State New
Headers show
Series
  • driver items registration and probing
Related show

Commit Message

Christophe Milard Feb. 22, 2017, 12:55 p.m.
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>

---
 platform/linux-generic/drv_driver.c | 134 +++++++++++++++++++++++++++++++++++-
 1 file changed, 131 insertions(+), 3 deletions(-)

-- 
2.7.4

Comments

Bill Fischofer Feb. 22, 2017, 10:54 p.m. | #1
On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard <
christophe.milard@linaro.org> wrote:

> 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>

> ---

>  platform/linux-generic/drv_driver.c | 134 ++++++++++++++++++++++++++++++

> +++++-

>  1 file changed, 131 insertions(+), 3 deletions(-)

>

> diff --git a/platform/linux-generic/drv_driver.c

> b/platform/linux-generic/drv_driver.c

> index 517a3c6..eb0dc48 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)

>


Same comment on the need for these guards.


> +               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);

> +}

> +

>  odpdrv_enumr_class_t odpdrv_enumr_class_register(od

> pdrv_enumr_class_param_t

>                                                  *param)

>  {

> @@ -415,10 +454,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;

>


Same comment on needing to initialize the head field (should be done at
init time along with the lock).


> +       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.

>


Ah, I missed this point in my earlier comments. This explains the
init_global_status checks. So I withdraw my earlier comments. However this
highly useful comment should really be highlighted in other routines that
use this convention as the reader may not catch the implications of using
constructor functions in this regard.


> +        */

> +

> +       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)

> @@ -469,6 +563,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)

> @@ -519,6 +614,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;

>  }

>

> @@ -536,6 +646,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();

> @@ -553,12 +664,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) {

> --

> 2.7.4

>

>
Christophe Milard Feb. 27, 2017, 1:53 p.m. | #2
On 22 February 2017 at 23:54, Bill Fischofer <bill.fischofer@linaro.org> wrote:
>

>

> On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard

> <christophe.milard@linaro.org> wrote:

>>

>> 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>

>> ---

>>  platform/linux-generic/drv_driver.c | 134

>> +++++++++++++++++++++++++++++++++++-

>>  1 file changed, 131 insertions(+), 3 deletions(-)

>>

>> diff --git a/platform/linux-generic/drv_driver.c

>> b/platform/linux-generic/drv_driver.c

>> index 517a3c6..eb0dc48 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)

>

>

> Same comment on the need for these guards.


same answer :-)

>

>>

>> +               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);

>> +}

>> +

>>  odpdrv_enumr_class_t

>> odpdrv_enumr_class_register(odpdrv_enumr_class_param_t

>>                                                  *param)

>>  {

>> @@ -415,10 +454,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;

>

>

> Same comment on needing to initialize the head field (should be done at init

> time along with the lock).


same answer :-)

>

>>

>> +       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.

>

>

> Ah, I missed this point in my earlier comments. This explains the

> init_global_status checks. So I withdraw my earlier comments. However this

> highly useful comment should really be highlighted in other routines that

> use this convention as the reader may not catch the implications of using

> constructor functions in this regard.


I thought I did write this comment everywhere it was needed. Can you
pinpoint where you wished to have it more precisely?
Thanks,

Christophe.

>

>>

>> +        */

>> +

>> +       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)

>> @@ -469,6 +563,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)

>> @@ -519,6 +614,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;

>>  }

>>

>> @@ -536,6 +646,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();

>> @@ -553,12 +664,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) {

>> --

>> 2.7.4

>>

>

Patch hide | download patch | download mbox

diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c
index 517a3c6..eb0dc48 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);
+}
+
 odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t
 						 *param)
 {
@@ -415,10 +454,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)
@@ -469,6 +563,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)
@@ -519,6 +614,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;
 }
 
@@ -536,6 +646,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();
@@ -553,12 +664,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) {