Quellcode durchsuchen

msm: synx: Fixing cleanup of merge synx and dma fences

1. dma fence framework takes care of putting the child dma fence reference
when the array fence is being destroyed. Synx shouldn't put the child
dma fence reference taken for dma fence array.
2. When destroying the child dma fence we have to signal the fence if
synx has taken the last reference. If there are more than 1 reference on
dma fence, then check if the other references are from merge fences
instead of any client taking direct reference on the dma fence.

Change-Id: I8b0879b8c1d2401cdd08f85ae330b74af99a2dad
Signed-off-by: Amir Suhail <[email protected]>
(cherry picked from commit a2795fd6f59324a7fbcff455b82b8cdc54d27e1a)
Amir Suhail vor 1 Jahr
Ursprung
Commit
51b2182fea
2 geänderte Dateien mit 76 neuen und 24 gelöschten Zeilen
  1. 35 14
      msm/synx/synx.c
  2. 41 10
      msm/synx/synx_util.c

+ 35 - 14
msm/synx/synx.c

@@ -1176,6 +1176,12 @@ int synx_merge(struct synx_session *session,
 	if (IS_ERR_OR_NULL(client))
 		return -SYNX_INVALID;
 
+	synx_obj = kzalloc(sizeof(*synx_obj), GFP_KERNEL);
+	if (IS_ERR_OR_NULL(synx_obj)) {
+		rc = -SYNX_NOMEM;
+		goto fail;
+	}
+
 	rc = synx_util_validate_merge(client, params->h_synxs,
 			params->num_objs, &fences, &count);
 	if (rc < 0) {
@@ -1183,12 +1189,8 @@ int synx_merge(struct synx_session *session,
 			"[sess :%llu] merge validation failed\n",
 			client->id);
 		rc = -SYNX_INVALID;
-		goto fail;
-	}
 
-	synx_obj = kzalloc(sizeof(*synx_obj), GFP_KERNEL);
-	if (IS_ERR_OR_NULL(synx_obj)) {
-		rc = -SYNX_NOMEM;
+		kfree(synx_obj);
 		goto fail;
 	}
 
@@ -1205,12 +1207,20 @@ int synx_merge(struct synx_session *session,
 					*params->h_merged_obj, 0);
 	if (IS_ERR_OR_NULL(map_entry)) {
 		rc = PTR_ERR(map_entry);
-		goto clean_up;
+
+		/*
+		 * dma fence put will take care of removing the references taken
+		 * on child fences
+		 */
+		dma_fence_put(synx_obj->fence);
+		kfree(synx_obj);
+		goto fail;
 	}
 
 	rc = synx_util_add_callback(synx_obj, *params->h_merged_obj);
+
 	if (rc != SYNX_SUCCESS)
-		goto clear;
+		goto clean_up;
 
 	rc = synx_util_init_handle(client, synx_obj,
 			params->h_merged_obj, map_entry);
@@ -1218,8 +1228,7 @@ int synx_merge(struct synx_session *session,
 		dprintk(SYNX_ERR,
 			"[sess :%llu] unable to init merge handle %u\n",
 			client->id, *params->h_merged_obj);
-		dma_fence_put(synx_obj->fence);
-		goto clear;
+		goto clean_up;
 	}
 
 	h_child_list = kzalloc(count*4, GFP_KERNEL);
@@ -1289,13 +1298,25 @@ int synx_merge(struct synx_session *session,
 	synx_put_client(client);
 	return SYNX_SUCCESS;
 clear:
-	synx_util_release_map_entry(map_entry);
+	synx_native_release_core(client, (*params->h_merged_obj));
+	synx_put_client(client);
+	return rc;
+
 clean_up:
-	kfree(synx_obj);
+	/*
+	 * if map_entry is not created the cleanup of child fences have to be
+	 * handled manually
+	 */
+	if (IS_ERR_OR_NULL(map_entry)) {
+		kfree(synx_obj);
+		synx_util_merge_error(client, params->h_synxs, count);
+		if (params->num_objs && params->num_objs <= count)
+			kfree(fences);
+
+	} else {
+		synx_util_release_map_entry(map_entry);
+	}
 fail:
-	synx_util_merge_error(client, params->h_synxs, count);
-	if (params->num_objs && params->num_objs <= count)
-		kfree(fences);
 	synx_put_client(client);
 	return rc;
 }

+ 41 - 10
msm/synx/synx_util.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -182,6 +182,36 @@ int synx_util_add_callback(struct synx_coredata *synx_obj,
 	return SYNX_SUCCESS;
 }
 
+static int synx_util_count_dma_array_fences(struct dma_fence *fence)
+{
+	struct dma_fence_cb *cur, *tmp;
+	int32_t num_dma_array = 0;
+	struct dma_fence_array_cb *cb_array = NULL;
+	struct dma_fence_array *array = NULL;
+
+	if (IS_ERR_OR_NULL(fence)) {
+		dprintk(SYNX_ERR, "invalid fence passed\n");
+		return num_dma_array;
+	}
+
+	list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) {
+		// count for parent fences
+		cb_array = container_of(cur, struct dma_fence_array_cb, cb);
+		if (IS_ERR_OR_NULL(cb_array)) {
+			dprintk(SYNX_VERB, "cb_array not found in fence %pK\n", fence);
+			continue;
+		}
+		array = cb_array->array;
+		if (!IS_ERR_OR_NULL(array) && dma_fence_is_array(&(array->base)))
+			num_dma_array++;
+	}
+
+	dprintk(SYNX_VERB, "number of fence_array found %d for child fence %pK\n",
+		num_dma_array, fence);
+
+	return num_dma_array;
+}
+
 int synx_util_init_group_coredata(struct synx_coredata *synx_obj,
 	struct dma_fence **fences,
 	struct synx_merge_params *params,
@@ -276,7 +306,6 @@ int synx_util_cleanup_merged_fence(struct synx_coredata *synx_obj, int status)
 						"signaling child fence %pK failed=%d\n",
 						array->fences[i], rc);
 			}
-			dma_fence_put(array->fences[i]);
 		}
 	}
 	return rc;
@@ -285,6 +314,7 @@ int synx_util_cleanup_merged_fence(struct synx_coredata *synx_obj, int status)
 void synx_util_object_destroy(struct synx_coredata *synx_obj)
 {
 	int rc;
+	int num_dma_array = 0;
 	u32 i;
 	s32 sync_id;
 	u32 type;
@@ -358,14 +388,15 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj)
 		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
-			dma_fence_set_error(synx_obj->fence,
-				-SYNX_STATE_SIGNALED_CANCEL);
-
-			rc = dma_fence_signal_locked(synx_obj->fence);
+		else if (synx_util_get_object_status_locked(synx_obj) == SYNX_STATE_ACTIVE) {
+			num_dma_array = synx_util_count_dma_array_fences(synx_obj->fence);
+			if (kref_read(&synx_obj->fence->refcount) == 1 + num_dma_array) {
+				// set fence error to cancel
+				dma_fence_set_error(synx_obj->fence,
+					-SYNX_STATE_SIGNALED_CANCEL);
+
+				rc = dma_fence_signal_locked(synx_obj->fence);
+			}
 		}
 		spin_unlock_irqrestore(synx_obj->fence->lock, flags);
 		if (rc)