Loading drivers/media/platform/msm/synx/synx.c +46 −132 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "synx: " fmt Loading Loading @@ -305,18 +305,14 @@ int synx_signal(struct synx_session session_id, s32 h_synx, u32 status) } EXPORT_SYMBOL(synx_signal); static int synx_match_payload(struct synx_client_cb *cb, struct synx_kernel_payload *payload, bool is_kernel_cb) static int synx_match_payload(struct synx_kernel_payload *cb_payload, struct synx_kernel_payload *payload) { int rc = 0; if (!cb || !payload) if (!cb_payload || !payload) return -EINVAL; if (is_kernel_cb) { struct synx_kernel_payload *cb_payload = &cb->kernel_cb; if ((cb_payload->cb_func == payload->cb_func) && (cb_payload->data == payload->data)) { if (payload->cancel_cb_func) { Loading @@ -325,50 +321,13 @@ static int synx_match_payload(struct synx_client_cb *cb, rc = 1; } else { rc = 2; pr_debug("kernel cb deregistration success\n"); } } } else { struct synx_user_payload *cb_payload = &cb->user_cb; struct synx_user_payload *user_payload = payload->data; if ((cb_payload->data[0] == user_payload->data[0]) && (cb_payload->data[1] == user_payload->data[1])) { if (user_payload->data[2]) { memcpy(cb_payload->data, user_payload->data, SYNX_PAYLOAD_WORDS * sizeof(__u64)); rc = 1; } else { rc = 2; pr_debug("user cb deregistration success\n"); } pr_debug("kernel cb de-registration success\n"); } } return rc; } void synx_default_user_callback(s32 h_synx, int status, void *data) { struct synx_user_payload *payload = data; struct synx_client *client = payload->client; struct synx_client_cb *cb = container_of(payload, struct synx_client_cb, user_cb); if (client) { payload->status = status; pr_debug("user cb queued for handle %d\n", h_synx); mutex_lock(&client->event_q_lock); list_add_tail(&cb->node, &client->event_q); mutex_unlock(&client->event_q_lock); wake_up_all(&client->event_wq); } else { pr_err("%s: invalid client session\n", __func__); } } int synx_register_callback(struct synx_session session_id, s32 h_synx, synx_callback cb_func, Loading Loading @@ -408,40 +367,16 @@ int synx_register_callback(struct synx_session session_id, goto clear; } if (cb_func == synx_default_user_callback) { /* userspace callback index allocated already */ idx = *((u32 *)userdata); if (idx < SYNX_MAX_OBJS) { /* data used in default callback func */ userdata = &client->cb_table[idx].user_cb; } else { pr_err("%s: [sess: %u] invalid cb index\n", __func__, client->id); kfree(synx_cb); rc = -EINVAL; goto clear; } } else { /* obtain a free index from client cb table */ rc = synx_util_alloc_cb_entry(client, &idx); if (rc) { pr_err("[sess :%u] error allocating cb entry\n", client->id); kfree(synx_cb); goto clear; } } payload.h_synx = h_synx; payload.cb_func = cb_func; payload.data = userdata; /* update the cb entry with kernel cb data */ rc = synx_util_update_cb_entry(client, &payload, idx); /* allocate a free index from client cb table */ rc = synx_util_alloc_cb_entry(client, &payload, &idx); if (rc) { pr_err("[sess :%u] error allocating cb entry\n", client->id); kfree(synx_cb); clear_bit(idx, client->cb_bitmap); goto clear; } Loading @@ -454,7 +389,7 @@ int synx_register_callback(struct synx_session session_id, /* add callback if object still ACTIVE, dispatch if SIGNALED */ if (status == SYNX_STATE_ACTIVE) { pr_debug("[sess: %u] callback added\n", client->id); list_add_tail(&synx_cb->node, &synx_obj->reg_cbs_list); list_add(&synx_cb->node, &synx_obj->reg_cbs_list); } else { synx_cb->status = status; pr_debug("[sess: %u] callback queued\n", client->id); Loading @@ -481,7 +416,6 @@ int synx_deregister_callback(struct synx_session session_id, { int rc = 0, ret = 0; u32 status; bool is_kernel_cb = true; bool match_found = false; struct synx_client *client; struct synx_coredata *synx_obj; Loading Loading @@ -509,9 +443,6 @@ int synx_deregister_callback(struct synx_session session_id, goto clear; } if (cb_func == synx_default_user_callback) is_kernel_cb = false; payload.h_synx = h_synx; payload.cb_func = cb_func; payload.data = userdata; Loading @@ -533,7 +464,8 @@ int synx_deregister_callback(struct synx_session session_id, &synx_obj->reg_cbs_list, node) { if (synx_cb->session_id.client_id != client->id) { continue; } else if (synx_cb->idx >= SYNX_MAX_OBJS) { } else if (synx_cb->idx == 0 || synx_cb->idx >= SYNX_MAX_OBJS) { /* * this should not happen. Even if it does, * the allocated memory will be cleaned up Loading @@ -546,7 +478,7 @@ int synx_deregister_callback(struct synx_session session_id, } cb_payload = &client->cb_table[synx_cb->idx]; ret = synx_match_payload(cb_payload, &payload, is_kernel_cb); ret = synx_match_payload(&cb_payload->kernel_cb, &payload); switch (ret) { case 1: /* queue the cancel cb work */ Loading @@ -558,6 +490,9 @@ int synx_deregister_callback(struct synx_session session_id, break; case 2: /* no cancellation cb */ if (synx_util_clear_cb_entry(client, cb_payload)) pr_err("%s: [sess: %u] error clearing cb %d\n", __func__, client->id, h_synx); list_del_init(&synx_cb->node); kfree(synx_cb); match_found = true; Loading Loading @@ -1206,10 +1141,7 @@ static int synx_handle_register_user_payload( struct synx_session session_id) { int rc = 0; u32 idx; struct synx_userpayload_info user_data; struct synx_client *client; struct synx_client_cb *cb_data; if (k_ioctl->size != sizeof(user_data)) return -EINVAL; Loading @@ -1219,34 +1151,14 @@ static int synx_handle_register_user_payload( k_ioctl->size)) return -EFAULT; client = synx_get_client(session_id); if (!client) return -EINVAL; /* obtain a free index from the cb table */ rc = synx_util_alloc_cb_entry(client, &idx); if (rc) { pr_err("%s: [sess :%u] error allocating cb entry\n", __func__, client->id); goto fail; } cb_data = &client->cb_table[idx]; cb_data->user_cb.client = client; cb_data->user_cb.h_synx = user_data.synx_obj; memcpy(&cb_data->user_cb.data, user_data.payload, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); pr_debug("user cb registration with payload %x\n", user_data.payload[0]); rc = synx_register_callback(session_id, user_data.synx_obj, synx_default_user_callback, &idx); if (rc) { synx_util_default_user_callback, (void *)user_data.payload[0]); if (rc) pr_err("[sess: %u] user cb registration failed for handle %d\n", session_id.client_id, user_data.synx_obj); clear_bit(idx, client->cb_bitmap); } fail: synx_put_client(client); return rc; } Loading @@ -1256,7 +1168,6 @@ static int synx_handle_deregister_user_payload( { int rc = 0; struct synx_userpayload_info user_data; struct synx_user_payload payload; if (k_ioctl->size != sizeof(user_data)) return -EINVAL; Loading @@ -1266,16 +1177,12 @@ static int synx_handle_deregister_user_payload( k_ioctl->size)) return -EFAULT; payload.h_synx = user_data.synx_obj; memcpy(&payload.data, user_data.payload, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); rc = synx_deregister_callback(session_id, payload.h_synx, synx_default_user_callback, &payload, NULL); user_data.synx_obj, synx_util_default_user_callback, (void *)user_data.payload[0], NULL); if (rc) pr_err("[sess: %u] callback deregistration failed for handle %d\n", session_id.client_id, payload.h_synx); session_id.client_id, user_data.synx_obj); return rc; } Loading Loading @@ -1420,7 +1327,6 @@ static ssize_t synx_read(struct file *filep, char __user *buf, size_t size, loff_t *f_pos) { ssize_t rc = 0; u32 idx; struct synx_client *client = NULL; struct synx_client_cb *cb; struct synx_session *session = filep->private_data; Loading @@ -1442,18 +1348,25 @@ static ssize_t synx_read(struct file *filep, cb = list_first_entry_or_null(&client->event_q, struct synx_client_cb, node); if (!cb) { mutex_unlock(&client->event_q_lock); rc = 0; goto fail; } if (cb->idx == 0 || cb->idx >= SYNX_MAX_OBJS) { pr_err("%s invalid index\n", __func__); mutex_unlock(&client->event_q_lock); rc = -EINVAL; goto fail; } list_del_init(&cb->node); mutex_unlock(&client->event_q_lock); rc = size; data.synx_obj = cb->user_cb.h_synx; data.reserved = cb->user_cb.status; memcpy(data.payload, &cb->user_cb.data, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); data.synx_obj = cb->kernel_cb.h_synx; data.reserved = cb->kernel_cb.status; data.payload[0] = (u64)cb->kernel_cb.data; if (copy_to_user(buf, &data, sizeof(struct synx_userpayload_info))) { Loading @@ -1461,9 +1374,9 @@ static ssize_t synx_read(struct file *filep, rc = -EFAULT; } idx = cb->idx; memset(cb, 0, sizeof(*cb)); clear_bit(idx, client->cb_bitmap); if (synx_util_clear_cb_entry(client, cb)) pr_err("%s: [sess: %u] error clearing cb for handle %d\n", __func__, client->id, data.synx_obj); fail: synx_put_client(client); pr_debug("[sess: %u] exit with status %d\n", Loading Loading @@ -1539,6 +1452,7 @@ int synx_initialize(struct synx_session *session_id, init_waitqueue_head(&client->event_wq); /* zero handle not allowed */ set_bit(0, client->bitmap); set_bit(0, client->cb_bitmap); mutex_lock(&synx_dev->dev_table_lock); client_metadata = &synx_dev->client_table[idx]; Loading @@ -1547,7 +1461,7 @@ int synx_initialize(struct synx_session *session_id, mutex_unlock(&synx_dev->dev_table_lock); session_id->client_id = idx; pr_debug("index location %ld allocated for client %s\n", pr_info("[sess: %u] session created %s\n", idx, params->name); return 0; Loading drivers/media/platform/msm/synx/synx_private.h +5 −20 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __SYNX_PRIVATE_H__ Loading Loading @@ -82,33 +82,19 @@ struct error_node { * callback registered on a synx object * * @h_synx : Synx object handle * @status : Synx obj status or callback failure * @data : Callback data, passed by client driver * @cb_func : Callback function, registered by client driver * @cancel_cb_func : Cancellation callback function */ struct synx_kernel_payload { s32 h_synx; u32 status; void *data; synx_callback cb_func; synx_callback cancel_cb_func; }; /** * struct synx_user_payload - Single node of information about a callback * registered from user space on a synx object * * @client : Synx client structure * @h_synx : Synx object handle * @status : Synx obj status or callback failure * @data : Payload data, opaque to kernel */ struct synx_user_payload { struct synx_client *client; s32 h_synx; u32 status; u64 data[SYNX_PAYLOAD_WORDS]; }; /** * struct synx_cb_data - Single node of information about callback * registered by client for the synx object Loading @@ -132,17 +118,16 @@ struct synx_cb_data { * registered by client * * @is_valid : True if this is a valid entry * @is_kernel_cb : True for kernel callback, false for user callback * @idx : Index of the client callback table * @client : Client session * @kernel_cb : Kernel callback payload * @user_cb : Userspace callback payload * @node : List member used to append this node to event list */ struct synx_client_cb { bool is_valid; u32 idx; struct synx_client *client; struct synx_kernel_payload kernel_cb; struct synx_user_payload user_cb; struct list_head node; }; Loading drivers/media/platform/msm/synx/synx_util.c +71 −24 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "synx: " fmt Loading Loading @@ -623,13 +623,14 @@ struct bind_operations *synx_util_get_bind_ops(u32 type) } int synx_util_alloc_cb_entry(struct synx_client *client, struct synx_kernel_payload *data, u32 *cb_idx) { bool bit; long idx; struct synx_client_cb *cb; if (!client || !cb_idx) if (!client || !data || !cb_idx) return -EINVAL; do { Loading @@ -644,28 +645,53 @@ int synx_util_alloc_cb_entry(struct synx_client *client, cb = &client->cb_table[idx]; memset(cb, 0, sizeof(*cb)); cb->is_valid = true; cb->client = client; cb->idx = idx; memcpy(&cb->kernel_cb, data, sizeof(cb->kernel_cb)); *cb_idx = idx; pr_debug("[sess: %u] allocated cb index %u\n", client->id, idx); pr_debug("[sess: %u] allocated cb index %u\n", client->id, *cb_idx); return 0; } int synx_util_update_cb_entry(struct synx_client *client, void *data, u32 cb_idx) int synx_util_clear_cb_entry(struct synx_client *client, struct synx_client_cb *cb) { struct synx_client_cb *cb; int rc = 0; u32 idx; if (!client || !data || (cb_idx >= SYNX_MAX_OBJS)) if (!cb) return -EINVAL; cb = &client->cb_table[cb_idx]; cb->is_valid = true; memcpy(&cb->kernel_cb, data, sizeof(cb->kernel_cb)); idx = cb->idx; memset(cb, 0, sizeof(*cb)); if (idx && idx < SYNX_MAX_OBJS) { clear_bit(idx, client->cb_bitmap); } else { pr_err("%s: found invalid index\n", __func__); rc = -EINVAL; } pr_debug("[sess: %u] updated cb index %u\n", client->id, cb_idx); return 0; return rc; } void synx_util_default_user_callback(s32 h_synx, int status, void *data) { struct synx_client_cb *cb = data; if (cb && cb->client) { pr_debug("user cb queued for handle %d\n", h_synx); cb->kernel_cb.status = status; mutex_lock(&cb->client->event_q_lock); list_add_tail(&cb->node, &cb->client->event_q); mutex_unlock(&cb->client->event_q_lock); wake_up_all(&cb->client->event_wq); } else { pr_err("%s: invalid params\n", __func__); } } void synx_util_callback_dispatch(struct synx_coredata *synx_obj, u32 status) Loading Loading @@ -693,7 +719,8 @@ void synx_util_cb_dispatch(struct work_struct *cb_dispatch) container_of(cb_dispatch, struct synx_cb_data, cb_dispatch); struct synx_client *client; struct synx_client_cb *cb; struct synx_kernel_payload *payload; struct synx_kernel_payload payload; u32 status; client = synx_get_client(synx_cb->session_id); if (!client) { Loading @@ -702,26 +729,46 @@ void synx_util_cb_dispatch(struct work_struct *cb_dispatch) goto free; } if (synx_cb->idx >= SYNX_MAX_OBJS) { pr_err("[sess: %u] invalid cb index\n", client->id); if (synx_cb->idx == 0 || synx_cb->idx >= SYNX_MAX_OBJS) { pr_err("[sess: %u] invalid cb index %u\n", client->id, synx_cb->idx); goto fail; } status = synx_cb->status; cb = &client->cb_table[synx_cb->idx]; if (!cb->is_valid) { pr_err("invalid cb payload\n"); goto fail; } payload = &cb->kernel_cb; memcpy(&payload, &cb->kernel_cb, sizeof(cb->kernel_cb)); payload.status = status; if (payload.cb_func == synx_util_default_user_callback) { /* * need to send client cb data for default * user cb (userspace cb) */ payload.data = cb; } else { /* * clear the cb entry. userspace cb entry * will be cleared after data read by the * polling thread or when client is destroyed */ if (synx_util_clear_cb_entry(client, cb)) pr_err("%s: [sess: %u] error clearing cb entry\n", __func__, client->id); } pr_debug("[sess: %u] kernel cb dispatch for handle %d\n", client->id, payload->h_synx); client->id, payload.h_synx); /* dispatch kernel callback */ payload->cb_func(payload->h_synx, synx_cb->status, payload->data); payload.cb_func(payload.h_synx, payload.status, payload.data); fail: synx_put_client(client); Loading Loading @@ -926,7 +973,7 @@ static void synx_client_destroy(struct kref *kref) memset(client_metadata, 0, sizeof(*client_metadata)); clear_bit(client->id, synx_dev->bitmap); pr_debug("[sess: %u] session destroyed %s\n", pr_info("[sess: %u] session destroyed %s\n", client->id, client->name); kfree(client); } Loading drivers/media/platform/msm/synx/synx_util.h +16 −7 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __SYNX_UTIL_H__ Loading Loading @@ -112,25 +112,25 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj); * @brief: Function to allocate synx_client_cb entry from cb table * * @param client : Pointer to client session info * @param data : Kernel payload data * @param cb_idx : Allocated index (filled by function) * * @return Status of operation. Negative in case of error. Zero otherwise. */ int synx_util_alloc_cb_entry(struct synx_client *client, struct synx_kernel_payload *data, u32 *cb_idx); /** * @brief: Function to allocate synx_client_cb entry from cb table * @brief: Function to clean up synx_client_cb entry from cb table * * @param client : Pointer to client session info * @param data : Opaque payload data * @param cb_idx : Callback table index * @param cb : Pointer to client cb entry * * @return Status of operation. Negative in case of error. Zero otherwise. */ int synx_util_update_cb_entry(struct synx_client *client, void *data, u32 cb_idx); int synx_util_clear_cb_entry(struct synx_client *client, struct synx_client_cb *cb); /** * @brief: Function to initialize synx object handle for the client Loading @@ -155,6 +155,15 @@ int synx_util_init_handle(struct synx_client *client, */ int synx_util_activate(struct synx_coredata *synx_obj); /** * @brief: Default kernel callback function to handle userspace callbacks * * @param h_synx : Synx object handle * @param status : Synx object state * @param data : Opaque pointer */ void synx_util_default_user_callback(s32 h_synx, int status, void *data); /** * @brief: Function to queue all the registered callbacks by clients for * the synx object Loading Loading
drivers/media/platform/msm/synx/synx.c +46 −132 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "synx: " fmt Loading Loading @@ -305,18 +305,14 @@ int synx_signal(struct synx_session session_id, s32 h_synx, u32 status) } EXPORT_SYMBOL(synx_signal); static int synx_match_payload(struct synx_client_cb *cb, struct synx_kernel_payload *payload, bool is_kernel_cb) static int synx_match_payload(struct synx_kernel_payload *cb_payload, struct synx_kernel_payload *payload) { int rc = 0; if (!cb || !payload) if (!cb_payload || !payload) return -EINVAL; if (is_kernel_cb) { struct synx_kernel_payload *cb_payload = &cb->kernel_cb; if ((cb_payload->cb_func == payload->cb_func) && (cb_payload->data == payload->data)) { if (payload->cancel_cb_func) { Loading @@ -325,50 +321,13 @@ static int synx_match_payload(struct synx_client_cb *cb, rc = 1; } else { rc = 2; pr_debug("kernel cb deregistration success\n"); } } } else { struct synx_user_payload *cb_payload = &cb->user_cb; struct synx_user_payload *user_payload = payload->data; if ((cb_payload->data[0] == user_payload->data[0]) && (cb_payload->data[1] == user_payload->data[1])) { if (user_payload->data[2]) { memcpy(cb_payload->data, user_payload->data, SYNX_PAYLOAD_WORDS * sizeof(__u64)); rc = 1; } else { rc = 2; pr_debug("user cb deregistration success\n"); } pr_debug("kernel cb de-registration success\n"); } } return rc; } void synx_default_user_callback(s32 h_synx, int status, void *data) { struct synx_user_payload *payload = data; struct synx_client *client = payload->client; struct synx_client_cb *cb = container_of(payload, struct synx_client_cb, user_cb); if (client) { payload->status = status; pr_debug("user cb queued for handle %d\n", h_synx); mutex_lock(&client->event_q_lock); list_add_tail(&cb->node, &client->event_q); mutex_unlock(&client->event_q_lock); wake_up_all(&client->event_wq); } else { pr_err("%s: invalid client session\n", __func__); } } int synx_register_callback(struct synx_session session_id, s32 h_synx, synx_callback cb_func, Loading Loading @@ -408,40 +367,16 @@ int synx_register_callback(struct synx_session session_id, goto clear; } if (cb_func == synx_default_user_callback) { /* userspace callback index allocated already */ idx = *((u32 *)userdata); if (idx < SYNX_MAX_OBJS) { /* data used in default callback func */ userdata = &client->cb_table[idx].user_cb; } else { pr_err("%s: [sess: %u] invalid cb index\n", __func__, client->id); kfree(synx_cb); rc = -EINVAL; goto clear; } } else { /* obtain a free index from client cb table */ rc = synx_util_alloc_cb_entry(client, &idx); if (rc) { pr_err("[sess :%u] error allocating cb entry\n", client->id); kfree(synx_cb); goto clear; } } payload.h_synx = h_synx; payload.cb_func = cb_func; payload.data = userdata; /* update the cb entry with kernel cb data */ rc = synx_util_update_cb_entry(client, &payload, idx); /* allocate a free index from client cb table */ rc = synx_util_alloc_cb_entry(client, &payload, &idx); if (rc) { pr_err("[sess :%u] error allocating cb entry\n", client->id); kfree(synx_cb); clear_bit(idx, client->cb_bitmap); goto clear; } Loading @@ -454,7 +389,7 @@ int synx_register_callback(struct synx_session session_id, /* add callback if object still ACTIVE, dispatch if SIGNALED */ if (status == SYNX_STATE_ACTIVE) { pr_debug("[sess: %u] callback added\n", client->id); list_add_tail(&synx_cb->node, &synx_obj->reg_cbs_list); list_add(&synx_cb->node, &synx_obj->reg_cbs_list); } else { synx_cb->status = status; pr_debug("[sess: %u] callback queued\n", client->id); Loading @@ -481,7 +416,6 @@ int synx_deregister_callback(struct synx_session session_id, { int rc = 0, ret = 0; u32 status; bool is_kernel_cb = true; bool match_found = false; struct synx_client *client; struct synx_coredata *synx_obj; Loading Loading @@ -509,9 +443,6 @@ int synx_deregister_callback(struct synx_session session_id, goto clear; } if (cb_func == synx_default_user_callback) is_kernel_cb = false; payload.h_synx = h_synx; payload.cb_func = cb_func; payload.data = userdata; Loading @@ -533,7 +464,8 @@ int synx_deregister_callback(struct synx_session session_id, &synx_obj->reg_cbs_list, node) { if (synx_cb->session_id.client_id != client->id) { continue; } else if (synx_cb->idx >= SYNX_MAX_OBJS) { } else if (synx_cb->idx == 0 || synx_cb->idx >= SYNX_MAX_OBJS) { /* * this should not happen. Even if it does, * the allocated memory will be cleaned up Loading @@ -546,7 +478,7 @@ int synx_deregister_callback(struct synx_session session_id, } cb_payload = &client->cb_table[synx_cb->idx]; ret = synx_match_payload(cb_payload, &payload, is_kernel_cb); ret = synx_match_payload(&cb_payload->kernel_cb, &payload); switch (ret) { case 1: /* queue the cancel cb work */ Loading @@ -558,6 +490,9 @@ int synx_deregister_callback(struct synx_session session_id, break; case 2: /* no cancellation cb */ if (synx_util_clear_cb_entry(client, cb_payload)) pr_err("%s: [sess: %u] error clearing cb %d\n", __func__, client->id, h_synx); list_del_init(&synx_cb->node); kfree(synx_cb); match_found = true; Loading Loading @@ -1206,10 +1141,7 @@ static int synx_handle_register_user_payload( struct synx_session session_id) { int rc = 0; u32 idx; struct synx_userpayload_info user_data; struct synx_client *client; struct synx_client_cb *cb_data; if (k_ioctl->size != sizeof(user_data)) return -EINVAL; Loading @@ -1219,34 +1151,14 @@ static int synx_handle_register_user_payload( k_ioctl->size)) return -EFAULT; client = synx_get_client(session_id); if (!client) return -EINVAL; /* obtain a free index from the cb table */ rc = synx_util_alloc_cb_entry(client, &idx); if (rc) { pr_err("%s: [sess :%u] error allocating cb entry\n", __func__, client->id); goto fail; } cb_data = &client->cb_table[idx]; cb_data->user_cb.client = client; cb_data->user_cb.h_synx = user_data.synx_obj; memcpy(&cb_data->user_cb.data, user_data.payload, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); pr_debug("user cb registration with payload %x\n", user_data.payload[0]); rc = synx_register_callback(session_id, user_data.synx_obj, synx_default_user_callback, &idx); if (rc) { synx_util_default_user_callback, (void *)user_data.payload[0]); if (rc) pr_err("[sess: %u] user cb registration failed for handle %d\n", session_id.client_id, user_data.synx_obj); clear_bit(idx, client->cb_bitmap); } fail: synx_put_client(client); return rc; } Loading @@ -1256,7 +1168,6 @@ static int synx_handle_deregister_user_payload( { int rc = 0; struct synx_userpayload_info user_data; struct synx_user_payload payload; if (k_ioctl->size != sizeof(user_data)) return -EINVAL; Loading @@ -1266,16 +1177,12 @@ static int synx_handle_deregister_user_payload( k_ioctl->size)) return -EFAULT; payload.h_synx = user_data.synx_obj; memcpy(&payload.data, user_data.payload, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); rc = synx_deregister_callback(session_id, payload.h_synx, synx_default_user_callback, &payload, NULL); user_data.synx_obj, synx_util_default_user_callback, (void *)user_data.payload[0], NULL); if (rc) pr_err("[sess: %u] callback deregistration failed for handle %d\n", session_id.client_id, payload.h_synx); session_id.client_id, user_data.synx_obj); return rc; } Loading Loading @@ -1420,7 +1327,6 @@ static ssize_t synx_read(struct file *filep, char __user *buf, size_t size, loff_t *f_pos) { ssize_t rc = 0; u32 idx; struct synx_client *client = NULL; struct synx_client_cb *cb; struct synx_session *session = filep->private_data; Loading @@ -1442,18 +1348,25 @@ static ssize_t synx_read(struct file *filep, cb = list_first_entry_or_null(&client->event_q, struct synx_client_cb, node); if (!cb) { mutex_unlock(&client->event_q_lock); rc = 0; goto fail; } if (cb->idx == 0 || cb->idx >= SYNX_MAX_OBJS) { pr_err("%s invalid index\n", __func__); mutex_unlock(&client->event_q_lock); rc = -EINVAL; goto fail; } list_del_init(&cb->node); mutex_unlock(&client->event_q_lock); rc = size; data.synx_obj = cb->user_cb.h_synx; data.reserved = cb->user_cb.status; memcpy(data.payload, &cb->user_cb.data, SYNX_USER_PAYLOAD_SIZE * sizeof(__u64)); data.synx_obj = cb->kernel_cb.h_synx; data.reserved = cb->kernel_cb.status; data.payload[0] = (u64)cb->kernel_cb.data; if (copy_to_user(buf, &data, sizeof(struct synx_userpayload_info))) { Loading @@ -1461,9 +1374,9 @@ static ssize_t synx_read(struct file *filep, rc = -EFAULT; } idx = cb->idx; memset(cb, 0, sizeof(*cb)); clear_bit(idx, client->cb_bitmap); if (synx_util_clear_cb_entry(client, cb)) pr_err("%s: [sess: %u] error clearing cb for handle %d\n", __func__, client->id, data.synx_obj); fail: synx_put_client(client); pr_debug("[sess: %u] exit with status %d\n", Loading Loading @@ -1539,6 +1452,7 @@ int synx_initialize(struct synx_session *session_id, init_waitqueue_head(&client->event_wq); /* zero handle not allowed */ set_bit(0, client->bitmap); set_bit(0, client->cb_bitmap); mutex_lock(&synx_dev->dev_table_lock); client_metadata = &synx_dev->client_table[idx]; Loading @@ -1547,7 +1461,7 @@ int synx_initialize(struct synx_session *session_id, mutex_unlock(&synx_dev->dev_table_lock); session_id->client_id = idx; pr_debug("index location %ld allocated for client %s\n", pr_info("[sess: %u] session created %s\n", idx, params->name); return 0; Loading
drivers/media/platform/msm/synx/synx_private.h +5 −20 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __SYNX_PRIVATE_H__ Loading Loading @@ -82,33 +82,19 @@ struct error_node { * callback registered on a synx object * * @h_synx : Synx object handle * @status : Synx obj status or callback failure * @data : Callback data, passed by client driver * @cb_func : Callback function, registered by client driver * @cancel_cb_func : Cancellation callback function */ struct synx_kernel_payload { s32 h_synx; u32 status; void *data; synx_callback cb_func; synx_callback cancel_cb_func; }; /** * struct synx_user_payload - Single node of information about a callback * registered from user space on a synx object * * @client : Synx client structure * @h_synx : Synx object handle * @status : Synx obj status or callback failure * @data : Payload data, opaque to kernel */ struct synx_user_payload { struct synx_client *client; s32 h_synx; u32 status; u64 data[SYNX_PAYLOAD_WORDS]; }; /** * struct synx_cb_data - Single node of information about callback * registered by client for the synx object Loading @@ -132,17 +118,16 @@ struct synx_cb_data { * registered by client * * @is_valid : True if this is a valid entry * @is_kernel_cb : True for kernel callback, false for user callback * @idx : Index of the client callback table * @client : Client session * @kernel_cb : Kernel callback payload * @user_cb : Userspace callback payload * @node : List member used to append this node to event list */ struct synx_client_cb { bool is_valid; u32 idx; struct synx_client *client; struct synx_kernel_payload kernel_cb; struct synx_user_payload user_cb; struct list_head node; }; Loading
drivers/media/platform/msm/synx/synx_util.c +71 −24 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "synx: " fmt Loading Loading @@ -623,13 +623,14 @@ struct bind_operations *synx_util_get_bind_ops(u32 type) } int synx_util_alloc_cb_entry(struct synx_client *client, struct synx_kernel_payload *data, u32 *cb_idx) { bool bit; long idx; struct synx_client_cb *cb; if (!client || !cb_idx) if (!client || !data || !cb_idx) return -EINVAL; do { Loading @@ -644,28 +645,53 @@ int synx_util_alloc_cb_entry(struct synx_client *client, cb = &client->cb_table[idx]; memset(cb, 0, sizeof(*cb)); cb->is_valid = true; cb->client = client; cb->idx = idx; memcpy(&cb->kernel_cb, data, sizeof(cb->kernel_cb)); *cb_idx = idx; pr_debug("[sess: %u] allocated cb index %u\n", client->id, idx); pr_debug("[sess: %u] allocated cb index %u\n", client->id, *cb_idx); return 0; } int synx_util_update_cb_entry(struct synx_client *client, void *data, u32 cb_idx) int synx_util_clear_cb_entry(struct synx_client *client, struct synx_client_cb *cb) { struct synx_client_cb *cb; int rc = 0; u32 idx; if (!client || !data || (cb_idx >= SYNX_MAX_OBJS)) if (!cb) return -EINVAL; cb = &client->cb_table[cb_idx]; cb->is_valid = true; memcpy(&cb->kernel_cb, data, sizeof(cb->kernel_cb)); idx = cb->idx; memset(cb, 0, sizeof(*cb)); if (idx && idx < SYNX_MAX_OBJS) { clear_bit(idx, client->cb_bitmap); } else { pr_err("%s: found invalid index\n", __func__); rc = -EINVAL; } pr_debug("[sess: %u] updated cb index %u\n", client->id, cb_idx); return 0; return rc; } void synx_util_default_user_callback(s32 h_synx, int status, void *data) { struct synx_client_cb *cb = data; if (cb && cb->client) { pr_debug("user cb queued for handle %d\n", h_synx); cb->kernel_cb.status = status; mutex_lock(&cb->client->event_q_lock); list_add_tail(&cb->node, &cb->client->event_q); mutex_unlock(&cb->client->event_q_lock); wake_up_all(&cb->client->event_wq); } else { pr_err("%s: invalid params\n", __func__); } } void synx_util_callback_dispatch(struct synx_coredata *synx_obj, u32 status) Loading Loading @@ -693,7 +719,8 @@ void synx_util_cb_dispatch(struct work_struct *cb_dispatch) container_of(cb_dispatch, struct synx_cb_data, cb_dispatch); struct synx_client *client; struct synx_client_cb *cb; struct synx_kernel_payload *payload; struct synx_kernel_payload payload; u32 status; client = synx_get_client(synx_cb->session_id); if (!client) { Loading @@ -702,26 +729,46 @@ void synx_util_cb_dispatch(struct work_struct *cb_dispatch) goto free; } if (synx_cb->idx >= SYNX_MAX_OBJS) { pr_err("[sess: %u] invalid cb index\n", client->id); if (synx_cb->idx == 0 || synx_cb->idx >= SYNX_MAX_OBJS) { pr_err("[sess: %u] invalid cb index %u\n", client->id, synx_cb->idx); goto fail; } status = synx_cb->status; cb = &client->cb_table[synx_cb->idx]; if (!cb->is_valid) { pr_err("invalid cb payload\n"); goto fail; } payload = &cb->kernel_cb; memcpy(&payload, &cb->kernel_cb, sizeof(cb->kernel_cb)); payload.status = status; if (payload.cb_func == synx_util_default_user_callback) { /* * need to send client cb data for default * user cb (userspace cb) */ payload.data = cb; } else { /* * clear the cb entry. userspace cb entry * will be cleared after data read by the * polling thread or when client is destroyed */ if (synx_util_clear_cb_entry(client, cb)) pr_err("%s: [sess: %u] error clearing cb entry\n", __func__, client->id); } pr_debug("[sess: %u] kernel cb dispatch for handle %d\n", client->id, payload->h_synx); client->id, payload.h_synx); /* dispatch kernel callback */ payload->cb_func(payload->h_synx, synx_cb->status, payload->data); payload.cb_func(payload.h_synx, payload.status, payload.data); fail: synx_put_client(client); Loading Loading @@ -926,7 +973,7 @@ static void synx_client_destroy(struct kref *kref) memset(client_metadata, 0, sizeof(*client_metadata)); clear_bit(client->id, synx_dev->bitmap); pr_debug("[sess: %u] session destroyed %s\n", pr_info("[sess: %u] session destroyed %s\n", client->id, client->name); kfree(client); } Loading
drivers/media/platform/msm/synx/synx_util.h +16 −7 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef __SYNX_UTIL_H__ Loading Loading @@ -112,25 +112,25 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj); * @brief: Function to allocate synx_client_cb entry from cb table * * @param client : Pointer to client session info * @param data : Kernel payload data * @param cb_idx : Allocated index (filled by function) * * @return Status of operation. Negative in case of error. Zero otherwise. */ int synx_util_alloc_cb_entry(struct synx_client *client, struct synx_kernel_payload *data, u32 *cb_idx); /** * @brief: Function to allocate synx_client_cb entry from cb table * @brief: Function to clean up synx_client_cb entry from cb table * * @param client : Pointer to client session info * @param data : Opaque payload data * @param cb_idx : Callback table index * @param cb : Pointer to client cb entry * * @return Status of operation. Negative in case of error. Zero otherwise. */ int synx_util_update_cb_entry(struct synx_client *client, void *data, u32 cb_idx); int synx_util_clear_cb_entry(struct synx_client *client, struct synx_client_cb *cb); /** * @brief: Function to initialize synx object handle for the client Loading @@ -155,6 +155,15 @@ int synx_util_init_handle(struct synx_client *client, */ int synx_util_activate(struct synx_coredata *synx_obj); /** * @brief: Default kernel callback function to handle userspace callbacks * * @param h_synx : Synx object handle * @param status : Synx object state * @param data : Opaque pointer */ void synx_util_default_user_callback(s32 h_synx, int status, void *data); /** * @brief: Function to queue all the registered callbacks by clients for * the synx object Loading