diff --git a/msm/synx/synx.c b/msm/synx/synx.c index 2fde5d1c07..ab51ea9b6a 100644 --- a/msm/synx/synx.c +++ b/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 */ diff --git a/msm/synx/synx_global.h b/msm/synx/synx_global.h index 074c2b6a79..9e22120204 100644 --- a/msm/synx/synx_global.h +++ b/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 diff --git a/msm/synx/synx_private.h b/msm/synx/synx_private.h index f9ef273aa7..25328fa39b 100644 --- a/msm/synx/synx_private.h +++ b/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; }; diff --git a/msm/synx/synx_util.c b/msm/synx/synx_util.c index 94dc12c6cc..86d3e593da 100644 --- a/msm/synx/synx_util.c +++ b/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);