msm: synx: Releases global handle index if handle is not signaled

This change provides fix for below issues :
1. If local handle is imported as global, synx takes extra reference
   on global handles which were not released because on signal
   callback data had local handle instead of global causing handle
   leak.
2. If all the child handles of merge fence are local and
   merged fence is global, upon merge its signaled incorrectly
   as num_child == 0 even if no one signaled merged fence.
3. During merge synx takes one reference each child dma fences.
   When merged fence is released, dma fence reference of child handles
   were not released causing handle/dma fence leak. This change
   signals underlying child fences if the merged handle is ACTIVE
   during release and release reference on dma fence.
4. If local handle is imported as global, map_count was not getting
   incremented because of which object was destroyed more than once.
   This change increases the map_count variable when local handle is
   imported as global or vice-versa.
5. In synx_signal API, synx_signal_offload_job followed by signaling
   dma fence. synx_signal_offload_job internally calls
   synx_signal_handler which signals dma fence and because of which
   sometimes synx_signal was returning failure. This fix ensures that
   synx_signal_handler does not overtake synx signal API.

Change-Id: Ia8d2eb969514347cac30f8ae33ce2028119dfd47
Signed-off-by: Urvesh Rathod <quic_urathod@quicinc.com>
This commit is contained in:
Urvesh Rathod
2023-04-24 14:20:26 +05:30
parent a1825820d5
commit 6b566f4639
5 changed files with 87 additions and 16 deletions

View File

@@ -12,6 +12,7 @@
#include "synx_util.h"
extern void synx_external_callback(s32 sync_obj, int status, void *data);
static u32 __fence_state(struct dma_fence *fence, bool locked);
int synx_util_init_coredata(struct synx_coredata *synx_obj,
struct synx_create_params *params,
@@ -247,6 +248,38 @@ void synx_util_put_object(struct synx_coredata *synx_obj)
kref_put(&synx_obj->refcount, synx_util_destroy_coredata);
}
int synx_util_cleanup_merged_fence(struct synx_coredata *synx_obj, int status)
{
struct dma_fence_array *array = NULL;
u32 i;
int rc = 0;
if (IS_ERR_OR_NULL(synx_obj) || IS_ERR_OR_NULL(synx_obj->fence))
return -SYNX_INVALID;
if (dma_fence_is_array(synx_obj->fence)) {
array = to_dma_fence_array(synx_obj->fence);
if (IS_ERR_OR_NULL(array))
return -SYNX_INVALID;
for (i = 0; i < array->num_fences; i++) {
if (kref_read(&array->fences[i]->refcount) == 1 &&
__fence_state(array->fences[i], false) == SYNX_STATE_ACTIVE) {
dma_fence_set_error(array->fences[i],
-SYNX_STATE_SIGNALED_CANCEL);
rc = dma_fence_signal(array->fences[i]);
if (rc)
dprintk(SYNX_ERR,
"signaling child fence %pK failed=%d\n",
array->fences[i], rc);
}
dma_fence_put(array->fences[i]);
}
}
return rc;
}
void synx_util_object_destroy(struct synx_coredata *synx_obj)
{
int rc;
@@ -311,7 +344,10 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj)
*/
if (!IS_ERR_OR_NULL(synx_obj->fence)) {
spin_lock_irqsave(synx_obj->fence->lock, flags);
if (kref_read(&synx_obj->fence->refcount) == 1 &&
if (synx_util_is_merged_object(synx_obj) &&
synx_util_get_object_status_locked(synx_obj) == SYNX_STATE_ACTIVE)
rc = synx_util_cleanup_merged_fence(synx_obj, -SYNX_STATE_SIGNALED_CANCEL);
else if (kref_read(&synx_obj->fence->refcount) == 1 &&
(synx_util_get_object_status_locked(synx_obj) ==
SYNX_STATE_ACTIVE)) {
// set fence error to cancel
@@ -319,12 +355,12 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj)
-SYNX_STATE_SIGNALED_CANCEL);
rc = dma_fence_signal_locked(synx_obj->fence);
if (rc)
dprintk(SYNX_ERR,
"signaling fence %pK failed=%d\n",
synx_obj->fence, rc);
}
spin_unlock_irqrestore(synx_obj->fence->lock, flags);
if (rc)
dprintk(SYNX_ERR,
"signaling fence %pK failed=%d\n",
synx_obj->fence, rc);
}
dma_fence_put(synx_obj->fence);
@@ -873,6 +909,7 @@ static void synx_util_cleanup_fence(
unsigned long flags;
u32 g_status;
u32 f_status;
u32 h_synx = 0;
mutex_lock(&synx_obj->obj_lock);
synx_obj->map_count--;
@@ -903,6 +940,8 @@ static void synx_util_cleanup_fence(
if (synx_util_get_object_status_locked(synx_obj) ==
SYNX_STATE_ACTIVE) {
signal_cb->synx_obj = NULL;
synx_global_fetch_handle_details(synx_obj->global_idx, &h_synx);
signal_cb->handle = h_synx;
synx_obj->signal_cb = NULL;
/*
* release reference held by signal cb and