瀏覽代碼

msm: synx: Custom signal support

This change ensures clients can send anything greater
than 64 as custom status from APSS to other cores.

Change-Id: Ib7f507e666fe0b60c5fc09f90652a09e15634376
Signed-off-by: Urvesh Rathod <[email protected]>
Urvesh Rathod 2 年之前
父節點
當前提交
e7e3b4aaac
共有 5 個文件被更改,包括 163 次插入74 次删除
  1. 112 23
      msm/synx/synx.c
  2. 37 43
      msm/synx/synx_global.c
  3. 3 0
      msm/synx/synx_global.h
  4. 2 1
      msm/synx/synx_private.h
  5. 9 7
      msm/synx/synx_util.c

+ 112 - 23
msm/synx/synx.c

@@ -483,6 +483,11 @@ int synx_native_signal_fence(struct synx_coredata *synx_obj,
 		return -SYNX_ALREADY;
 	}
 
+	synx_obj->status = status;
+
+	if (status >= SYNX_DMA_FENCE_STATE_MAX)
+		status = SYNX_DMA_FENCE_STATE_MAX - 1;
+
 	/* set fence error to model {signal w/ error} */
 	if (status != SYNX_STATE_SIGNALED_SUCCESS)
 		dma_fence_set_error(synx_obj->fence, -status);
@@ -514,6 +519,7 @@ int synx_native_signal_merged_fence(struct synx_coredata *synx_obj, u32 status)
 			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 ||
@@ -525,6 +531,7 @@ int synx_native_signal_merged_fence(struct synx_coredata *synx_obj, u32 status)
 		}
 		spin_unlock_irqrestore(synx_child_obj[i]->fence->lock, flags);
 
+		status = synx_global_get_status(synx_child_obj[i]->global_idx);
 		rc = synx_native_signal_fence(synx_child_obj[i], status);
 		mutex_unlock(&synx_child_obj[i]->obj_lock);
 	}
@@ -533,6 +540,80 @@ fail:
 	return rc;
 }
 
+u32 synx_get_child_status(struct synx_coredata *synx_obj)
+{
+	u32 h_child = 0, i = 0;
+	u32 status = SYNX_DMA_FENCE_STATE_MAX - 1, child_status = SYNX_STATE_ACTIVE;
+	struct dma_fence_array *array = NULL;
+	struct synx_map_entry *fence_entry = NULL;
+	struct synx_coredata *synx_child_obj = NULL;
+
+	if (!dma_fence_is_array(synx_obj->fence))
+		return status;
+
+	array = to_dma_fence_array(synx_obj->fence);
+	if (IS_ERR_OR_NULL(array))
+		goto bail;
+
+	for (i = 0; i < array->num_fences; i++) {
+		h_child = synx_util_get_fence_entry((u64)array->fences[i], 1);
+		if (h_child == 0)
+			h_child = synx_util_get_fence_entry((u64)array->fences[i], 0);
+
+		if (h_child == 0)
+			continue;
+
+		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);
+			goto bail;
+		}
+		synx_child_obj = fence_entry->synx_obj;
+
+		mutex_lock(&synx_child_obj->obj_lock);
+		if (synx_util_is_global_object(synx_child_obj))
+			child_status = synx_global_get_status(synx_child_obj->global_idx);
+		else
+			child_status = synx_child_obj->status;
+		mutex_unlock(&synx_child_obj->obj_lock);
+		synx_util_release_map_entry(fence_entry);
+
+		dprintk(SYNX_VERB, "Child handle %u status %d", h_child, child_status);
+		if (child_status != SYNX_STATE_ACTIVE &&
+			(status == SYNX_DMA_FENCE_STATE_MAX - 1 ||
+			(child_status > SYNX_STATE_SIGNALED_SUCCESS &&
+			child_status <= SYNX_STATE_SIGNALED_MAX)))
+			status = child_status;
+	}
+bail:
+	return status;
+}
+
+u32 synx_custom_get_status(struct synx_coredata *synx_obj, u32 status)
+{
+	u32 custom_status = status;
+	u32 parent_global_status =
+		synx_util_is_global_object(synx_obj) ?
+		synx_global_get_status(synx_obj->global_idx) : SYNX_STATE_ACTIVE;
+
+	if (IS_ERR_OR_NULL(synx_obj))
+		goto bail;
+
+	mutex_lock(&synx_obj->obj_lock);
+	if (synx_util_is_merged_object(synx_obj)) {
+		if (parent_global_status == SYNX_STATE_ACTIVE)
+			synx_obj->status = synx_get_child_status(synx_obj);
+		else
+			synx_obj->status = parent_global_status;
+	}
+
+	custom_status = synx_obj->status;
+	mutex_unlock(&synx_obj->obj_lock);
+
+bail:
+	return custom_status;
+}
+
 void synx_signal_handler(struct work_struct *cb_dispatch)
 {
 	int rc = SYNX_SUCCESS;
@@ -544,6 +625,13 @@ void synx_signal_handler(struct work_struct *cb_dispatch)
 	u32 h_synx = signal_cb->handle;
 	u32 status = signal_cb->status;
 
+	if (signal_cb->flag & SYNX_SIGNAL_FROM_FENCE) {
+		status = synx_custom_get_status(synx_obj, status);
+		dprintk(SYNX_VERB,
+			"handle %d will be updated with status %d\n",
+			h_synx, status);
+	}
+
 	if ((signal_cb->flag & SYNX_SIGNAL_FROM_FENCE) &&
 			(synx_util_is_global_handle(h_synx) ||
 			synx_util_is_global_object(synx_obj))) {
@@ -590,8 +678,8 @@ void synx_signal_handler(struct work_struct *cb_dispatch)
 	}
 
 	mutex_lock(&synx_obj->obj_lock);
-
-	if (signal_cb->flag & SYNX_SIGNAL_FROM_IPC) {
+	if (signal_cb->flag & SYNX_SIGNAL_FROM_IPC &&
+		synx_util_get_object_status(synx_obj) == SYNX_STATE_ACTIVE) {
 		if (synx_util_is_merged_object(synx_obj))
 			rc = synx_native_signal_merged_fence(synx_obj, status);
 		else
@@ -648,8 +736,12 @@ void synx_fence_callback(struct dma_fence *fence,
 	 */
 	if (status == 1)
 		status = SYNX_STATE_SIGNALED_SUCCESS;
-	else if (status < 0)
+	else if (status == -SYNX_STATE_SIGNALED_CANCEL)
+		status = SYNX_STATE_SIGNALED_CANCEL;
+	else if (status < 0 && status >= -SYNX_STATE_SIGNALED_MAX)
 		status = SYNX_STATE_SIGNALED_EXTERNAL;
+	else
+		status = (u32)-status;
 
 	signal_cb->status = status;
 
@@ -707,7 +799,10 @@ int synx_signal(struct synx_session *session, u32 h_synx, u32 status)
 	if (IS_ERR_OR_NULL(client))
 		return -SYNX_INVALID;
 
-	if (status <= SYNX_STATE_ACTIVE) {
+	if (status <= SYNX_STATE_ACTIVE ||
+			!(status == SYNX_STATE_SIGNALED_SUCCESS ||
+			status == SYNX_STATE_SIGNALED_CANCEL ||
+			status > SYNX_STATE_SIGNALED_MAX)) {
 		dprintk(SYNX_ERR,
 			"[sess :%llu] signaling with wrong status: %u\n",
 			client->id, status);
@@ -727,7 +822,6 @@ int synx_signal(struct synx_session *session, u32 h_synx, u32 status)
 	}
 
 	mutex_lock(&synx_obj->obj_lock);
-
 	if (synx_util_is_global_handle(h_synx) ||
 			synx_util_is_global_object(synx_obj))
 		rc = synx_global_update_status(
@@ -997,7 +1091,7 @@ EXPORT_SYMBOL(synx_cancel_async_wait);
 int synx_merge(struct synx_session *session,
 	struct synx_merge_params *params)
 {
-	int rc, i, num_signaled = 0;
+	int rc = SYNX_SUCCESS, 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;
@@ -1073,6 +1167,7 @@ int synx_merge(struct synx_session *session,
 
 	h_child_idx_list = kzalloc(count*4, GFP_KERNEL);
 	if (IS_ERR_OR_NULL(h_child_idx_list)) {
+		kfree(h_child_list);
 		rc = -SYNX_NOMEM;
 		goto clear;
 	}
@@ -1110,10 +1205,14 @@ int synx_merge(struct synx_session *session,
 						client->id, h_child_list[i]);
 					continue;
 				}
-
-				rc = synx_native_signal_fence(synx_obj_child, status);
+				mutex_lock(&synx_obj_child->obj_lock);
+				if (synx_obj->status == SYNX_STATE_ACTIVE)
+					rc = synx_native_signal_fence(synx_obj_child, status);
+				mutex_unlock(&synx_obj_child->obj_lock);
 				if (rc != SYNX_SUCCESS)
 					dprintk(SYNX_ERR, "h_synx %u failed with status %d\n", h_child_list[i], rc);
+
+				synx_util_release_handle(synx_data_child);
 			}
 		}
 	}
@@ -1361,7 +1460,7 @@ EXPORT_SYMBOL(synx_bind);
 int synx_get_status(struct synx_session *session,
 	u32 h_synx)
 {
-	int rc = 0;
+	int rc = 0, status = 0;
 	struct synx_client *client;
 	struct synx_handle_coredata *synx_data;
 	struct synx_coredata *synx_obj;
@@ -1381,23 +1480,13 @@ int synx_get_status(struct synx_session *session,
 		goto fail;
 	}
 
-	if (synx_util_is_global_handle(h_synx)) {
-		rc = synx_global_get_status(
-				synx_util_global_idx(h_synx));
-		if (rc != SYNX_STATE_ACTIVE) {
-			dprintk(SYNX_VERB,
-				"[sess :%llu] handle %u in status %d\n",
-				client->id, h_synx, rc);
-			goto fail;
-		}
-	}
-
 	mutex_lock(&synx_obj->obj_lock);
-	rc = synx_util_get_object_status(synx_obj);
+	status = synx_util_get_object_status(synx_obj);
+	rc = synx_obj->status;
 	mutex_unlock(&synx_obj->obj_lock);
 	dprintk(SYNX_VERB,
-		"[sess :%llu] handle %u status %d\n",
-		client->id, h_synx, rc);
+		"[sess :%llu] handle %u synx coredata status %d and dma fence status %d\n",
+		client->id, h_synx, rc, status);
 
 fail:
 	synx_util_release_handle(synx_data);

+ 37 - 43
msm/synx/synx_global.c

@@ -460,7 +460,7 @@ u32 synx_global_get_status(u32 idx)
 {
 	int rc;
 	unsigned long flags;
-	u32 status;
+	u32 status = SYNX_STATE_ACTIVE;
 	struct synx_global_coredata *synx_g_obj;
 
 	if (!synx_gmem.table)
@@ -473,7 +473,8 @@ u32 synx_global_get_status(u32 idx)
 	if (rc)
 		return rc;
 	synx_g_obj = &synx_gmem.table[idx];
-	status = synx_g_obj->status;
+	if (synx_g_obj->status != SYNX_STATE_ACTIVE && synx_g_obj->num_child == 0)
+		status = synx_g_obj->status;
 	synx_gmem_unlock(idx, &flags);
 
 	return status;
@@ -500,8 +501,10 @@ u32 synx_global_test_status_set_wait(u32 idx,
 	synx_global_print_data(synx_g_obj, __func__);
 	status = synx_g_obj->status;
 	/* if handle is still ACTIVE */
-	if (status == SYNX_STATE_ACTIVE)
+	if (status == SYNX_STATE_ACTIVE || synx_g_obj->num_child != 0) {
 		synx_g_obj->waiters |= (1UL << id);
+		status = SYNX_STATE_ACTIVE;
+	}
 	else
 		dprintk(SYNX_DBG, "handle %u already signaled %u",
 			synx_g_obj->handle, synx_g_obj->status);
@@ -533,21 +536,17 @@ static int synx_global_update_status_core(u32 idx,
 	if (synx_g_obj->num_child != 0) {
 		/* composite handle */
 		synx_g_obj->num_child--;
+		if (synx_g_obj->status == SYNX_STATE_ACTIVE ||
+			(status > SYNX_STATE_SIGNALED_SUCCESS &&
+			status <= SYNX_STATE_SIGNALED_MAX))
+			synx_g_obj->status = status;
+
 		if (synx_g_obj->num_child == 0) {
-			if (synx_g_obj->status == SYNX_STATE_ACTIVE) {
-				synx_g_obj->status =
-					(status == SYNX_STATE_SIGNALED_SUCCESS) ?
-					SYNX_STATE_SIGNALED_SUCCESS : SYNX_STATE_SIGNALED_ERROR;
-				data |= synx_g_obj->status;
-				synx_global_get_waiting_cores_locked(synx_g_obj,
-					wait_cores);
-				synx_global_get_parents_locked(synx_g_obj, h_parents);
-			} else {
-				data = 0;
-				dprintk(SYNX_WARN,
-					"merged handle %u already in state %u\n",
-					synx_g_obj->handle, synx_g_obj->status);
-			}
+			data |= synx_g_obj->status;
+			synx_global_get_waiting_cores_locked(synx_g_obj,
+				wait_cores);
+			synx_global_get_parents_locked(synx_g_obj, h_parents);
+
 			/* release ref held by constituting handles */
 			synx_g_obj->refcount--;
 			if (synx_g_obj->refcount == 0) {
@@ -555,15 +554,6 @@ static int synx_global_update_status_core(u32 idx,
 					sizeof(*synx_g_obj));
 				clear = true;
 			}
-		} else if (status != SYNX_STATE_SIGNALED_SUCCESS) {
-			synx_g_obj->status = SYNX_STATE_SIGNALED_ERROR;
-			data |= synx_g_obj->status;
-			synx_global_get_waiting_cores_locked(synx_g_obj,
-				wait_cores);
-			synx_global_get_parents_locked(synx_g_obj, h_parents);
-			dprintk(SYNX_WARN,
-				"merged handle %u signaled with error state\n",
-				synx_g_obj->handle);
 		} else {
 			/* pending notification from  handles */
 			data = 0;
@@ -723,8 +713,8 @@ int synx_global_merge(u32 *idx_list, u32 num_list, u32 p_idx)
 	struct synx_global_coredata *synx_g_obj;
 	u32 i, j = 0;
 	u32 idx;
-	bool sig_error = false;
 	u32 num_child = 0;
+	u32 parent_status = SYNX_STATE_ACTIVE;
 
 	if (!synx_gmem.table)
 		return -SYNX_NOMEM;
@@ -746,18 +736,26 @@ int synx_global_merge(u32 *idx_list, u32 num_list, u32 p_idx)
 			goto fail;
 
 		synx_g_obj = &synx_gmem.table[idx];
-		if (synx_g_obj->status == SYNX_STATE_ACTIVE) {
-			for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
-				if (synx_g_obj->parents[i] == 0) {
-					synx_g_obj->parents[i] = p_idx;
-					break;
-				}
+		for (i = 0; i < SYNX_GLOBAL_MAX_PARENTS; i++) {
+			if (synx_g_obj->parents[i] == 0) {
+				synx_g_obj->parents[i] = p_idx;
+				break;
 			}
-			num_child++;
-		} else if (synx_g_obj->status >
-			SYNX_STATE_SIGNALED_SUCCESS) {
-			sig_error = true;
 		}
+		if (synx_g_obj->status == SYNX_STATE_ACTIVE)
+			num_child++;
+		else if (synx_g_obj->status >
+			SYNX_STATE_SIGNALED_SUCCESS &&
+			synx_g_obj->status <= SYNX_STATE_SIGNALED_MAX)
+			parent_status = synx_g_obj->status;
+		else if (parent_status == SYNX_STATE_ACTIVE)
+			parent_status = synx_g_obj->status;
+
+		if (synx_g_obj->status != SYNX_STATE_ACTIVE && synx_g_obj->num_child != 0)
+			num_child++;
+
+		dprintk(SYNX_MEM, "synx_obj->status %d parent status %d\n",
+			synx_g_obj->status, parent_status);
 		synx_gmem_unlock(idx, &flags);
 
 		if (i >= SYNX_GLOBAL_MAX_PARENTS) {
@@ -773,13 +771,9 @@ int synx_global_merge(u32 *idx_list, u32 num_list, u32 p_idx)
 		goto fail;
 	synx_g_obj = &synx_gmem.table[p_idx];
 	synx_g_obj->num_child += num_child;
-	if (sig_error)
-		synx_g_obj->status = SYNX_STATE_SIGNALED_ERROR;
-	else if (synx_g_obj->num_child != 0)
+	if (synx_g_obj->num_child != 0)
 		synx_g_obj->refcount++;
-	else if (synx_g_obj->num_child == 0 &&
-		synx_g_obj->status == SYNX_STATE_ACTIVE)
-		synx_g_obj->status = SYNX_STATE_SIGNALED_SUCCESS;
+	synx_g_obj->status = parent_status;
 	synx_global_print_data(synx_g_obj, __func__);
 	synx_gmem_unlock(p_idx, &flags);
 

+ 3 - 0
msm/synx/synx_global.h

@@ -54,6 +54,9 @@ enum synx_core_id {
 #define SYNX_STATE_SIGNALED_EXTERNAL   5
 #define SYNX_STATE_SIGNALED_SSR        6
 
+/* dma fence states */
+#define SYNX_DMA_FENCE_STATE_MAX             4096
+
 /**
  * struct synx_global_coredata - Synx global object, used for book keeping
  * of all metadata associated with each individual global entry

+ 2 - 1
msm/synx/synx_private.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __SYNX_PRIVATE_H__
@@ -149,6 +149,7 @@ struct synx_coredata {
 	struct mutex obj_lock;
 	struct kref refcount;
 	u32 type;
+	u32 status;
 	u32 num_bound_synxs;
 	struct synx_bind_desc bound_synxs[SYNX_MAX_NUM_BINDINGS];
 	struct list_head reg_cbs_list;

+ 9 - 7
msm/synx/synx_util.c

@@ -108,6 +108,7 @@ int synx_util_init_coredata(struct synx_coredata *synx_obj,
 	if (rc != SYNX_SUCCESS)
 		goto clean;
 
+	synx_obj->status = synx_util_get_object_status(synx_obj);
 	return SYNX_SUCCESS;
 
 clean:
@@ -217,6 +218,7 @@ int synx_util_init_group_coredata(struct synx_coredata *synx_obj,
 	kref_init(&synx_obj->refcount);
 	mutex_init(&synx_obj->obj_lock);
 	INIT_LIST_HEAD(&synx_obj->reg_cbs_list);
+	synx_obj->status = synx_util_get_object_status(synx_obj);
 
 	synx_util_activate(synx_obj);
 	return rc;
@@ -731,7 +733,7 @@ static u32 __fence_state(struct dma_fence *fence, bool locked)
 static u32 __fence_group_state(struct dma_fence *fence, bool locked)
 {
 	u32 i = 0;
-	u32 state = SYNX_STATE_INVALID;
+	u32 state = SYNX_STATE_INVALID, parent_state = SYNX_STATE_INVALID;
 	struct dma_fence_array *array = NULL;
 	u32 intr, actv_cnt, sig_cnt, err_cnt;
 
@@ -747,6 +749,8 @@ static u32 __fence_group_state(struct dma_fence *fence, bool locked)
 
 	for (i = 0; i < array->num_fences; i++) {
 		intr = __fence_state(array->fences[i], locked);
+		if (err_cnt == 0)
+			parent_state = intr;
 		switch (intr) {
 		case SYNX_STATE_ACTIVE:
 			actv_cnt++;
@@ -755,7 +759,7 @@ static u32 __fence_group_state(struct dma_fence *fence, bool locked)
 			sig_cnt++;
 			break;
 		default:
-			err_cnt++;
+			intr > SYNX_STATE_SIGNALED_MAX ? sig_cnt++ : err_cnt++;
 		}
 	}
 
@@ -763,12 +767,10 @@ static u32 __fence_group_state(struct dma_fence *fence, bool locked)
 		"group cnt stats act:%u, sig: %u, err: %u\n",
 		actv_cnt, sig_cnt, err_cnt);
 
-	if (err_cnt)
-		state = SYNX_STATE_SIGNALED_ERROR;
-	else if (actv_cnt)
+	if (actv_cnt)
 		state = SYNX_STATE_ACTIVE;
-	else if (sig_cnt == array->num_fences)
-		state = SYNX_STATE_SIGNALED_SUCCESS;
+	else
+		state = parent_state;
 
 	return state;
 }