Browse Source

msm: synx: async_wait timeout changes

Adding timeout parameter for async wait so the callback
will be invoked on timer expiry if not signalled.

Change-Id: Ia31f59021f00befed5317fdac262d823c659c6bf
Signed-off-by: Ram Nagesh <[email protected]>
Signed-off-by: Urvesh Rathod <[email protected]>
Urvesh Rathod 2 years ago
parent
commit
d87e10c694
4 changed files with 82 additions and 4 deletions
  1. 66 4
      msm/synx/synx.c
  2. 1 0
      msm/synx/synx_global.h
  3. 3 0
      msm/synx/synx_private.h
  4. 12 0
      msm/synx/synx_util.c

+ 66 - 4
msm/synx/synx.c

@@ -882,6 +882,52 @@ static int synx_match_payload(struct synx_kernel_payload *cb_payload,
 	return rc;
 }
 
+/* Timer Callback function. This will be called when timer expires */
+void synx_timer_cb(struct timer_list *data)
+{
+	struct synx_client *client;
+	struct synx_handle_coredata *synx_data;
+	struct synx_coredata *synx_obj;
+	struct synx_cb_data *synx_cb = container_of(data, struct synx_cb_data, synx_timer);
+
+	client = synx_get_client(synx_cb->session);
+	if (IS_ERR_OR_NULL(client)) {
+		dprintk(SYNX_ERR,
+			"invalid session data 0x%x in cb payload\n",
+			synx_cb->session);
+		return;
+	}
+	synx_data = synx_util_acquire_handle(client, synx_cb->h_synx);
+	synx_obj = synx_util_obtain_object(synx_data);
+	if (IS_ERR_OR_NULL(synx_obj)) {
+		dprintk(SYNX_ERR,
+			"[sess :0x%llx] invalid handle access 0x%x\n",
+			synx_cb->session, synx_cb->h_synx);
+		return;
+	}
+	dprintk(SYNX_VERB,
+		"Timer expired for synx_cb 0x%x timeout 0x%llx. Deleting the timer.\n",
+		synx_cb, synx_cb->timeout);
+
+	synx_cb->status = SYNX_STATE_TIMEOUT;
+	del_timer(&synx_cb->synx_timer);
+	list_del_init(&synx_cb->node);
+	queue_work(synx_dev->wq_cb, &synx_cb->cb_dispatch);
+}
+
+static int synx_start_timer(struct synx_cb_data *synx_cb)
+{
+	int rc = 0;
+
+	timer_setup(&synx_cb->synx_timer, synx_timer_cb, 0);
+	rc = mod_timer(&synx_cb->synx_timer, jiffies + msecs_to_jiffies(synx_cb->timeout));
+	dprintk(SYNX_VERB,
+		"Timer started for synx_cb 0x%x timeout 0x%llx\n",
+		synx_cb, synx_cb->timeout);
+	return rc;
+}
+
+
 int synx_async_wait(struct synx_session *session,
 	struct synx_callback_params *params)
 {
@@ -897,9 +943,6 @@ int synx_async_wait(struct synx_session *session,
 	if (IS_ERR_OR_NULL(session) || IS_ERR_OR_NULL(params))
 		return -SYNX_INVALID;
 
-	if (params->timeout_ms != SYNX_NO_TIMEOUT)
-		return -SYNX_NOSUPPORT;
-
 	client = synx_get_client(session);
 	if (IS_ERR_OR_NULL(client))
 		return -SYNX_INVALID;
@@ -952,6 +995,8 @@ int synx_async_wait(struct synx_session *session,
 
 	synx_cb->session = session;
 	synx_cb->idx = idx;
+	synx_cb->h_synx = params->h_synx;
+
 	INIT_WORK(&synx_cb->cb_dispatch, synx_util_cb_dispatch);
 
 	/* add callback if object still ACTIVE, dispatch if SIGNALED */
@@ -959,6 +1004,17 @@ int synx_async_wait(struct synx_session *session,
 		dprintk(SYNX_VERB,
 			"[sess :%llu] callback added for handle %u\n",
 			client->id, params->h_synx);
+		synx_cb->timeout = params->timeout_ms;
+		if (params->timeout_ms != SYNX_NO_TIMEOUT) {
+			rc = synx_start_timer(synx_cb);
+			if (rc != SYNX_SUCCESS) {
+				dprintk(SYNX_ERR,
+					"[sess :%llu] timer start failed - synx_cb: 0x%x, params->timeout_ms: 0x%llx, handle: 0x%x, ret : %d\n",
+					client->id, synx_cb, params->timeout_ms,
+					params->h_synx, rc);
+				goto release;
+			}
+		}
 		list_add(&synx_cb->node, &synx_obj->reg_cbs_list);
 	} else {
 		synx_cb->status = status;
@@ -1024,7 +1080,7 @@ int synx_cancel_async_wait(
 	status = synx_util_get_object_status(synx_obj);
 	if (status != SYNX_STATE_ACTIVE) {
 		dprintk(SYNX_ERR,
-			"handle %u already signaled cannot cancel\n",
+			"handle %u already signaled or timed out, cannot cancel\n",
 			params->h_synx);
 		rc = -SYNX_INVALID;
 		goto release;
@@ -1052,6 +1108,12 @@ int synx_cancel_async_wait(
 
 		cb_payload = &client->cb_table[synx_cb->idx];
 		ret = synx_match_payload(&cb_payload->kernel_cb, &payload);
+		if (synx_cb->timeout != SYNX_NO_TIMEOUT) {
+			dprintk(SYNX_VERB,
+				"Deleting timer synx_cb 0x%x, timeout 0x%llx\n",
+				synx_cb, synx_cb->timeout);
+			del_timer(&synx_cb->synx_timer);
+		}
 		switch (ret) {
 		case 1:
 			/* queue the cancel cb work */

+ 1 - 0
msm/synx/synx_global.h

@@ -53,6 +53,7 @@ enum synx_core_id {
 #define SYNX_STATE_SIGNALED_ERROR      3
 #define SYNX_STATE_SIGNALED_EXTERNAL   5
 #define SYNX_STATE_SIGNALED_SSR        6
+#define SYNX_STATE_TIMEOUT             7
 
 /* dma fence states */
 #define SYNX_DMA_FENCE_STATE_MAX             4096

+ 3 - 0
msm/synx/synx_private.h

@@ -101,7 +101,10 @@ struct synx_kernel_payload {
 struct synx_cb_data {
 	struct synx_session *session;
 	u32 idx;
+	u32 h_synx;
 	u32 status;
+	struct timer_list synx_timer;
+	u64 timeout;
 	struct work_struct cb_dispatch;
 	struct list_head node;
 };

+ 12 - 0
msm/synx/synx_util.c

@@ -301,6 +301,12 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj)
 			"dipatching un-released callbacks of session %pK\n",
 			synx_cb->session);
 		synx_cb->status = SYNX_STATE_SIGNALED_CANCEL;
+		if (synx_cb->timeout != SYNX_NO_TIMEOUT) {
+			dprintk(SYNX_VERB,
+				"Deleting timer synx_cb 0x%x, timeout 0x%llx\n",
+				synx_cb, synx_cb->timeout);
+			del_timer(&synx_cb->synx_timer);
+		}
 		list_del_init(&synx_cb->node);
 		queue_work(synx_dev->wq_cb,
 			&synx_cb->cb_dispatch);
@@ -1175,6 +1181,12 @@ void synx_util_callback_dispatch(struct synx_coredata *synx_obj, u32 status)
 	list_for_each_entry_safe(synx_cb,
 		synx_cb_temp, &synx_obj->reg_cbs_list, node) {
 		synx_cb->status = status;
+		if (synx_cb->timeout != SYNX_NO_TIMEOUT) {
+			dprintk(SYNX_VERB,
+				"Deleting timer synx_cb 0x%x, timeout 0x%llx\n",
+				synx_cb, synx_cb->timeout);
+			del_timer(&synx_cb->synx_timer);
+		}
 		list_del_init(&synx_cb->node);
 		queue_work(synx_dev->wq_cb,
 			&synx_cb->cb_dispatch);