Эх сурвалжийг харах

msm: synx: Adding merge API support for synx V2

This change enables clients to signal synx merged handles
from same and other cores. This change also ensures
that underlying child dma fences are signaled when composite
synx handle is signaled from other core.

Change-Id: Ib81bc2291c85b93fe11eddf5d0ce450bbe486c83
Signed-off-by: Urvesh Rathod <[email protected]>
Urvesh Rathod 2 жил өмнө
parent
commit
d120b83d98
3 өөрчлөгдсөн 167 нэмэгдсэн , 39 устгасан
  1. 123 39
      msm/synx/synx.c
  2. 42 0
      msm/synx/synx_util.c
  3. 2 0
      msm/synx/synx_util.h

+ 123 - 39
msm/synx/synx.c

@@ -497,6 +497,42 @@ int synx_native_signal_fence(struct synx_coredata *synx_obj,
 	return rc;
 }
 
+int synx_native_signal_merged_fence(struct synx_coredata *synx_obj, u32 status)
+{
+	int rc = SYNX_SUCCESS;
+	unsigned long flags;
+	int i = 0, num_fences = 0;
+	struct synx_coredata **synx_child_obj = NULL;
+
+	rc = synx_get_child_coredata(synx_obj, &synx_child_obj, &num_fences);
+	if (rc != SYNX_SUCCESS)
+		return rc;
+	for(i = 0; i < num_fences; i++)
+	{
+		if (IS_ERR_OR_NULL(synx_child_obj[i]) || IS_ERR_OR_NULL(synx_child_obj[i]->fence)) {
+			dprintk(SYNX_ERR, "Invalid child coredata %d\n", i);
+			rc = -SYNX_NOENT;
+			goto fail;
+		}
+		mutex_lock(&synx_child_obj[i]->obj_lock);
+		spin_lock_irqsave(synx_child_obj[i]->fence->lock, flags);
+		if (synx_util_get_object_status_locked(synx_child_obj[i]) != SYNX_STATE_ACTIVE ||
+			!synx_util_is_global_object(synx_child_obj[i]))
+		{
+			spin_unlock_irqrestore(synx_child_obj[i]->fence->lock, flags);
+			mutex_unlock(&synx_child_obj[i]->obj_lock);
+			continue;
+		}
+		spin_unlock_irqrestore(synx_child_obj[i]->fence->lock, flags);
+
+		rc = synx_native_signal_fence(synx_child_obj[i], status);
+		mutex_unlock(&synx_child_obj[i]->obj_lock);
+	}
+fail:
+	kfree(synx_child_obj);
+	return rc;
+}
+
 void synx_signal_handler(struct work_struct *cb_dispatch)
 {
 	int rc = SYNX_SUCCESS;
@@ -552,13 +588,25 @@ void synx_signal_handler(struct work_struct *cb_dispatch)
 
 	mutex_lock(&synx_obj->obj_lock);
 
-	if (signal_cb->flag & SYNX_SIGNAL_FROM_IPC)
-		rc = synx_native_signal_fence(synx_obj, status);
-
-	if (rc == SYNX_SUCCESS)
-		rc = synx_native_signal_core(synx_obj, status,
-				(signal_cb->flag & SYNX_SIGNAL_FROM_CALLBACK) ?
-				true : false, signal_cb->ext_sync_id);
+	if (signal_cb->flag & SYNX_SIGNAL_FROM_IPC) {
+		if (synx_util_is_merged_object(synx_obj)) {
+			rc = synx_native_signal_merged_fence(synx_obj, status);
+			if (rc != SYNX_SUCCESS) {
+				mutex_unlock(&synx_obj->obj_lock);
+				dprintk(SYNX_ERR,
+					"failed to signal merged fence for %u failed=%d\n",
+					h_synx, rc);
+				goto fail;
+			}
+		}
+		else {
+			rc = synx_native_signal_fence(synx_obj, status);
+			if (rc == SYNX_SUCCESS)
+				rc = synx_native_signal_core(synx_obj, status,
+						(signal_cb->flag & SYNX_SIGNAL_FROM_CALLBACK) ?
+						true : false, signal_cb->ext_sync_id);
+		}
+	}
 
 	mutex_unlock(&synx_obj->obj_lock);
 
@@ -766,14 +814,6 @@ int synx_async_wait(struct synx_session *session,
 	}
 
 	mutex_lock(&synx_obj->obj_lock);
-	if (synx_util_is_merged_object(synx_obj)) {
-		dprintk(SYNX_ERR,
-			"[sess :%llu] cannot async wait on merged handle %u\n",
-			client->id, params->h_synx);
-		rc = -SYNX_INVALID;
-		goto release;
-	}
-
 	synx_cb = kzalloc(sizeof(*synx_cb), GFP_ATOMIC);
 	if (IS_ERR_OR_NULL(synx_cb)) {
 		rc = -SYNX_NOMEM;
@@ -795,10 +835,17 @@ int synx_async_wait(struct synx_session *session,
 	}
 
 	if (synx_util_is_global_handle(params->h_synx) ||
-			synx_util_is_global_object(synx_obj))
+			synx_util_is_global_object(synx_obj)) {
 		status = synx_global_test_status_set_wait(
 					synx_util_global_idx(params->h_synx),
 					SYNX_CORE_APSS);
+		if (status != SYNX_STATE_ACTIVE) {
+			if (synx_util_is_merged_object(synx_obj))
+				synx_native_signal_merged_fence(synx_obj, status);
+			else
+				synx_native_signal_fence(synx_obj, status);
+		}
+	}
 	else
 		status = synx_util_get_object_status(synx_obj);
 
@@ -862,10 +909,9 @@ int synx_cancel_async_wait(
 	}
 
 	mutex_lock(&synx_obj->obj_lock);
-	if (synx_util_is_merged_object(synx_obj) ||
-		synx_util_is_external_object(synx_obj)) {
+	if (synx_util_is_external_object(synx_obj)) {
 		dprintk(SYNX_ERR,
-			"cannot cancel wait on composite handle\n");
+			"cannot cancel wait on external fence\n");
 		goto release;
 	}
 
@@ -944,14 +990,14 @@ EXPORT_SYMBOL(synx_cancel_async_wait);
 int synx_merge(struct synx_session *session,
 	struct synx_merge_params *params)
 {
-	int rc, i, j = 0;
-	u32 h_child;
-	u32 count = 0;
-	u32 *h_child_list;
+	int rc, i, num_signaled = 0;
+	u32 count = 0, h_child, status = SYNX_STATE_ACTIVE;
+	u32 *h_child_list = NULL, *h_child_idx_list = NULL;
 	struct synx_client *client;
 	struct dma_fence **fences = NULL;
-	struct synx_coredata *synx_obj;
 	struct synx_map_entry *map_entry;
+	struct synx_coredata *synx_obj, *synx_obj_child;
+	struct synx_handle_coredata *synx_data_child;
 
 	if (IS_ERR_OR_NULL(session) || IS_ERR_OR_NULL(params))
 		return -SYNX_INVALID;
@@ -1008,36 +1054,67 @@ int synx_merge(struct synx_session *session,
 		goto clear;
 	}
 
-	if (params->flags & SYNX_MERGE_GLOBAL_FENCE) {
-		h_child_list = kzalloc(count*4, GFP_KERNEL);
-		if (IS_ERR_OR_NULL(synx_obj)) {
-			rc = -SYNX_NOMEM;
-			goto clear;
-		}
+	h_child_list = kzalloc(count*4, GFP_KERNEL);
+	if (IS_ERR_OR_NULL(h_child_list)) {
+		rc = -SYNX_NOMEM;
+		goto clear;
+	}
 
-		for (i = 0; i < count; i++) {
-			h_child = synx_util_get_fence_entry((u64)fences[i], 1);
-			if (!synx_util_is_global_handle(h_child))
-				continue;
+	h_child_idx_list = kzalloc(count*4, GFP_KERNEL);
+	if (IS_ERR_OR_NULL(h_child_idx_list)) {
+		rc = -SYNX_NOMEM;
+		goto clear;
+	}
 
-			h_child_list[j++] = synx_util_global_idx(h_child);
-		}
+	for (i = 0; i < count; i++) {
+		h_child = synx_util_get_fence_entry((u64)fences[i], 1);
+		if (!synx_util_is_global_handle(h_child))
+			continue;
 
-		rc = synx_global_merge(h_child_list, j,
+		h_child_list[num_signaled] = h_child;
+		h_child_idx_list[num_signaled++] = synx_util_global_idx(h_child);
+	}
+
+	if (params->flags & SYNX_MERGE_GLOBAL_FENCE) {
+		rc = synx_global_merge(h_child_idx_list, num_signaled,
 			synx_util_global_idx(*params->h_merged_obj));
 		if (rc != SYNX_SUCCESS) {
 			dprintk(SYNX_ERR, "global merge failed\n");
+			kfree(h_child_list);
+			kfree(h_child_idx_list);
 			goto clear;
 		}
 	}
+	else {
+		for(i = 0; i < num_signaled; i++) {
+			status = synx_global_test_status_set_wait(synx_util_global_idx(h_child_list[i]), SYNX_CORE_APSS);
+
+			if (status != SYNX_STATE_ACTIVE) {
+				synx_data_child = synx_util_acquire_handle(client, h_child_list[i]);
+				synx_obj_child = synx_util_obtain_object(synx_data_child);
+
+				if (IS_ERR_OR_NULL(synx_obj_child)) {
+					dprintk(SYNX_ERR,
+						"[sess :%llu] invalid child handle %u\n",
+						client->id, h_child_list[i]);
+					continue;
+				}
+
+				rc = synx_native_signal_fence(synx_obj_child, status);
+				if (rc != SYNX_SUCCESS)
+					dprintk(SYNX_ERR, "h_synx %u failed with status %d\n", h_child_list[i], rc);
+			}
+		}
+	}
 
 	dprintk(SYNX_MEM,
 		"[sess :%llu] merge allocated %u, core %pK, fence %pK\n",
 		client->id, *params->h_merged_obj, synx_obj,
 		synx_obj->fence);
+	kfree(h_child_list);
+	kfree(h_child_idx_list);
 	synx_put_client(client);
 	return SYNX_SUCCESS;
-
 clear:
 	synx_util_release_map_entry(map_entry);
 clean_up:
@@ -1118,8 +1195,15 @@ int synx_wait(struct synx_session *session,
 	if (synx_util_is_global_handle(h_synx)) {
 		rc = synx_global_test_status_set_wait(
 			synx_util_global_idx(h_synx), SYNX_CORE_APSS);
-		if (rc != SYNX_STATE_ACTIVE)
+		if (rc != SYNX_STATE_ACTIVE) {
+			mutex_lock(&synx_obj->obj_lock);
+			if (synx_util_is_merged_object(synx_obj))
+				synx_native_signal_merged_fence(synx_obj, rc);
+			else
+				synx_native_signal_fence(synx_obj, rc);
+			mutex_unlock(&synx_obj->obj_lock);
 			goto fail;
+		}
 	}
 
 	timeleft = dma_fence_wait_timeout(synx_obj->fence, (bool) 0,

+ 42 - 0
msm/synx/synx_util.c

@@ -1205,6 +1205,48 @@ free:
 	kfree(synx_cb);
 }
 
+int synx_get_child_coredata(struct synx_coredata *synx_obj, struct synx_coredata ***child_synx_obj, int *num_fences)
+{
+	int rc = SYNX_SUCCESS;
+	int i = 0, handle_count = 0;
+	u32 h_child = 0;
+	struct dma_fence_array *array = NULL;
+	struct synx_coredata **synx_datas = NULL;
+	struct synx_map_entry *fence_entry = NULL;
+
+	if (IS_ERR_OR_NULL(synx_obj) || IS_ERR_OR_NULL(num_fences))
+		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;
+		synx_datas = kcalloc(array->num_fences, sizeof(*synx_datas), GFP_KERNEL);
+		if (IS_ERR_OR_NULL(synx_datas))
+			return -SYNX_NOMEM;
+
+		for (i = 0; i < array->num_fences; i++) {
+			h_child = synx_util_get_fence_entry((u64)array->fences[i], 1);
+			fence_entry = synx_util_get_map_entry(h_child);
+			if (IS_ERR_OR_NULL(fence_entry) || IS_ERR_OR_NULL(fence_entry->synx_obj))
+			{
+				dprintk(SYNX_ERR, "Invalid handle access %u", h_child);
+				rc = -SYNX_NOENT;
+				goto fail;
+			}
+
+			synx_datas[handle_count++] = fence_entry->synx_obj;
+			synx_util_release_map_entry(fence_entry);
+		}
+	}
+
+	*child_synx_obj = synx_datas;
+	*num_fences = handle_count;
+	return rc;
+fail:
+	kfree(synx_datas);
+	return rc;
+}
+
 u32 synx_util_get_fence_entry(u64 key, u32 global)
 {
 	u32 h_synx = 0;

+ 2 - 0
msm/synx/synx_util.h

@@ -178,4 +178,6 @@ void synx_util_map_import_params_to_create(
 struct bind_operations *synx_util_get_bind_ops(u32 type);
 u32 synx_util_map_client_id_to_core(enum synx_client_id id);
 
+int synx_get_child_coredata(struct synx_coredata *synx_obj, struct synx_coredata ***child_synx_obj, int *num_fences);
+
 #endif /* __SYNX_UTIL_H__ */