Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01f20206 authored by Sumukh Hallymysore Ravindra's avatar Sumukh Hallymysore Ravindra
Browse files

msm: synx: support for external dma fence



Changes to support synx framework with both internally
created dma fences and as a wrapper to externally
managed dma fences.
Accepts the external dma fence and binds to existing
synx object through the synx_export api. A new api
added to return the dma fence backing the synx object.
Modifications to object creation, management and cleanup
due to the support for external dma fences. Each synx
object holds single reference to the underlying dma fence
and multiple client references to the synx object is
managed through the reference counts maintained per
client handle.
Added mutex lock to handle the critical section with
synx objects. Non interruptible spin locks will be used
when required to update backing fence.

Change-Id: I94a77436e0c2379e3be5227dfb1ce835dc109ea5
Signed-off-by: default avatarSumukh Hallymysore Ravindra <shallymy@codeaurora.org>
parent d5ee68b8
Loading
Loading
Loading
Loading
+254 −193
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/poll.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/vmalloc.h>
@@ -17,42 +18,10 @@


struct synx_device *synx_dev;
struct synx_device *synx_dev;


static int synx_validate_callback(
	struct synx_coredata *synx_obj,
	s32 sync_id,
	void *data)
{
	u32 i;
	int rc = -EINVAL;
	struct synx_bind_desc *bind_desc = NULL;

	if (!synx_obj)
		return -EINVAL;

	/* need to validate the callback
	 * as it could be dispatched and/or
	 * scheduled late, after the handle
	 * has been released and re-allocated.
	 */
	spin_lock_bh(&synx_obj->lock);
	for (i = 0; i < synx_obj->num_bound_synxs; i++) {
		bind_desc = &synx_obj->bound_synxs[i];
		if ((sync_id ==
			bind_desc->external_desc.id[0]) &&
			(data == bind_desc->external_data)) {
			rc = 0;
			pr_debug("callback validation success %d\n",
				sync_id);
			break;
		}
	}
	spin_unlock_bh(&synx_obj->lock);

	return rc;
}

void synx_external_callback(s32 sync_obj, int status, void *data)
void synx_external_callback(s32 sync_obj, int status, void *data)
{
{
	int rc;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;
	struct synx_client *client = NULL;
	struct synx_client *client = NULL;
	struct synx_external_data *bind_data = data;
	struct synx_external_data *bind_data = data;
@@ -70,28 +39,28 @@ void synx_external_callback(s32 sync_obj, int status, void *data)
		goto free;
		goto free;
	}
	}


	synx_obj = synx_util_acquire_object(client, bind_data->h_synx);
	synx_data = synx_util_acquire_handle(client, bind_data->h_synx);
	if (!synx_obj) {
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("[sess: %u] invalid callback from external obj %d handle %d\n",
		pr_err("[sess: %u] invalid callback from external obj %d handle %d\n",
			client->id, sync_obj, bind_data->h_synx);
			client->id, sync_obj, bind_data->h_synx);
		goto fail;
		goto fail;
	}
	}


	if (synx_validate_callback(synx_obj, sync_obj, data)) {
		pr_err("[sess: %u] stale callback from external obj %d handle %d\n",
			client->id, sync_obj, bind_data->h_synx);
		goto release;
	}

	pr_debug("[sess: %u] external callback from %d on handle %d\n",
	pr_debug("[sess: %u] external callback from %d on handle %d\n",
		client->id, sync_obj, bind_data->h_synx);
		client->id, sync_obj, bind_data->h_synx);
	if (synx_signal_core(synx_obj, status, true, sync_obj))
		pr_err("[sess: %u] signal callback failed for handle %d\n",
			client->id, bind_data->h_synx);


release:
	mutex_lock(&synx_obj->obj_lock);
	synx_util_release_object(client, bind_data->h_synx);
	rc = synx_signal_fence(synx_obj, status);
	if (rc)
		pr_err("[sess: %u] signaling failed for handle %d with err: %d\n",
			client->id, bind_data->h_synx, rc);
	else
		synx_signal_core(synx_obj, status, true, sync_obj);
	mutex_unlock(&synx_obj->obj_lock);

fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
free:
free:
	kfree(bind_data);
	kfree(bind_data);
@@ -110,10 +79,10 @@ const char *synx_fence_driver_name(struct dma_fence *fence)


void synx_fence_release(struct dma_fence *fence)
void synx_fence_release(struct dma_fence *fence)
{
{
	struct synx_coredata *synx_obj =
	/* release the memory allocated during create */
		container_of(fence, struct synx_coredata, fence);
	kfree(fence->lock);

	kfree(fence);
	synx_util_object_destroy(synx_obj);
	pr_debug("released synx backing fence %pK\n", fence);
}
}
EXPORT_SYMBOL(synx_fence_release);
EXPORT_SYMBOL(synx_fence_release);


@@ -125,6 +94,44 @@ static struct dma_fence_ops synx_fence_ops = {
	.release = synx_fence_release,
	.release = synx_fence_release,
};
};


struct dma_fence *synx_get_fence(struct synx_session session_id,
	s32 h_synx)
{
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct dma_fence *fence = NULL;

	pr_debug("[sess: %u] Enter from pid %d\n",
		session_id.client_id, current->pid);

	client = synx_get_client(session_id);
	if (!client)
		return NULL;

	synx_data = synx_util_acquire_handle(client, h_synx);
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
		goto fail;
	}

	mutex_lock(&synx_obj->obj_lock);
	fence = synx_obj->fence;
	/* obtain an additional reference to the fence */
	dma_fence_get(fence);
	mutex_unlock(&synx_obj->obj_lock);

fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	pr_debug("[sess: %u] Exit from pid %d\n",
		session_id.client_id, current->pid);
	return fence;
}
EXPORT_SYMBOL(synx_get_fence);

int synx_create(struct synx_session session_id,
int synx_create(struct synx_session session_id,
	struct synx_create_params *params)
	struct synx_create_params *params)
{
{
@@ -166,23 +173,14 @@ int synx_create(struct synx_session session_id,
		goto clean_up;
		goto clean_up;
	}
	}


	rc = synx_util_activate(synx_obj);
	if (rc) {
		pr_err("[sess: %u] unable to activate handle %ld\n",
			client->id, h_synx);
		goto clear_bit;
		return -EINVAL;
	}

	*params->h_synx = h_synx;
	*params->h_synx = h_synx;
	pr_debug("[sess: %u] new synx obj with handle %ld\n",
	pr_debug("[sess: %u] new synx obj with handle %ld, fence %pK\n",
		client->id, h_synx);
		client->id, h_synx, synx_obj);
	synx_put_client(client);
	synx_put_client(client);
	return 0;
	return 0;


clear_bit:
	clear_bit(h_synx, client->bitmap);
clean_up:
clean_up:
	dma_fence_put(synx_obj->fence);
	kfree(synx_obj);
	kfree(synx_obj);
fail:
fail:
	synx_put_client(client);
	synx_put_client(client);
@@ -195,12 +193,11 @@ int synx_signal_core(struct synx_coredata *synx_obj,
	bool cb_signal,
	bool cb_signal,
	s32 ext_sync_id)
	s32 ext_sync_id)
{
{
	int rc, ret;
	int rc = 0, ret;
	u32 i = 0;
	u32 i = 0;
	u32 idx = 0;
	u32 idx = 0;
	s32 sync_id;
	s32 sync_id;
	u32 type;
	u32 type;
	struct dma_fence *fence;
	struct synx_external_data *data = NULL;
	struct synx_external_data *data = NULL;
	struct synx_bind_desc bind_descs[SYNX_MAX_NUM_BINDINGS];
	struct synx_bind_desc bind_descs[SYNX_MAX_NUM_BINDINGS];
	struct bind_operations *bind_ops = NULL;
	struct bind_operations *bind_ops = NULL;
@@ -208,37 +205,6 @@ int synx_signal_core(struct synx_coredata *synx_obj,
	if (!synx_obj)
	if (!synx_obj)
		return -EINVAL;
		return -EINVAL;


	if (status < SYNX_STATE_SIGNALED_SUCCESS) {
		pr_err("signaling with undefined status = %d\n", status);
		return -EINVAL;
	}

	if (synx_util_is_merged_object(synx_obj)) {
		pr_err("signaling a composite synx object\n");
		return -EINVAL;
	}

	spin_lock_bh(&synx_obj->lock);

	if (synx_util_get_object_status_locked(synx_obj) != SYNX_STATE_ACTIVE) {
		spin_unlock_bh(&synx_obj->lock);
		return -EALREADY;
	}

	fence = synx_util_get_fence(synx_obj);
	/* set fence error to model {signal w/ error} */
	if (status != SYNX_STATE_SIGNALED_SUCCESS)
		dma_fence_set_error(fence, -status);

	rc = dma_fence_signal_locked(fence);
	if (rc) {
		pr_err("signaling object failed with err: %d\n", rc);
		if (status == SYNX_STATE_SIGNALED_SUCCESS) {
			status = SYNX_STATE_SIGNALED_ERROR;
			dma_fence_set_error(fence, -status);
		}
	}

	synx_util_callback_dispatch(synx_obj, status);
	synx_util_callback_dispatch(synx_obj, status);


	/*
	/*
@@ -268,7 +234,6 @@ int synx_signal_core(struct synx_coredata *synx_obj,
		}
		}
		synx_obj->num_bound_synxs = 0;
		synx_obj->num_bound_synxs = 0;
	}
	}
	spin_unlock_bh(&synx_obj->lock);


	for (i = 0; i < idx; i++) {
	for (i = 0; i < idx; i++) {
		sync_id = bind_descs[i].external_desc.id[0];
		sync_id = bind_descs[i].external_desc.id[0];
@@ -294,11 +259,9 @@ int synx_signal_core(struct synx_coredata *synx_obj,
		/* optional function to enable external signaling */
		/* optional function to enable external signaling */
		if (bind_ops->enable_signaling) {
		if (bind_ops->enable_signaling) {
			ret = bind_ops->enable_signaling(sync_id);
			ret = bind_ops->enable_signaling(sync_id);
			if (ret < 0) {
			if (ret < 0)
				pr_err("enabling fail on %d, type: %u, err: %d\n",
				pr_err("enabling fail on %d, type: %u, err: %d\n",
					sync_id, type, ret);
					sync_id, type, ret);
				continue;
			}
		}
		}
		ret = bind_ops->signal(sync_id, status);
		ret = bind_ops->signal(sync_id, status);
		if (ret < 0)
		if (ret < 0)
@@ -315,10 +278,75 @@ int synx_signal_core(struct synx_coredata *synx_obj,
	return rc;
	return rc;
}
}


static int synx_signal_global(struct synx_coredata *synx_obj)
{
	return 0;
}

void synx_fence_callback(struct dma_fence *fence,
	struct dma_fence_cb *cb)
{
	struct synx_coredata *synx_obj =
		container_of(cb, struct synx_coredata, fence_cb);

	synx_signal_global(synx_obj);
}
EXPORT_SYMBOL(synx_fence_callback);

int synx_signal_fence(struct synx_coredata *synx_obj,
	u32 status)
{
	int rc = 0;
	unsigned long flags;

	if (!synx_obj || !synx_obj->fence)
		return -EINVAL;

	if (status < SYNX_STATE_SIGNALED_SUCCESS) {
		pr_err("signaling with wrong status = %u\n",
			status);
		return -EINVAL;
	}

	if (synx_util_is_merged_object(synx_obj)) {
		pr_err("signaling a composite object\n");
		return -EINVAL;
	}

	/*
	 * remove registered callback for the fence
	 * so it does not invoke the signal through callback again
	 */
	if (!dma_fence_remove_callback(synx_obj->fence,
		&synx_obj->fence_cb)) {
		pr_err("synx callback could not be removed\n");
		return -EINVAL;
	}

	spin_lock_irqsave(synx_obj->fence->lock, flags);
	if (synx_util_get_object_status_locked(synx_obj) !=
		SYNX_STATE_ACTIVE) {
		spin_unlock_irqrestore(synx_obj->fence->lock, flags);
		return -EALREADY;
	}

	/* set fence error to model {signal w/ error} */
	if (status != SYNX_STATE_SIGNALED_SUCCESS)
		dma_fence_set_error(synx_obj->fence, -status);

	rc = dma_fence_signal_locked(synx_obj->fence);
	if (rc)
		pr_err("signaling object failed with err: %d\n", rc);
	spin_unlock_irqrestore(synx_obj->fence->lock, flags);

	return rc;
}

int synx_signal(struct synx_session session_id, s32 h_synx, u32 status)
int synx_signal(struct synx_session session_id, s32 h_synx, u32 status)
{
{
	int rc = 0;
	int rc = 0;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;


	pr_debug("[sess: %u] Enter signal from pid %d\n",
	pr_debug("[sess: %u] Enter signal from pid %d\n",
@@ -328,21 +356,26 @@ int synx_signal(struct synx_session session_id, s32 h_synx, u32 status)
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	if (!synx_obj) {
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
		goto fail;
		goto fail;
	}
	}


	rc = synx_signal_core(synx_obj, status, false, 0);
	mutex_lock(&synx_obj->obj_lock);
	rc = synx_signal_fence(synx_obj, status);
	if (rc)
	if (rc)
		pr_err("[sess: %u] signaling failed for handle %d with err: %d\n",
		pr_err("[sess: %u] signaling failed for handle %d with err: %d\n",
			client->id, h_synx, rc);
			client->id, h_synx, rc);
	synx_util_release_object(client, h_synx);
	else
		rc = synx_signal_core(synx_obj, status, false, 0);
	mutex_unlock(&synx_obj->obj_lock);


fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit signal with status %d\n",
	pr_debug("[sess: %u] exit signal with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -382,6 +415,7 @@ int synx_register_callback(struct synx_session session_id,
	u32 idx;
	u32 idx;
	u32 status;
	u32 status;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;
	struct synx_cb_data *synx_cb;
	struct synx_cb_data *synx_cb;
	struct synx_kernel_payload payload;
	struct synx_kernel_payload payload;
@@ -393,7 +427,8 @@ int synx_register_callback(struct synx_session session_id,
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj) {
	if (!synx_obj) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
@@ -401,15 +436,18 @@ int synx_register_callback(struct synx_session session_id,
		goto fail;
		goto fail;
	}
	}


	if (synx_util_is_merged_object(synx_obj)) {
	mutex_lock(&synx_obj->obj_lock);
	if (synx_util_is_merged_object(synx_obj) ||
		synx_util_is_external_object(synx_obj)) {
		pr_err("cannot register cb with composite synx object\n");
		pr_err("cannot register cb with composite synx object\n");
		goto clear;
		rc = -EINVAL;
		goto release;
	}
	}


	synx_cb = kzalloc(sizeof(*synx_cb), GFP_ATOMIC);
	synx_cb = kzalloc(sizeof(*synx_cb), GFP_ATOMIC);
	if (!synx_cb) {
	if (!synx_cb) {
		rc = -ENOMEM;
		rc = -ENOMEM;
		goto clear;
		goto release;
	}
	}


	payload.h_synx = h_synx;
	payload.h_synx = h_synx;
@@ -422,11 +460,10 @@ int synx_register_callback(struct synx_session session_id,
		pr_err("[sess :%u] error allocating cb entry\n",
		pr_err("[sess :%u] error allocating cb entry\n",
			client->id);
			client->id);
		kfree(synx_cb);
		kfree(synx_cb);
		goto clear;
		goto release;
	}
	}


	spin_lock_bh(&synx_obj->lock);
	status = synx_util_get_object_status(synx_obj);
	status = synx_util_get_object_status_locked(synx_obj);
	synx_cb->session_id = session_id;
	synx_cb->session_id = session_id;
	synx_cb->idx = idx;
	synx_cb->idx = idx;
	INIT_WORK(&synx_cb->cb_dispatch, synx_util_cb_dispatch);
	INIT_WORK(&synx_cb->cb_dispatch, synx_util_cb_dispatch);
@@ -441,11 +478,11 @@ int synx_register_callback(struct synx_session session_id,
		queue_work(synx_dev->work_queue,
		queue_work(synx_dev->work_queue,
			&synx_cb->cb_dispatch);
			&synx_cb->cb_dispatch);
	}
	}
	spin_unlock_bh(&synx_obj->lock);


clear:
release:
	synx_util_release_object(client, h_synx);
	mutex_unlock(&synx_obj->obj_lock);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit register cb with status %d\n",
	pr_debug("[sess: %u] exit register cb with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -463,6 +500,7 @@ int synx_deregister_callback(struct synx_session session_id,
	u32 status;
	u32 status;
	bool match_found = false;
	bool match_found = false;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;
	struct synx_kernel_payload payload;
	struct synx_kernel_payload payload;
	struct synx_cb_data *synx_cb, *synx_cb_temp;
	struct synx_cb_data *synx_cb, *synx_cb_temp;
@@ -475,7 +513,8 @@ int synx_deregister_callback(struct synx_session session_id,
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj) {
	if (!synx_obj) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
@@ -483,9 +522,11 @@ int synx_deregister_callback(struct synx_session session_id,
		goto fail;
		goto fail;
	}
	}


	if (synx_util_is_merged_object(synx_obj)) {
	mutex_lock(&synx_obj->obj_lock);
	if (synx_util_is_merged_object(synx_obj) ||
		synx_util_is_external_object(synx_obj)) {
		pr_err("cannot deregister cb with composite synx object\n");
		pr_err("cannot deregister cb with composite synx object\n");
		goto clear;
		goto release;
	}
	}


	payload.h_synx = h_synx;
	payload.h_synx = h_synx;
@@ -493,14 +534,12 @@ int synx_deregister_callback(struct synx_session session_id,
	payload.data = userdata;
	payload.data = userdata;
	payload.cancel_cb_func = cancel_cb_func;
	payload.cancel_cb_func = cancel_cb_func;


	spin_lock_bh(&synx_obj->lock);
	status = synx_util_get_object_status(synx_obj);
	status = synx_util_get_object_status_locked(synx_obj);
	if (status != SYNX_STATE_ACTIVE) {
	if (status != SYNX_STATE_ACTIVE) {
		pr_err("handle %d already signaled. cannot deregister cb/s\n",
		pr_err("handle %d already signaled. cannot deregister cb/s\n",
			h_synx);
			h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
		spin_unlock_bh(&synx_obj->lock);
		goto release;
		goto clear;
	}
	}


	status = SYNX_CALLBACK_RESULT_CANCELED;
	status = SYNX_CALLBACK_RESULT_CANCELED;
@@ -546,16 +585,15 @@ int synx_deregister_callback(struct synx_session session_id,
			break;
			break;
		}
		}
	}
	}
	spin_unlock_bh(&synx_obj->lock);


	if (!match_found)
	if (!match_found)
		rc = -EINVAL;
		rc = -EINVAL;


clear:
release:
	synx_util_release_object(client, h_synx);
	mutex_unlock(&synx_obj->obj_lock);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	return rc;


	pr_debug("[sess: %u] exit deregister cb with status %d\n",
	pr_debug("[sess: %u] exit deregister cb with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -614,29 +652,21 @@ int synx_merge(struct synx_session session_id,
	if (rc) {
	if (rc) {
		pr_err("[sess: %u] unable to init merge handle %ld\n",
		pr_err("[sess: %u] unable to init merge handle %ld\n",
			client->id, h_synx);
			client->id, h_synx);
		dma_fence_put(synx_obj->fence);
		goto clean_up;
		goto clean_up;
	}
	}


	rc = synx_util_activate(synx_obj);
	if (rc) {
		pr_err("[sess: %u] unable to activate merge handle %ld\n",
			client->id, h_synx);
		goto clear_bit;
	}

	*h_synx_merged = h_synx;
	*h_synx_merged = h_synx;
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit merge with status %d\n",
	pr_debug("[sess: %u] exit merge with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
	return 0;
	return 0;


clear_bit:
	clear_bit(h_synx, client->bitmap);
clean_up:
clean_up:
	kfree(synx_obj);
	kfree(synx_obj);
fail:
fail:
	synx_util_merge_error(client, h_synxs, count);
	synx_util_merge_error(client, h_synxs, count);
	if (num_objs <= count)
	if (num_objs && num_objs <= count)
		kfree(fences);
		kfree(fences);
	synx_put_client(client);
	synx_put_client(client);
	return rc;
	return rc;
@@ -647,6 +677,7 @@ int synx_release(struct synx_session session_id, s32 h_synx)
{
{
	int rc = 0;
	int rc = 0;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;


	pr_debug("[sess: %u] Enter release from pid %d\n",
	pr_debug("[sess: %u] Enter release from pid %d\n",
@@ -656,7 +687,9 @@ int synx_release(struct synx_session session_id, s32 h_synx)
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	synx_obj = synx_util_obtain_object(synx_data);
	/* no need to check for fence here */
	if (!synx_obj) {
	if (!synx_obj) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
@@ -665,10 +698,10 @@ int synx_release(struct synx_session session_id, s32 h_synx)
	}
	}


	/* release the reference obtained at synx creation */
	/* release the reference obtained at synx creation */
	synx_util_release_object(client, h_synx);
	synx_util_release_handle(synx_data);
	synx_util_release_object(client, h_synx);


fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit release with status %d\n",
	pr_debug("[sess: %u] exit release with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -682,8 +715,8 @@ int synx_wait(struct synx_session session_id, s32 h_synx, u64 timeout_ms)
	int rc = 0;
	int rc = 0;
	unsigned long timeleft;
	unsigned long timeleft;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;
	struct dma_fence *fence;


	pr_debug("[sess: %u] Enter wait from pid %d\n",
	pr_debug("[sess: %u] Enter wait from pid %d\n",
		session_id.client_id, current->pid);
		session_id.client_id, current->pid);
@@ -692,32 +725,33 @@ int synx_wait(struct synx_session session_id, s32 h_synx, u64 timeout_ms)
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	if (!synx_obj) {
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
		goto fail;
		goto fail;
	}
	}


	fence = synx_util_get_fence(synx_obj);
	timeleft = dma_fence_wait_timeout(synx_obj->fence, (bool) 0,
	timeleft = dma_fence_wait_timeout(fence, (bool) 0,
					msecs_to_jiffies(timeout_ms));
					msecs_to_jiffies(timeout_ms));
	if (timeleft <= 0) {
	if (timeleft <= 0) {
		pr_err("[sess: %u] wait timeout for handle %d\n",
		pr_err("[sess: %u] wait timeout for handle %d\n",
			client->id, h_synx);
			client->id, h_synx);
		rc = -ETIMEDOUT;
		rc = -ETIMEDOUT;
		goto clear;
		goto fail;
	}
	}


	mutex_lock(&synx_obj->obj_lock);
	rc = synx_util_get_object_status(synx_obj);
	rc = synx_util_get_object_status(synx_obj);
	mutex_unlock(&synx_obj->obj_lock);
	/* remap the state if signaled successfully */
	/* remap the state if signaled successfully */
	if (rc == SYNX_STATE_SIGNALED_SUCCESS)
	if (rc == SYNX_STATE_SIGNALED_SUCCESS)
		rc = 0;
		rc = 0;


clear:
	synx_util_release_object(client, h_synx);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit wait with status %d\n",
	pr_debug("[sess: %u] exit wait with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -731,7 +765,9 @@ int synx_bind(struct synx_session session_id,
{
{
	int rc = 0;
	int rc = 0;
	u32 i;
	u32 i;
	u32 bound_idx;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;
	struct synx_external_data *data = NULL;
	struct synx_external_data *data = NULL;
	struct bind_operations *bind_ops = NULL;
	struct bind_operations *bind_ops = NULL;
@@ -743,7 +779,8 @@ int synx_bind(struct synx_session session_id,
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj) {
	if (!synx_obj) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
@@ -751,29 +788,30 @@ int synx_bind(struct synx_session session_id,
		goto fail;
		goto fail;
	}
	}


	if (synx_util_is_merged_object(synx_obj)) {
		pr_err("[sess: %u] cannot bind to merged handle %d\n",
			client->id, h_synx);
		rc = -EINVAL;
		goto clear;
	}

	bind_ops = synx_util_get_bind_ops(external_sync.type);
	bind_ops = synx_util_get_bind_ops(external_sync.type);
	if (!bind_ops) {
	if (!bind_ops) {
		pr_err("[sess: %u] invalid bind ops for %u\n",
		pr_err("[sess: %u] invalid bind ops for %u\n",
			client->id, external_sync.type);
			client->id, external_sync.type);
		rc = -EINVAL;
		rc = -EINVAL;
		goto clear;
		goto fail;
	}

	mutex_lock(&synx_obj->obj_lock);
	if (synx_util_is_merged_object(synx_obj) ||
		synx_util_is_external_object(synx_obj)) {
		pr_err("[sess: %u] cannot bind to merged handle %d\n",
			client->id, h_synx);
		rc = -EINVAL;
		goto release;
	}
	}


	data = kzalloc(sizeof(*data), GFP_KERNEL);
	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
	if (!data) {
		rc = -ENOMEM;
		rc = -ENOMEM;
		goto clear;
		goto release;
	}
	}


	spin_lock_bh(&synx_obj->lock);
	if (synx_util_get_object_status(synx_obj) != SYNX_STATE_ACTIVE) {
	if (synx_util_get_object_status_locked(synx_obj) != SYNX_STATE_ACTIVE) {
		pr_err("[sess: %u] bind prohibited to inactive handle %d\n",
		pr_err("[sess: %u] bind prohibited to inactive handle %d\n",
			client->id, h_synx);
			client->id, h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -801,32 +839,38 @@ int synx_bind(struct synx_session session_id,
	/* data passed to external callback */
	/* data passed to external callback */
	data->h_synx = h_synx;
	data->h_synx = h_synx;
	data->session_id = session_id;
	data->session_id = session_id;

	bound_idx = synx_obj->num_bound_synxs;
	memcpy(&synx_obj->bound_synxs[bound_idx],
		   &external_sync, sizeof(struct synx_external_desc));
	synx_obj->bound_synxs[bound_idx].external_data = data;
	synx_obj->num_bound_synxs++;
	mutex_unlock(&synx_obj->obj_lock);

	rc = bind_ops->register_callback(synx_external_callback,
	rc = bind_ops->register_callback(synx_external_callback,
			data, external_sync.id[0]);
			data, external_sync.id[0]);
	if (rc) {
	if (rc) {
		pr_err("[sess: %u] callback registration failed for %d\n",
		pr_err("[sess: %u] callback registration failed for %d\n",
			client->id, external_sync.id[0]);
			client->id, external_sync.id[0]);
		mutex_lock(&synx_obj->obj_lock);
		memset(&synx_obj->bound_synxs[bound_idx], 0,
			sizeof(struct synx_external_desc));
		synx_obj->num_bound_synxs--;
		goto free;
		goto free;
	}
	}


	memcpy(&synx_obj->bound_synxs[synx_obj->num_bound_synxs],
	synx_util_release_handle(synx_data);
		   &external_sync, sizeof(struct synx_external_desc));
	synx_obj->bound_synxs[synx_obj->num_bound_synxs].external_data = data;
	synx_obj->num_bound_synxs++;
	spin_unlock_bh(&synx_obj->lock);

	synx_util_release_object(client, h_synx);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit bind\n",
	pr_debug("[sess: %u] bind of handle %d with id %d successful\n",
		session_id.client_id);
		session_id.client_id, h_synx, external_sync.id[0]);
	return 0;
	return 0;


free:
free:
	spin_unlock_bh(&synx_obj->lock);
	kfree(data);
	kfree(data);
clear:
release:
	synx_util_release_object(client, h_synx);
	mutex_unlock(&synx_obj->obj_lock);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	return rc;
	return rc;
}
}
@@ -836,6 +880,7 @@ int synx_get_status(struct synx_session session_id, s32 h_synx)
{
{
	int rc = 0;
	int rc = 0;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;


	pr_debug("[sess: %u] Enter get_status from pid %d\n",
	pr_debug("[sess: %u] Enter get_status from pid %d\n",
@@ -845,20 +890,23 @@ int synx_get_status(struct synx_session session_id, s32 h_synx)
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	if (!synx_obj) {
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
		rc = SYNX_STATE_INVALID;
		rc = SYNX_STATE_INVALID;
		goto fail;
		goto fail;
	}
	}


	mutex_lock(&synx_obj->obj_lock);
	rc = synx_util_get_object_status(synx_obj);
	rc = synx_util_get_object_status(synx_obj);
	mutex_unlock(&synx_obj->obj_lock);
	pr_debug("[sess: %u] synx object handle %d status %d\n",
	pr_debug("[sess: %u] synx object handle %d status %d\n",
		client->id, h_synx, rc);
		client->id, h_synx, rc);


	synx_util_release_object(client, h_synx);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit get_status with status %d\n",
	pr_debug("[sess: %u] exit get_status with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -869,7 +917,9 @@ EXPORT_SYMBOL(synx_get_status);
int synx_addrefcount(struct synx_session session_id, s32 h_synx, s32 count)
int synx_addrefcount(struct synx_session session_id, s32 h_synx, s32 count)
{
{
	int rc = 0;
	int rc = 0;
	u32 idx;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_handle_coredata *synx_data;
	struct synx_coredata *synx_obj;
	struct synx_coredata *synx_obj;


	pr_debug("[sess: %u] Enter addrefcount from pid %d\n",
	pr_debug("[sess: %u] Enter addrefcount from pid %d\n",
@@ -879,8 +929,9 @@ int synx_addrefcount(struct synx_session session_id, s32 h_synx, s32 count)
	if (!client)
	if (!client)
		return -EINVAL;
		return -EINVAL;


	synx_obj = synx_util_acquire_object(client, h_synx);
	synx_data = synx_util_acquire_handle(client, h_synx);
	if (!synx_obj) {
	synx_obj = synx_util_obtain_object(synx_data);
	if (!synx_obj || !synx_obj->fence) {
		pr_err("%s: [sess: %u] invalid handle access %d\n",
		pr_err("%s: [sess: %u] invalid handle access %d\n",
			__func__, client->id, h_synx);
			__func__, client->id, h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -891,15 +942,18 @@ int synx_addrefcount(struct synx_session session_id, s32 h_synx, s32 count)
		pr_err("[sess: %u] invalid addrefcount for handle %d\n",
		pr_err("[sess: %u] invalid addrefcount for handle %d\n",
			client->id, h_synx);
			client->id, h_synx);
		rc = -EINVAL;
		rc = -EINVAL;
		goto clear;
		goto fail;
	}
	}


	idx = synx_util_handle_index(h_synx);
	mutex_lock(&client->synx_table_lock[idx]);
	/* acquire additional references to handle */
	while (count--)
	while (count--)
		synx_util_acquire_object(client, h_synx);
		kref_get(&synx_data->internal_refcount);
	mutex_unlock(&client->synx_table_lock[idx]);


clear:
	synx_util_release_object(client, h_synx);
fail:
fail:
	synx_util_release_handle(synx_data);
	synx_put_client(client);
	synx_put_client(client);
	pr_debug("[sess: %u] exit addrefcount with status %d\n",
	pr_debug("[sess: %u] exit addrefcount with status %d\n",
		session_id.client_id, rc);
		session_id.client_id, rc);
@@ -948,9 +1002,10 @@ int synx_import(struct synx_session session_id,
	}
	}


	*params->new_h_synx = h_synx;
	*params->new_h_synx = h_synx;
	pr_debug("[sess: %u] new import obj with handle %ld, fence %pK\n",
		client->id, h_synx, synx_obj);
	synx_put_client(client);
	synx_put_client(client);


	pr_debug("[sess: %u] exit import\n", session_id.client_id);
	return 0;
	return 0;


clean_up:
clean_up:
@@ -1006,6 +1061,7 @@ static int synx_handle_create(struct synx_private_ioctl_arg *k_ioctl,


	params.h_synx = &synx_create_info.synx_obj;
	params.h_synx = &synx_create_info.synx_obj;
	params.name = synx_create_info.name;
	params.name = synx_create_info.name;
	params.type = 0;
	result = synx_create(session_id, &params);
	result = synx_create(session_id, &params);


	if (!result)
	if (!result)
@@ -1085,6 +1141,7 @@ static int synx_handle_export(struct synx_private_ioctl_arg *k_ioctl,


	params.h_synx = id_info.synx_obj;
	params.h_synx = id_info.synx_obj;
	params.secure_key = &id_info.secure_key;
	params.secure_key = &id_info.secure_key;
	params.fence = NULL;
	if (synx_export(session_id, &params))
	if (synx_export(session_id, &params))
		return -EINVAL;
		return -EINVAL;


@@ -1463,22 +1520,19 @@ int synx_initialize(struct synx_session *session_id,
	struct synx_initialization_params *params)
	struct synx_initialization_params *params)
{
{
	u32 i;
	u32 i;
	u16 unique_id;
	long idx;
	long idx;
	bool bit;
	struct synx_client *client;
	struct synx_client *client;
	struct synx_client_metadata *client_metadata;
	struct synx_client_metadata *client_metadata;


	if (!session_id || !params)
	if (!session_id || !params)
		return -EINVAL;
		return -EINVAL;


	do {
	idx = synx_util_get_free_handle(synx_dev->bitmap, SYNX_MAX_CLIENTS);
		idx = find_first_zero_bit(synx_dev->bitmap, SYNX_MAX_CLIENTS);
	if (idx >= SYNX_MAX_CLIENTS) {
	if (idx >= SYNX_MAX_CLIENTS) {
		pr_err("maximum client limit reached\n");
		pr_err("maximum client limit reached\n");
		return -ENOMEM;
		return -ENOMEM;
	}
	}
		bit = test_and_set_bit(idx, synx_dev->bitmap);
	} while (bit);


	client = vzalloc(sizeof(*client));
	client = vzalloc(sizeof(*client));
	if (!client) {
	if (!client) {
@@ -1488,8 +1542,16 @@ int synx_initialize(struct synx_session *session_id,


	if (params->name)
	if (params->name)
		strlcpy(client->name, params->name, sizeof(client->name));
		strlcpy(client->name, params->name, sizeof(client->name));

	do {
		get_random_bytes(&unique_id, sizeof(unique_id));
	} while (!unique_id);

	client->device = synx_dev;
	client->device = synx_dev;
	client->id = idx;
	client->id = unique_id;
	client->id <<= SYNX_CLIENT_HANDLE_SHIFT;
	client->id |= (idx & SYNX_CLIENT_HANDLE_MASK);

	mutex_init(&client->event_q_lock);
	mutex_init(&client->event_q_lock);
	for (i = 0; i < SYNX_MAX_OBJS; i++)
	for (i = 0; i < SYNX_MAX_OBJS; i++)
		mutex_init(&client->synx_table_lock[i]);
		mutex_init(&client->synx_table_lock[i]);
@@ -1503,12 +1565,11 @@ int synx_initialize(struct synx_session *session_id,
	client_metadata = &synx_dev->client_table[idx];
	client_metadata = &synx_dev->client_table[idx];
	client_metadata->client = client;
	client_metadata->client = client;
	kref_init(&client_metadata->refcount);
	kref_init(&client_metadata->refcount);
	session_id->client_id = client->id;
	mutex_unlock(&synx_dev->dev_table_lock);
	mutex_unlock(&synx_dev->dev_table_lock);


	session_id->client_id = idx;
	pr_info("[sess: %u] session created %s\n",
	pr_info("[sess: %u] session created %s\n",
		idx, params->name);
		session_id->client_id, params->name);

	return 0;
	return 0;
}
}
EXPORT_SYMBOL(synx_initialize);
EXPORT_SYMBOL(synx_initialize);
+31 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,18 @@
#include <linux/list.h>
#include <linux/list.h>
#include <uapi/media/synx.h>
#include <uapi/media/synx.h>


/**
 * SYNX_FLAG_GLOBAL_FENCE   : Creates a global synx object
 *                            If flag not set, creates local synx object
 * SYNX_FLAG_EXTERNAL_FENCE : Creates an synx object with external fence
 */
enum synx_flags {
	SYNX_FLAG_GLOBAL_FENCE = 0x1,
	SYNX_FLAG_MERGED_FENCE = 0x2,
	SYNX_FLAG_EXTERNAL_FENCE = 0x4,
	SYNX_FLAG_MAX = 0x8,
};

typedef void (*synx_callback)(s32 sync_obj, int status, void *data);
typedef void (*synx_callback)(s32 sync_obj, int status, void *data);


/**
/**
@@ -67,6 +79,7 @@ struct synx_initialization_params {
 * struct synx_create_params - Synx creation parameters
 * struct synx_create_params - Synx creation parameters
 *
 *
 * @h_synx : Pointer to synx object handle (filled by function)
 * @h_synx : Pointer to synx object handle (filled by function)
 * @type   : Synx flags for customization
 * @name   : Optional parameter associating a name with the synx
 * @name   : Optional parameter associating a name with the synx
 *           object for debug purposes
 *           object for debug purposes
 *           Only first 64 bytes are accepted,
 *           Only first 64 bytes are accepted,
@@ -74,6 +87,7 @@ struct synx_initialization_params {
 */
 */
struct synx_create_params {
struct synx_create_params {
	s32 *h_synx;
	s32 *h_synx;
	u32 type;
	const char *name;
	const char *name;
};
};


@@ -83,10 +97,12 @@ struct synx_create_params {
 * @h_synx     : Synx object handle to export
 * @h_synx     : Synx object handle to export
 * @secure_key : Pointer to Key generated for authentication
 * @secure_key : Pointer to Key generated for authentication
 *               (filled by the function)
 *               (filled by the function)
 * @fence      : Pointer to dma fence for external synx object
 */
 */
struct synx_export_params {
struct synx_export_params {
	s32 h_synx;
	s32 h_synx;
	u32 *secure_key;
	u32 *secure_key;
	struct dma_fence *fence;
};
};


/**
/**
@@ -328,6 +344,21 @@ int synx_import(struct synx_session session_id,
int synx_export(struct synx_session session_id,
int synx_export(struct synx_session session_id,
	struct synx_export_params *params);
	struct synx_export_params *params);


/**
 * @brief: Get the dma fence backing the synx object
 *
 * Function obtains an additional reference to the fence.
 * This reference needs to be released by the client
 * through dma_fence_put explicitly.
 *
 * @param session_id : Client session id
 * @param h_synx     : Synx object handle
 *
 * @return Dma fence pointer for a valid synx handle. NULL otherwise.
 */
struct dma_fence *synx_get_fence(struct synx_session session_id,
	s32 h_synx);

/**
/**
 * @brief: Release the synx object
 * @brief: Release the synx object


+20 −10

File changed.

Preview size limit exceeded, changes collapsed.

+23 −16

File changed.

Preview size limit exceeded, changes collapsed.

+353 −282

File changed.

Preview size limit exceeded, changes collapsed.

Loading