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: Sumukh Hallymysore Ravindra <shallymy@codeaurora.org>
This commit is contained in:
Sumukh Hallymysore Ravindra 2019-11-27 13:57:41 -08:00
commit 01f202069f
7 changed files with 790 additions and 527 deletions

View file

@ -7,6 +7,7 @@
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
@ -17,42 +18,10 @@
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)
{
int rc;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
struct synx_client *client = NULL;
struct synx_external_data *bind_data = data;
@ -70,28 +39,28 @@ void synx_external_callback(s32 sync_obj, int status, void *data)
goto free;
}
synx_obj = synx_util_acquire_object(client, bind_data->h_synx);
if (!synx_obj) {
synx_data = synx_util_acquire_handle(client, bind_data->h_synx);
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",
client->id, sync_obj, bind_data->h_synx);
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",
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:
synx_util_release_object(client, bind_data->h_synx);
mutex_lock(&synx_obj->obj_lock);
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:
synx_util_release_handle(synx_data);
synx_put_client(client);
free:
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)
{
struct synx_coredata *synx_obj =
container_of(fence, struct synx_coredata, fence);
synx_util_object_destroy(synx_obj);
/* release the memory allocated during create */
kfree(fence->lock);
kfree(fence);
pr_debug("released synx backing fence %pK\n", fence);
}
EXPORT_SYMBOL(synx_fence_release);
@ -125,6 +94,44 @@ static struct dma_fence_ops synx_fence_ops = {
.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,
struct synx_create_params *params)
{
@ -166,23 +173,14 @@ int synx_create(struct synx_session session_id,
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;
pr_debug("[sess: %u] new synx obj with handle %ld\n",
client->id, h_synx);
pr_debug("[sess: %u] new synx obj with handle %ld, fence %pK\n",
client->id, h_synx, synx_obj);
synx_put_client(client);
return 0;
clear_bit:
clear_bit(h_synx, client->bitmap);
clean_up:
dma_fence_put(synx_obj->fence);
kfree(synx_obj);
fail:
synx_put_client(client);
@ -195,12 +193,11 @@ int synx_signal_core(struct synx_coredata *synx_obj,
bool cb_signal,
s32 ext_sync_id)
{
int rc, ret;
int rc = 0, ret;
u32 i = 0;
u32 idx = 0;
s32 sync_id;
u32 type;
struct dma_fence *fence;
struct synx_external_data *data = NULL;
struct synx_bind_desc bind_descs[SYNX_MAX_NUM_BINDINGS];
struct bind_operations *bind_ops = NULL;
@ -208,37 +205,6 @@ int synx_signal_core(struct synx_coredata *synx_obj,
if (!synx_obj)
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);
/*
@ -268,7 +234,6 @@ int synx_signal_core(struct synx_coredata *synx_obj,
}
synx_obj->num_bound_synxs = 0;
}
spin_unlock_bh(&synx_obj->lock);
for (i = 0; i < idx; i++) {
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 */
if (bind_ops->enable_signaling) {
ret = bind_ops->enable_signaling(sync_id);
if (ret < 0) {
if (ret < 0)
pr_err("enabling fail on %d, type: %u, err: %d\n",
sync_id, type, ret);
continue;
}
}
ret = bind_ops->signal(sync_id, status);
if (ret < 0)
@ -315,10 +278,75 @@ int synx_signal_core(struct synx_coredata *synx_obj,
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 rc = 0;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
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)
return -EINVAL;
synx_obj = synx_util_acquire_object(client, h_synx);
if (!synx_obj) {
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);
rc = -EINVAL;
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)
pr_err("[sess: %u] signaling failed for handle %d with err: %d\n",
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:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit signal with status %d\n",
session_id.client_id, rc);
@ -382,6 +415,7 @@ int synx_register_callback(struct synx_session session_id,
u32 idx;
u32 status;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
struct synx_cb_data *synx_cb;
struct synx_kernel_payload payload;
@ -393,7 +427,8 @@ int synx_register_callback(struct synx_session session_id,
if (!client)
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) {
pr_err("%s: [sess: %u] invalid handle access %d\n",
__func__, client->id, h_synx);
@ -401,15 +436,18 @@ int synx_register_callback(struct synx_session session_id,
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");
goto clear;
rc = -EINVAL;
goto release;
}
synx_cb = kzalloc(sizeof(*synx_cb), GFP_ATOMIC);
if (!synx_cb) {
rc = -ENOMEM;
goto clear;
goto release;
}
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",
client->id);
kfree(synx_cb);
goto clear;
goto release;
}
spin_lock_bh(&synx_obj->lock);
status = synx_util_get_object_status_locked(synx_obj);
status = synx_util_get_object_status(synx_obj);
synx_cb->session_id = session_id;
synx_cb->idx = idx;
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,
&synx_cb->cb_dispatch);
}
spin_unlock_bh(&synx_obj->lock);
clear:
synx_util_release_object(client, h_synx);
release:
mutex_unlock(&synx_obj->obj_lock);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit register cb with status %d\n",
session_id.client_id, rc);
@ -463,6 +500,7 @@ int synx_deregister_callback(struct synx_session session_id,
u32 status;
bool match_found = false;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
struct synx_kernel_payload payload;
struct synx_cb_data *synx_cb, *synx_cb_temp;
@ -475,7 +513,8 @@ int synx_deregister_callback(struct synx_session session_id,
if (!client)
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) {
pr_err("%s: [sess: %u] invalid handle access %d\n",
__func__, client->id, h_synx);
@ -483,9 +522,11 @@ int synx_deregister_callback(struct synx_session session_id,
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");
goto clear;
goto release;
}
payload.h_synx = h_synx;
@ -493,14 +534,12 @@ int synx_deregister_callback(struct synx_session session_id,
payload.data = userdata;
payload.cancel_cb_func = cancel_cb_func;
spin_lock_bh(&synx_obj->lock);
status = synx_util_get_object_status_locked(synx_obj);
status = synx_util_get_object_status(synx_obj);
if (status != SYNX_STATE_ACTIVE) {
pr_err("handle %d already signaled. cannot deregister cb/s\n",
h_synx);
rc = -EINVAL;
spin_unlock_bh(&synx_obj->lock);
goto clear;
goto release;
}
status = SYNX_CALLBACK_RESULT_CANCELED;
@ -546,16 +585,15 @@ int synx_deregister_callback(struct synx_session session_id,
break;
}
}
spin_unlock_bh(&synx_obj->lock);
if (!match_found)
rc = -EINVAL;
clear:
synx_util_release_object(client, h_synx);
release:
mutex_unlock(&synx_obj->obj_lock);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
return rc;
pr_debug("[sess: %u] exit deregister cb with status %d\n",
session_id.client_id, rc);
@ -614,29 +652,21 @@ int synx_merge(struct synx_session session_id,
if (rc) {
pr_err("[sess: %u] unable to init merge handle %ld\n",
client->id, h_synx);
dma_fence_put(synx_obj->fence);
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;
synx_put_client(client);
pr_debug("[sess: %u] exit merge with status %d\n",
session_id.client_id, rc);
return 0;
clear_bit:
clear_bit(h_synx, client->bitmap);
clean_up:
kfree(synx_obj);
fail:
synx_util_merge_error(client, h_synxs, count);
if (num_objs <= count)
if (num_objs && num_objs <= count)
kfree(fences);
synx_put_client(client);
return rc;
@ -647,6 +677,7 @@ int synx_release(struct synx_session session_id, s32 h_synx)
{
int rc = 0;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
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)
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) {
pr_err("%s: [sess: %u] invalid handle access %d\n",
__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 */
synx_util_release_object(client, h_synx);
synx_util_release_object(client, h_synx);
synx_util_release_handle(synx_data);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit release with status %d\n",
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;
unsigned long timeleft;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
struct dma_fence *fence;
pr_debug("[sess: %u] Enter wait from pid %d\n",
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)
return -EINVAL;
synx_obj = synx_util_acquire_object(client, h_synx);
if (!synx_obj) {
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);
rc = -EINVAL;
goto fail;
}
fence = synx_util_get_fence(synx_obj);
timeleft = dma_fence_wait_timeout(fence, (bool) 0,
timeleft = dma_fence_wait_timeout(synx_obj->fence, (bool) 0,
msecs_to_jiffies(timeout_ms));
if (timeleft <= 0) {
pr_err("[sess: %u] wait timeout for handle %d\n",
client->id, h_synx);
rc = -ETIMEDOUT;
goto clear;
goto fail;
}
mutex_lock(&synx_obj->obj_lock);
rc = synx_util_get_object_status(synx_obj);
mutex_unlock(&synx_obj->obj_lock);
/* remap the state if signaled successfully */
if (rc == SYNX_STATE_SIGNALED_SUCCESS)
rc = 0;
clear:
synx_util_release_object(client, h_synx);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit wait with status %d\n",
session_id.client_id, rc);
@ -731,7 +765,9 @@ int synx_bind(struct synx_session session_id,
{
int rc = 0;
u32 i;
u32 bound_idx;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
struct synx_external_data *data = NULL;
struct bind_operations *bind_ops = NULL;
@ -743,7 +779,8 @@ int synx_bind(struct synx_session session_id,
if (!client)
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) {
pr_err("%s: [sess: %u] invalid handle access %d\n",
__func__, client->id, h_synx);
@ -751,29 +788,30 @@ int synx_bind(struct synx_session session_id,
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);
if (!bind_ops) {
pr_err("[sess: %u] invalid bind ops for %u\n",
client->id, external_sync.type);
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);
if (!data) {
rc = -ENOMEM;
goto clear;
goto release;
}
spin_lock_bh(&synx_obj->lock);
if (synx_util_get_object_status_locked(synx_obj) != SYNX_STATE_ACTIVE) {
if (synx_util_get_object_status(synx_obj) != SYNX_STATE_ACTIVE) {
pr_err("[sess: %u] bind prohibited to inactive handle %d\n",
client->id, h_synx);
rc = -EINVAL;
@ -801,32 +839,38 @@ int synx_bind(struct synx_session session_id,
/* data passed to external callback */
data->h_synx = h_synx;
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,
data, external_sync.id[0]);
if (rc) {
pr_err("[sess: %u] callback registration failed for %d\n",
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;
}
memcpy(&synx_obj->bound_synxs[synx_obj->num_bound_synxs],
&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_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit bind\n",
session_id.client_id);
pr_debug("[sess: %u] bind of handle %d with id %d successful\n",
session_id.client_id, h_synx, external_sync.id[0]);
return 0;
free:
spin_unlock_bh(&synx_obj->lock);
kfree(data);
clear:
synx_util_release_object(client, h_synx);
release:
mutex_unlock(&synx_obj->obj_lock);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
return rc;
}
@ -836,6 +880,7 @@ int synx_get_status(struct synx_session session_id, s32 h_synx)
{
int rc = 0;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
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)
return -EINVAL;
synx_obj = synx_util_acquire_object(client, h_synx);
if (!synx_obj) {
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);
rc = SYNX_STATE_INVALID;
goto fail;
}
mutex_lock(&synx_obj->obj_lock);
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",
client->id, h_synx, rc);
synx_util_release_object(client, h_synx);
fail:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit get_status with status %d\n",
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 rc = 0;
u32 idx;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *synx_obj;
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)
return -EINVAL;
synx_obj = synx_util_acquire_object(client, h_synx);
if (!synx_obj) {
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);
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",
client->id, h_synx);
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--)
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:
synx_util_release_handle(synx_data);
synx_put_client(client);
pr_debug("[sess: %u] exit addrefcount with status %d\n",
session_id.client_id, rc);
@ -948,9 +1002,10 @@ int synx_import(struct synx_session session_id,
}
*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);
pr_debug("[sess: %u] exit import\n", session_id.client_id);
return 0;
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.name = synx_create_info.name;
params.type = 0;
result = synx_create(session_id, &params);
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.secure_key = &id_info.secure_key;
params.fence = NULL;
if (synx_export(session_id, &params))
return -EINVAL;
@ -1463,22 +1520,19 @@ int synx_initialize(struct synx_session *session_id,
struct synx_initialization_params *params)
{
u32 i;
u16 unique_id;
long idx;
bool bit;
struct synx_client *client;
struct synx_client_metadata *client_metadata;
if (!session_id || !params)
return -EINVAL;
do {
idx = find_first_zero_bit(synx_dev->bitmap, SYNX_MAX_CLIENTS);
if (idx >= SYNX_MAX_CLIENTS) {
pr_err("maximum client limit reached\n");
return -ENOMEM;
}
bit = test_and_set_bit(idx, synx_dev->bitmap);
} while (bit);
idx = synx_util_get_free_handle(synx_dev->bitmap, SYNX_MAX_CLIENTS);
if (idx >= SYNX_MAX_CLIENTS) {
pr_err("maximum client limit reached\n");
return -ENOMEM;
}
client = vzalloc(sizeof(*client));
if (!client) {
@ -1488,8 +1542,16 @@ int synx_initialize(struct synx_session *session_id,
if (params->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->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);
for (i = 0; i < SYNX_MAX_OBJS; 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->client = client;
kref_init(&client_metadata->refcount);
session_id->client_id = client->id;
mutex_unlock(&synx_dev->dev_table_lock);
session_id->client_id = idx;
pr_info("[sess: %u] session created %s\n",
idx, params->name);
session_id->client_id, params->name);
return 0;
}
EXPORT_SYMBOL(synx_initialize);

View file

@ -9,6 +9,18 @@
#include <linux/list.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);
/**
@ -67,6 +79,7 @@ struct synx_initialization_params {
* struct synx_create_params - Synx creation parameters
*
* @h_synx : Pointer to synx object handle (filled by function)
* @type : Synx flags for customization
* @name : Optional parameter associating a name with the synx
* object for debug purposes
* Only first 64 bytes are accepted,
@ -74,6 +87,7 @@ struct synx_initialization_params {
*/
struct synx_create_params {
s32 *h_synx;
u32 type;
const char *name;
};
@ -83,10 +97,12 @@ struct synx_create_params {
* @h_synx : Synx object handle to export
* @secure_key : Pointer to Key generated for authentication
* (filled by the function)
* @fence : Pointer to dma fence for external synx object
*/
struct synx_export_params {
s32 h_synx;
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,
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

View file

@ -43,6 +43,7 @@ static ssize_t synx_table_read(struct file *file,
struct synx_device *dev = file->private_data;
struct error_node *err_node, *err_node_tmp;
struct synx_client *client;
struct synx_handle_coredata *synx_data;
struct synx_coredata *row;
char *dbuf, *cur, *end;
@ -68,22 +69,31 @@ static ssize_t synx_table_read(struct file *file,
cur += scnprintf(cur, end - cur, "\n");
for (j = 0; j < SYNX_MAX_CLIENTS; j++) {
struct synx_session session;
struct synx_client_metadata *client_meta;
session.client_id = j;
client = synx_get_client(session);
if (!client)
mutex_lock(&synx_dev->dev_table_lock);
client_meta = &synx_dev->client_table[j];
if (!client_meta->client) {
mutex_unlock(&synx_dev->dev_table_lock);
continue;
}
kref_get(&client_meta->refcount);
client = client_meta->client;
mutex_unlock(&synx_dev->dev_table_lock);
cur += scnprintf(cur, end - cur,
"=============== session %08u ===============\n",
client->id);
cur += scnprintf(cur, end - cur,
"session name ::: %s\n",
client->name);
for (i = 0; i < SYNX_MAX_OBJS; i++) {
row = synx_util_acquire_object(client, i);
if (!row)
synx_data = synx_util_acquire_handle(client, i);
row = synx_util_obtain_object(synx_data);
if (!row || !row->fence)
continue;
spin_lock_bh(&row->lock);
mutex_lock(&row->obj_lock);
if (columns & NAME_COLUMN)
cur += scnprintf(cur, end - cur,
"|%10s|", row->name);
@ -95,7 +105,7 @@ static ssize_t synx_table_read(struct file *file,
"|%11d|", row->num_bound_synxs);
if (columns & STATE_COLUMN) {
status =
synx_util_get_object_status_locked(row);
synx_util_get_object_status(row);
cur += scnprintf(cur, end - cur,
"|%10d|", status);
}
@ -107,9 +117,9 @@ static ssize_t synx_table_read(struct file *file,
cur,
end);
}
spin_unlock_bh(&row->lock);
mutex_unlock(&row->obj_lock);
cur += scnprintf(cur, end - cur, "\n");
synx_util_release_object(client, i);
synx_util_release_handle(synx_data);
}
cur += scnprintf(cur, end - cur,
"\n================================================\n\n");

View file

@ -19,23 +19,17 @@
#define SYNX_DEVICE_NAME "synx_device"
#define SYNX_CLIENT_HANDLE_SHIFT 8
#define SYNX_SECURE_KEY_SHIFT 16
#define SYNX_OBJ_HANDLE_SHIFT 10
#define MAX_TIMESTAMP_SIZE 32
#define SYNX_OBJ_NAME_LEN 64
#define SYNX_MAX_CLIENTS (1UL<<SYNX_CLIENT_HANDLE_SHIFT)
#define SYNX_MAX_OBJS 1024
#define SYNX_MAX_OBJS (1UL<<SYNX_OBJ_HANDLE_SHIFT)
#define SYNX_MAX_REF_COUNTS 2048
#define SYNX_PAYLOAD_WORDS 4
#define SYNX_SECURE_KEY_SIZE (1UL<<SYNX_SECURE_KEY_SHIFT)
#define SYNX_SECURE_KEY_MASK (SYNX_SECURE_KEY_SIZE-1)
#define SYNX_CLIENT_HANDLE_MASK (SYNX_MAX_CLIENTS-1)
#define SYNX_OBJ_TYPE_LOCAL 0x1
#define SYNX_OBJ_TYPE_MERGED 0x2
#define SYNX_STATE_FORCED_RELEASE 5
#define SYNX_OBJ_HANDLE_MASK (SYNX_MAX_OBJS-1)
/**
* struct synx_external_data - data passed over to external sync objects
@ -152,9 +146,10 @@ struct synx_registered_ops {
* of all metadata associated with each individual synx object
*
* @name : Optional string representation of the synx object
* @fence : Dma fence backing the synx object
* @merged_fence : Pointer to dma fence backing merged synx object
* @lock : Spinlock
* @fence : Pointer to dma fence backing synx object
* @fence_cb : Callback struct registered with external fence
* @obj_lock : Mutex lock for coredata access
* @refcount : References by the various client
* @type : Synx object type
* @num_bound_synxs : Number of external bound synx objects
* @bound_synxs : Array of bound external sync objects
@ -162,9 +157,10 @@ struct synx_registered_ops {
*/
struct synx_coredata {
char name[SYNX_OBJ_NAME_LEN];
struct dma_fence fence;
struct dma_fence *merged_fence;
spinlock_t lock;
struct dma_fence *fence;
struct dma_fence_cb fence_cb;
struct mutex obj_lock;
struct kref refcount;
u32 type;
u32 num_bound_synxs;
struct synx_bind_desc bound_synxs[SYNX_MAX_NUM_BINDINGS];
@ -191,7 +187,7 @@ struct synx_handle_coredata {
struct synx_coredata *synx_obj;
struct kref internal_refcount;
struct kref import_refcount;
u32 id;
u32 handle;
u16 key;
};
@ -285,4 +281,15 @@ int synx_signal_core(struct synx_coredata *synx_obj,
bool cb_signal,
s32 ext_sync_id);
/**
* @brief: Internal function to signal the synx fence
*
* @param synx_obj : Pointer to the synx object to signal
* @param status : Signaling status
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
int synx_signal_fence(struct synx_coredata *synx_obj,
u32 status);
#endif /* __SYNX_PRIVATE_H__ */

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,9 @@
extern struct synx_device *synx_dev;
extern void synx_fence_callback(struct dma_fence *fence,
struct dma_fence_cb *cb);
/**
* @brief: Function to check if the external obj type is valid
*
@ -17,7 +20,13 @@ extern struct synx_device *synx_dev;
*
* @return True if valid. False otherwise
*/
bool synx_util_is_valid_bind_type(u32 type);
static inline bool synx_util_is_valid_bind_type(u32 type)
{
if (type < SYNX_MAX_BIND_TYPES)
return true;
return false;
}
/**
* @brief: Function to get the synx object type
@ -26,7 +35,35 @@ bool synx_util_is_valid_bind_type(u32 type);
*
* @return Synx object type. Zero if invalid
*/
u32 synx_util_get_object_type(struct synx_coredata *synx_obj);
static inline u32 synx_util_get_object_type(
struct synx_coredata *synx_obj)
{
return synx_obj->type;
}
/**
* @brief: Function to get the client metadata index from session id
*
* @param client_id : Client session id
*
* @return Client metadata index.
*/
static inline u32 synx_util_client_index(u32 client_id)
{
return (client_id & SYNX_CLIENT_HANDLE_MASK);
}
/**
* @brief: Function to get the client synx table index from handle
*
* @param h_synx : Synx object handle
*
* @return Synx object index.
*/
static inline u32 synx_util_handle_index(s32 h_synx)
{
return (h_synx & SYNX_OBJ_HANDLE_MASK);
}
/**
* @brief: Function to check if the synx object is a composite (merged)
@ -35,17 +72,49 @@ u32 synx_util_get_object_type(struct synx_coredata *synx_obj);
*
* @return True if merged object. False otherwise
*/
bool synx_util_is_merged_object(struct synx_coredata *synx_obj);
static inline bool synx_util_is_merged_object(
struct synx_coredata *synx_obj)
{
if (synx_obj->type & SYNX_FLAG_MERGED_FENCE)
return true;
return false;
}
/**
* @brief: Function to get the dma fence backing the synx object
* @brief: Function to check if object is of global type
*
* @param synx_obj : Pointer to synx object
*
* @return Dma fence. NULL if synx_obj is invalid
* @return True if global object. False otherwise.
*/
struct dma_fence *synx_util_get_fence(
struct synx_coredata *synx_obj);
static inline bool synx_util_is_global_object(
struct synx_coredata *synx_obj)
{
if (synx_obj->type & SYNX_FLAG_GLOBAL_FENCE)
return true;
return false;
}
/**
* @brief: Function to check if object is of external type
*
* The dma fence backing the external synx object is created and
* managed outside the synx framework.
*
* @param synx_obj : Pointer to synx object
*
* @return True if external object. False otherwise.
*/
static inline bool synx_util_is_external_object(
struct synx_coredata *synx_obj)
{
if (synx_obj->type & SYNX_FLAG_EXTERNAL_FENCE)
return true;
return false;
}
/**
* @brief: Function to acquire reference to synx object
@ -108,6 +177,16 @@ int synx_util_init_group_coredata(struct synx_coredata *synx_obj,
*/
void synx_util_object_destroy(struct synx_coredata *synx_obj);
/**
* @brief: Function to find a free index from the bitmap
*
* @param bitmap : Pointer to bitmap
* @param size : Max index
*
* @return Free index if available.
*/
long synx_util_get_free_handle(unsigned long *bitmap, unsigned int size);
/**
* @brief: Function to allocate synx_client_cb entry from cb table
*
@ -245,42 +324,45 @@ u32 synx_util_get_object_status(struct synx_coredata *synx_obj);
u32 synx_util_get_object_status_locked(struct synx_coredata *synx_obj);
/**
* @brief: Function to obtain the synx object metadata for the client
* @brief: Function to acquire the synx object handle
*
* This function increments the reference count of synx handle data.
* The reference should be released by calling synx_util_release_handle
*
* @param client : Pointer to client session
* @param h_synx : Synx object handle
*
* @return Pointer to synx object metadata for the client.
* NULL if invalid synx handle.
* @return Pointer to synx handle data on success. NULL otherwise.
*/
struct synx_handle_coredata *synx_util_obtain_handle(
struct synx_handle_coredata *synx_util_acquire_handle(
struct synx_client *client, s32 h_synx);
/**
* @brief: Function to acquire the synx object
* @brief: Function to obtain the synx object
*
* This function increments the reference count of the dma fence.
* @param synx_data : Pointer to synx object handle data
*
* @param client : Pointer to client session
* @param h_synx : Synx object handle
*
* @return Pointer to synx object. NULL if invalid synx handle.
* @return Pointer to synx object on success. NULL otherwise.
*/
struct synx_coredata *synx_util_acquire_object(
struct synx_client *client, s32 h_synx);
static inline struct synx_coredata *synx_util_obtain_object(
struct synx_handle_coredata *synx_data) {
if (!synx_data)
return NULL;
return synx_data->synx_obj;
}
/**
* @brief: Function to release the synx object
* @brief: Function to release the synx object handle
*
* This function decrements the reference count of the dma fence and
* implicitly calls up the synx object cleanup if count reaches 0.
* Synx object should not be derefrenced in the function after
* This function decrements the reference count of the synx handle and
* implicitly calls up the synx object release if count reaches 0.
* Synx handle data should not be derefrenced in the function after
* calling this.
*
* @param client : Pointer to client session
* @param h_synx : Synx object handle
* @param synx_data : Pointer to synx object handle data
*/
void synx_util_release_object(struct synx_client *client, s32 h_synx);
void synx_util_release_handle(struct synx_handle_coredata *synx_data);
/**
* @brief: Function called implicitly when import refcount reaches zero

View file

@ -17,6 +17,7 @@
#define SYNX_STATE_SIGNALED_SUCCESS 2
#define SYNX_STATE_SIGNALED_ERROR 3
#define SYNX_STATE_SIGNALED_CANCEL 4
#define SYNX_STATE_SIGNALED_EXTERNAL 5
#define SYNX_MAX_WAITING_SYNX 16