[API-NEXT,PATCHv2,10/23] linux-gen: drv: device creation and deletion

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

Commit Message

Christophe Milard March 22, 2017, 2:48 p.m.
Functions to create and remove devices are populated to do
more proper things.

Signed-off-by: Christophe Milard <christophe.milard@linaro.org>

---
 platform/linux-generic/drv_driver.c | 181 ++++++++++++++++++++++++++++++++++--
 1 file changed, 173 insertions(+), 8 deletions(-)

-- 
2.7.4

Patch

diff --git a/platform/linux-generic/drv_driver.c b/platform/linux-generic/drv_driver.c
index 4ade3c3..60edde1 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)
@@ -331,6 +478,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;
 }
 
@@ -347,6 +511,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();