Loading drivers/misc/qseecom.c +310 −67 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ #define RPMB_SERVICE 0x2000 #define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000 #define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000 enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, Loading Loading @@ -162,6 +165,12 @@ struct qseecom_control { uint32_t qsee_perf_client; struct qseecom_clk qsee; struct qseecom_clk ce_drv; bool support_bus_scaling; uint32_t cumulative_mode; enum qseecom_bandwidth_request_mode current_mode; struct timer_list bw_scale_down_timer; struct work_struct bw_inactive_req_ws; }; struct qseecom_client_handle { Loading Loading @@ -191,6 +200,7 @@ struct qseecom_dev_handle { atomic_t ioctl_count; bool perf_enabled; bool fast_load_enabled; enum qseecom_bandwidth_request_mode mode; }; enum qseecom_set_clear_key_flag { Loading Loading @@ -314,6 +324,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, return ret; } data->listener.id = 0; data->type = QSEECOM_LISTENER_SERVICE; if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) { pr_err("Service is not unique and is already registered\n"); data->released = true; Loading Loading @@ -422,6 +433,153 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) return ret; } static int __qseecom_set_msm_bus_request(uint32_t mode) { int ret = 0; struct qseecom_clk *qclk; qclk = &qseecom.qsee; if (qclk->ce_core_src_clk != NULL) { if (mode == INACTIVE) { __qseecom_disable_clk(CLK_QSEE); } else { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) pr_err("CLK enabling failed (%d) MODE (%d)\n", ret, mode); } } if ((!ret) && (qseecom.current_mode != mode)) { ret = msm_bus_scale_client_update_request( qseecom.qsee_perf_client, mode); if (ret) { pr_err("Bandwidth req failed(%d) MODE (%d)\n", ret, mode); if (qclk->ce_core_src_clk != NULL) { if (mode == INACTIVE) __qseecom_enable_clk(CLK_QSEE); else __qseecom_disable_clk(CLK_QSEE); } } qseecom.current_mode = mode; } return ret; } static void qseecom_bw_inactive_req_work(struct work_struct *work) { mutex_lock(&app_access_lock); mutex_lock(&qsee_bw_mutex); __qseecom_set_msm_bus_request(INACTIVE); pr_debug("current_mode = %d, cumulative_mode = %d\n", qseecom.current_mode, qseecom.cumulative_mode); mutex_unlock(&qsee_bw_mutex); mutex_unlock(&app_access_lock); return; } static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data) { schedule_work(&qseecom.bw_inactive_req_ws); return; } static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration) { int32_t ret = 0; int32_t request_mode = INACTIVE; mutex_lock(&qsee_bw_mutex); if (mode == 0) { if (qseecom.cumulative_mode > MEDIUM) request_mode = HIGH; else request_mode = qseecom.cumulative_mode; } else { request_mode = mode; } __qseecom_set_msm_bus_request(request_mode); del_timer_sync(&(qseecom.bw_scale_down_timer)); qseecom.bw_scale_down_timer.expires = jiffies + msecs_to_jiffies(duration); add_timer(&(qseecom.bw_scale_down_timer)); mutex_unlock(&qsee_bw_mutex); return ret; } static int qseecom_unregister_bus_bandwidth_needs( struct qseecom_dev_handle *data) { int32_t ret = 0; qseecom.cumulative_mode -= data->mode; data->mode = INACTIVE; return ret; } static int __qseecom_register_bus_bandwidth_needs( struct qseecom_dev_handle *data, uint32_t request_mode) { int32_t ret = 0; if (data->mode == INACTIVE) { qseecom.cumulative_mode += request_mode; data->mode = request_mode; } else { if (data->mode != request_mode) { qseecom.cumulative_mode -= data->mode; qseecom.cumulative_mode += request_mode; data->mode = request_mode; } } return ret; } static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data, void __user *argp) { int32_t ret = 0; int32_t req_mode; ret = copy_from_user(&req_mode, argp, sizeof(req_mode)); if (ret) { pr_err("copy_from_user failed\n"); return ret; } mutex_lock(&qsee_bw_mutex); ret = __qseecom_register_bus_bandwidth_needs(data, req_mode); mutex_unlock(&qsee_bw_mutex); return ret; } static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data) { if (!qseecom.support_bus_scaling) qsee_disable_clock_vote(data, CLK_SFPB); return; } static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data) { int ret = 0; if (qseecom.support_bus_scaling) { qseecom_scale_bus_bandwidth_timer( MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT); } else { ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) pr_err("Fail vote for clk SFPB ret %d\n", ret); } return ret; } static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, void __user *argp) { Loading Loading @@ -596,7 +754,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) u32 app_id = 0; struct ion_handle *ihandle; /* Ion handle */ struct qseecom_load_img_req load_img_req; int32_t ret; int32_t ret = 0; ion_phys_addr_t pa = 0; uint32_t len; struct qseecom_command_scm_resp resp; Loading @@ -611,15 +769,15 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) return -EFAULT; } /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) pr_warning("Unable to vote for SFPB clock"); return ret; req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE); ret = __qseecom_check_app_exists(req); if (ret < 0) { qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading @@ -645,7 +803,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) load_img_req.ifd_data_fd); if (IS_ERR_OR_NULL(ihandle)) { pr_err("Ion client could not retrieve the handle\n"); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -ENOMEM; } Loading @@ -670,7 +828,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) pr_err("scm_call to load app failed\n"); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EINVAL; } Loading @@ -678,7 +836,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n"); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } Loading @@ -689,7 +847,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) ret); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } } Loading @@ -699,7 +857,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) resp.result); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } Loading @@ -708,7 +866,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { pr_err("kmalloc failed\n"); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -ENOMEM; } entry->app_id = app_id; Loading @@ -731,10 +889,10 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) { pr_err("copy_to_user failed\n"); kzfree(entry); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return 0; } Loading Loading @@ -887,6 +1045,8 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } data->type = QSEECOM_SECURE_SERVICE; switch (req.cmd_id) { case QSEOS_RPMB_PROVISION_KEY_COMMAND: case QSEOS_RPMB_ERASE_COMMAND: Loading @@ -899,6 +1059,14 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } if (qseecom.support_bus_scaling) { qseecom_scale_bus_bandwidth_timer(HIGH, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); if (ret) { pr_err("Fail to set bw HIGH%d\n", ret); return ret; } } else { ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) { pr_err("Failed to vote for DFAB clock%d\n", ret); Loading @@ -906,8 +1074,10 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, } ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) { qsee_disable_clock_vote(data, CLK_DFAB); pr_err("Failed to vote for SFPB clock%d\n", ret); goto exit_reset_dfab_freq; goto exit; } } msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, Loading @@ -921,7 +1091,11 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, ION_IOC_INV_CACHES); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); goto exit_reset_sdfab_freq; if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(data, CLK_DFAB); qsee_disable_clock_vote(data, CLK_SFPB); } goto exit; } switch (resp.result) { Loading @@ -944,10 +1118,7 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, ret = -EINVAL; break; } exit_reset_sdfab_freq: qsee_disable_clock_vote(data, CLK_SFPB); exit_reset_dfab_freq: qsee_disable_clock_vote(data, CLK_DFAB); exit: return ret; } Loading Loading @@ -1403,10 +1574,9 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) /* Populate the remaining parameters */ load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND; memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE); ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { kzfree(img_data); pr_warning("Unable to vote for SFPB clock"); return -EIO; } Loading @@ -1418,7 +1588,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) kzfree(img_data); if (ret) { pr_err("scm_call to load failed : ret %d\n", ret); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EIO; } Loading @@ -1441,7 +1611,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) ret = -EINVAL; break; } qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading Loading @@ -1470,9 +1640,8 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data) /* Populate the remaining parameters */ load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND; /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { pr_err("Unable to vote for SFPB clock: ret = %d", ret); kzfree(img_data); return -EIO; } Loading Loading @@ -1508,7 +1677,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data) } } kzfree(img_data); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading Loading @@ -1718,10 +1887,24 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) pr_err("Unable to find the handle, exiting\n"); else ret = qseecom_unload_app(data); if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); if (data->mode != INACTIVE) { qseecom_unregister_bus_bandwidth_needs(data); if (qseecom.cumulative_mode == INACTIVE) { ret = __qseecom_set_msm_bus_request(INACTIVE); if (ret) pr_err("Fail to scale down bus\n"); } } mutex_unlock(&qsee_bw_mutex); } else { if (data->fast_load_enabled == true) qsee_disable_clock_vote(data, CLK_SFPB); if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } if (ret == 0) { kzfree(data); kzfree(*handle); Loading Loading @@ -1752,7 +1935,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); ret = __qseecom_send_cmd(data, &req); atomic_dec(&data->ioctl_count); Loading @@ -1775,18 +1960,31 @@ int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high) return -EINVAL; } if (high) { if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); __qseecom_register_bus_bandwidth_needs(handle->dev, HIGH); mutex_unlock(&qsee_bw_mutex); if (ret) pr_err("Failed to scale bus (med) %d\n", ret); } else { ret = qsee_vote_for_clock(handle->dev, CLK_DFAB); if (ret) pr_err("Failed to vote for DFAB clock%d\n", ret); pr_err("Failed to vote for DFAB clock%d\n", ret); ret = qsee_vote_for_clock(handle->dev, CLK_SFPB); if (ret) { pr_err("Failed to vote for SFPB clock%d\n", ret); pr_err("Failed to vote for SFPB clock%d\n", ret); qsee_disable_clock_vote(handle->dev, CLK_DFAB); } } } else { if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(handle->dev, CLK_DFAB); qsee_disable_clock_vote(handle->dev, CLK_SFPB); } } return ret; } EXPORT_SYMBOL(qseecom_set_bandwidth); Loading Loading @@ -2121,9 +2319,8 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, } /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { pr_err("Unable to vote for SFPB clock: ret = %d", ret); ret = -EIO; goto exit_cpu_restore; } Loading Loading @@ -2161,7 +2358,7 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, } exit_disable_clock: qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); exit_cpu_restore: /* Restore the CPU mask */ mask = CPU_MASK_ALL; Loading Loading @@ -2700,6 +2897,9 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, case QSEECOM_IOCTL_SEND_CMD_REQ: { /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); atomic_inc(&data->ioctl_count); ret = qseecom_send_cmd(data, argp); atomic_dec(&data->ioctl_count); Loading @@ -2712,6 +2912,9 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: { /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); atomic_inc(&data->ioctl_count); ret = qseecom_send_modfd_cmd(data, argp); atomic_dec(&data->ioctl_count); Loading Loading @@ -2789,19 +2992,34 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, } case QSEECOM_IOCTL_PERF_ENABLE_REQ:{ atomic_inc(&data->ioctl_count); if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); __qseecom_register_bus_bandwidth_needs(data, HIGH); mutex_unlock(&qsee_bw_mutex); } else { ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) pr_err("Failed to vote for DFAB clock%d\n", ret); pr_err("Fail to vote for DFAB clock%d\n", ret); ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) pr_err("Failed to vote for SFPB clock%d\n", ret); pr_err("Fail to vote for SFPB clock%d\n", ret); } atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_PERF_DISABLE_REQ:{ atomic_inc(&data->ioctl_count); if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(data, CLK_DFAB); qsee_disable_clock_vote(data, CLK_SFPB); } atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: { atomic_inc(&data->ioctl_count); ret = qseecom_scale_bus_bandwidth(data, argp); atomic_dec(&data->ioctl_count); break; } Loading Loading @@ -2943,6 +3161,7 @@ static int qseecom_open(struct inode *inode, struct file *file) data->abort = 0; data->type = QSEECOM_GENERIC; data->released = false; data->mode = INACTIVE; init_waitqueue_head(&data->abort_wq); atomic_set(&data->ioctl_count, 0); Loading @@ -2955,8 +3174,8 @@ static int qseecom_release(struct inode *inode, struct file *file) int ret = 0; if (data->released == false) { pr_warn("data: released = false, type = %d, data = 0x%x\n", data->type, (u32)data); pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n", data->type, data->mode, (u32)data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: ret = qseecom_unregister_listener(data); Loading @@ -2979,11 +3198,23 @@ static int qseecom_release(struct inode *inode, struct file *file) } } if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); if (data->mode != INACTIVE) { qseecom_unregister_bus_bandwidth_needs(data); if (qseecom.cumulative_mode == INACTIVE) { ret = __qseecom_set_msm_bus_request(INACTIVE); if (ret) pr_err("Fail to scale down bus\n"); } } mutex_unlock(&qsee_bw_mutex); } else { if (data->fast_load_enabled == true) qsee_disable_clock_vote(data, CLK_SFPB); if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } kfree(data); return ret; Loading Loading @@ -3126,6 +3357,10 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee.ce_core_src_clk = NULL; qseecom.qsee.ce_bus_clk = NULL; qseecom.cumulative_mode = 0; qseecom.current_mode = INACTIVE; qseecom.support_bus_scaling = false; qseecom.ce_drv.ce_core_clk = NULL; qseecom.ce_drv.ce_clk = NULL; qseecom.ce_drv.ce_core_src_clk = NULL; Loading Loading @@ -3205,7 +3440,9 @@ static int qseecom_probe(struct platform_device *pdev) /* register client for bus scaling */ if (pdev->dev.of_node) { qseecom.support_bus_scaling = of_property_read_bool((&pdev->dev)->of_node, "qcom,support-bus-scaling"); if (of_property_read_u32((&pdev->dev)->of_node, "qcom,disk-encrypt-pipe-pair", &qseecom.ce_info.disk_encrypt_pipe)) { Loading Loading @@ -3298,7 +3535,13 @@ static int qseecom_probe(struct platform_device *pdev) qseecom_platform_support = (struct msm_bus_scale_pdata *) pdev->dev.platform_data; } if (qseecom.support_bus_scaling) { init_timer(&(qseecom.bw_scale_down_timer)); INIT_WORK(&qseecom.bw_inactive_req_ws, qseecom_bw_inactive_req_work); qseecom.bw_scale_down_timer.function = qseecom_scale_bus_bandwidth_timer_callback; } qseecom.qsee_perf_client = msm_bus_scale_register_client( qseecom_platform_support); Loading include/uapi/linux/qseecom.h +11 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,13 @@ enum qseecom_buffer_protection { QSEOS_UNPROTECT_PROTECTED_BUFFER, }; enum qseecom_bandwidth_request_mode { INACTIVE = 0, LOW, MEDIUM, HIGH, }; /* * struct qseecom_send_modfd_resp - for send command ioctl request * @req_len - command buffer length Loading Loading @@ -247,4 +254,8 @@ struct qseecom_send_modfd_listener_resp { #define QSEECOM_IOCTL_UNPROTECT_BUF \ _IOWR(QSEECOM_IOC_MAGIC, 22, int) #define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 23, int) #endif /* _UAPI_QSEECOM_H_ */ Loading
drivers/misc/qseecom.c +310 −67 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ #define RPMB_SERVICE 0x2000 #define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000 #define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000 enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, Loading Loading @@ -162,6 +165,12 @@ struct qseecom_control { uint32_t qsee_perf_client; struct qseecom_clk qsee; struct qseecom_clk ce_drv; bool support_bus_scaling; uint32_t cumulative_mode; enum qseecom_bandwidth_request_mode current_mode; struct timer_list bw_scale_down_timer; struct work_struct bw_inactive_req_ws; }; struct qseecom_client_handle { Loading Loading @@ -191,6 +200,7 @@ struct qseecom_dev_handle { atomic_t ioctl_count; bool perf_enabled; bool fast_load_enabled; enum qseecom_bandwidth_request_mode mode; }; enum qseecom_set_clear_key_flag { Loading Loading @@ -314,6 +324,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, return ret; } data->listener.id = 0; data->type = QSEECOM_LISTENER_SERVICE; if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) { pr_err("Service is not unique and is already registered\n"); data->released = true; Loading Loading @@ -422,6 +433,153 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) return ret; } static int __qseecom_set_msm_bus_request(uint32_t mode) { int ret = 0; struct qseecom_clk *qclk; qclk = &qseecom.qsee; if (qclk->ce_core_src_clk != NULL) { if (mode == INACTIVE) { __qseecom_disable_clk(CLK_QSEE); } else { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) pr_err("CLK enabling failed (%d) MODE (%d)\n", ret, mode); } } if ((!ret) && (qseecom.current_mode != mode)) { ret = msm_bus_scale_client_update_request( qseecom.qsee_perf_client, mode); if (ret) { pr_err("Bandwidth req failed(%d) MODE (%d)\n", ret, mode); if (qclk->ce_core_src_clk != NULL) { if (mode == INACTIVE) __qseecom_enable_clk(CLK_QSEE); else __qseecom_disable_clk(CLK_QSEE); } } qseecom.current_mode = mode; } return ret; } static void qseecom_bw_inactive_req_work(struct work_struct *work) { mutex_lock(&app_access_lock); mutex_lock(&qsee_bw_mutex); __qseecom_set_msm_bus_request(INACTIVE); pr_debug("current_mode = %d, cumulative_mode = %d\n", qseecom.current_mode, qseecom.cumulative_mode); mutex_unlock(&qsee_bw_mutex); mutex_unlock(&app_access_lock); return; } static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data) { schedule_work(&qseecom.bw_inactive_req_ws); return; } static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration) { int32_t ret = 0; int32_t request_mode = INACTIVE; mutex_lock(&qsee_bw_mutex); if (mode == 0) { if (qseecom.cumulative_mode > MEDIUM) request_mode = HIGH; else request_mode = qseecom.cumulative_mode; } else { request_mode = mode; } __qseecom_set_msm_bus_request(request_mode); del_timer_sync(&(qseecom.bw_scale_down_timer)); qseecom.bw_scale_down_timer.expires = jiffies + msecs_to_jiffies(duration); add_timer(&(qseecom.bw_scale_down_timer)); mutex_unlock(&qsee_bw_mutex); return ret; } static int qseecom_unregister_bus_bandwidth_needs( struct qseecom_dev_handle *data) { int32_t ret = 0; qseecom.cumulative_mode -= data->mode; data->mode = INACTIVE; return ret; } static int __qseecom_register_bus_bandwidth_needs( struct qseecom_dev_handle *data, uint32_t request_mode) { int32_t ret = 0; if (data->mode == INACTIVE) { qseecom.cumulative_mode += request_mode; data->mode = request_mode; } else { if (data->mode != request_mode) { qseecom.cumulative_mode -= data->mode; qseecom.cumulative_mode += request_mode; data->mode = request_mode; } } return ret; } static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data, void __user *argp) { int32_t ret = 0; int32_t req_mode; ret = copy_from_user(&req_mode, argp, sizeof(req_mode)); if (ret) { pr_err("copy_from_user failed\n"); return ret; } mutex_lock(&qsee_bw_mutex); ret = __qseecom_register_bus_bandwidth_needs(data, req_mode); mutex_unlock(&qsee_bw_mutex); return ret; } static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data) { if (!qseecom.support_bus_scaling) qsee_disable_clock_vote(data, CLK_SFPB); return; } static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data) { int ret = 0; if (qseecom.support_bus_scaling) { qseecom_scale_bus_bandwidth_timer( MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT); } else { ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) pr_err("Fail vote for clk SFPB ret %d\n", ret); } return ret; } static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, void __user *argp) { Loading Loading @@ -596,7 +754,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) u32 app_id = 0; struct ion_handle *ihandle; /* Ion handle */ struct qseecom_load_img_req load_img_req; int32_t ret; int32_t ret = 0; ion_phys_addr_t pa = 0; uint32_t len; struct qseecom_command_scm_resp resp; Loading @@ -611,15 +769,15 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) return -EFAULT; } /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) pr_warning("Unable to vote for SFPB clock"); return ret; req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE); ret = __qseecom_check_app_exists(req); if (ret < 0) { qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading @@ -645,7 +803,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) load_img_req.ifd_data_fd); if (IS_ERR_OR_NULL(ihandle)) { pr_err("Ion client could not retrieve the handle\n"); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -ENOMEM; } Loading @@ -670,7 +828,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) pr_err("scm_call to load app failed\n"); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EINVAL; } Loading @@ -678,7 +836,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n"); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } Loading @@ -689,7 +847,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) ret); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } } Loading @@ -699,7 +857,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) resp.result); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } Loading @@ -708,7 +866,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { pr_err("kmalloc failed\n"); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -ENOMEM; } entry->app_id = app_id; Loading @@ -731,10 +889,10 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) { pr_err("copy_to_user failed\n"); kzfree(entry); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EFAULT; } qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return 0; } Loading Loading @@ -887,6 +1045,8 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } data->type = QSEECOM_SECURE_SERVICE; switch (req.cmd_id) { case QSEOS_RPMB_PROVISION_KEY_COMMAND: case QSEOS_RPMB_ERASE_COMMAND: Loading @@ -899,6 +1059,14 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } if (qseecom.support_bus_scaling) { qseecom_scale_bus_bandwidth_timer(HIGH, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); if (ret) { pr_err("Fail to set bw HIGH%d\n", ret); return ret; } } else { ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) { pr_err("Failed to vote for DFAB clock%d\n", ret); Loading @@ -906,8 +1074,10 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, } ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) { qsee_disable_clock_vote(data, CLK_DFAB); pr_err("Failed to vote for SFPB clock%d\n", ret); goto exit_reset_dfab_freq; goto exit; } } msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, Loading @@ -921,7 +1091,11 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, ION_IOC_INV_CACHES); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); goto exit_reset_sdfab_freq; if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(data, CLK_DFAB); qsee_disable_clock_vote(data, CLK_SFPB); } goto exit; } switch (resp.result) { Loading @@ -944,10 +1118,7 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, ret = -EINVAL; break; } exit_reset_sdfab_freq: qsee_disable_clock_vote(data, CLK_SFPB); exit_reset_dfab_freq: qsee_disable_clock_vote(data, CLK_DFAB); exit: return ret; } Loading Loading @@ -1403,10 +1574,9 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) /* Populate the remaining parameters */ load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND; memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE); ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { kzfree(img_data); pr_warning("Unable to vote for SFPB clock"); return -EIO; } Loading @@ -1418,7 +1588,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) kzfree(img_data); if (ret) { pr_err("scm_call to load failed : ret %d\n", ret); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return -EIO; } Loading @@ -1441,7 +1611,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) ret = -EINVAL; break; } qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading Loading @@ -1470,9 +1640,8 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data) /* Populate the remaining parameters */ load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND; /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { pr_err("Unable to vote for SFPB clock: ret = %d", ret); kzfree(img_data); return -EIO; } Loading Loading @@ -1508,7 +1677,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data) } } kzfree(img_data); qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); return ret; } Loading Loading @@ -1718,10 +1887,24 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) pr_err("Unable to find the handle, exiting\n"); else ret = qseecom_unload_app(data); if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); if (data->mode != INACTIVE) { qseecom_unregister_bus_bandwidth_needs(data); if (qseecom.cumulative_mode == INACTIVE) { ret = __qseecom_set_msm_bus_request(INACTIVE); if (ret) pr_err("Fail to scale down bus\n"); } } mutex_unlock(&qsee_bw_mutex); } else { if (data->fast_load_enabled == true) qsee_disable_clock_vote(data, CLK_SFPB); if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } if (ret == 0) { kzfree(data); kzfree(*handle); Loading Loading @@ -1752,7 +1935,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); ret = __qseecom_send_cmd(data, &req); atomic_dec(&data->ioctl_count); Loading @@ -1775,18 +1960,31 @@ int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high) return -EINVAL; } if (high) { if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); __qseecom_register_bus_bandwidth_needs(handle->dev, HIGH); mutex_unlock(&qsee_bw_mutex); if (ret) pr_err("Failed to scale bus (med) %d\n", ret); } else { ret = qsee_vote_for_clock(handle->dev, CLK_DFAB); if (ret) pr_err("Failed to vote for DFAB clock%d\n", ret); pr_err("Failed to vote for DFAB clock%d\n", ret); ret = qsee_vote_for_clock(handle->dev, CLK_SFPB); if (ret) { pr_err("Failed to vote for SFPB clock%d\n", ret); pr_err("Failed to vote for SFPB clock%d\n", ret); qsee_disable_clock_vote(handle->dev, CLK_DFAB); } } } else { if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(handle->dev, CLK_DFAB); qsee_disable_clock_vote(handle->dev, CLK_SFPB); } } return ret; } EXPORT_SYMBOL(qseecom_set_bandwidth); Loading Loading @@ -2121,9 +2319,8 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, } /* Vote for the SFPB clock */ ret = qsee_vote_for_clock(data, CLK_SFPB); ret = __qseecom_enable_clk_scale_up(data); if (ret) { pr_err("Unable to vote for SFPB clock: ret = %d", ret); ret = -EIO; goto exit_cpu_restore; } Loading Loading @@ -2161,7 +2358,7 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, } exit_disable_clock: qsee_disable_clock_vote(data, CLK_SFPB); __qseecom_disable_clk_scale_down(data); exit_cpu_restore: /* Restore the CPU mask */ mask = CPU_MASK_ALL; Loading Loading @@ -2700,6 +2897,9 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, case QSEECOM_IOCTL_SEND_CMD_REQ: { /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); atomic_inc(&data->ioctl_count); ret = qseecom_send_cmd(data, argp); atomic_dec(&data->ioctl_count); Loading @@ -2712,6 +2912,9 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: { /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); if (qseecom.support_bus_scaling) qseecom_scale_bus_bandwidth_timer(INACTIVE, QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); atomic_inc(&data->ioctl_count); ret = qseecom_send_modfd_cmd(data, argp); atomic_dec(&data->ioctl_count); Loading Loading @@ -2789,19 +2992,34 @@ static long qseecom_ioctl(struct file *file, unsigned cmd, } case QSEECOM_IOCTL_PERF_ENABLE_REQ:{ atomic_inc(&data->ioctl_count); if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); __qseecom_register_bus_bandwidth_needs(data, HIGH); mutex_unlock(&qsee_bw_mutex); } else { ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) pr_err("Failed to vote for DFAB clock%d\n", ret); pr_err("Fail to vote for DFAB clock%d\n", ret); ret = qsee_vote_for_clock(data, CLK_SFPB); if (ret) pr_err("Failed to vote for SFPB clock%d\n", ret); pr_err("Fail to vote for SFPB clock%d\n", ret); } atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_PERF_DISABLE_REQ:{ atomic_inc(&data->ioctl_count); if (!qseecom.support_bus_scaling) { qsee_disable_clock_vote(data, CLK_DFAB); qsee_disable_clock_vote(data, CLK_SFPB); } atomic_dec(&data->ioctl_count); break; } case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: { atomic_inc(&data->ioctl_count); ret = qseecom_scale_bus_bandwidth(data, argp); atomic_dec(&data->ioctl_count); break; } Loading Loading @@ -2943,6 +3161,7 @@ static int qseecom_open(struct inode *inode, struct file *file) data->abort = 0; data->type = QSEECOM_GENERIC; data->released = false; data->mode = INACTIVE; init_waitqueue_head(&data->abort_wq); atomic_set(&data->ioctl_count, 0); Loading @@ -2955,8 +3174,8 @@ static int qseecom_release(struct inode *inode, struct file *file) int ret = 0; if (data->released == false) { pr_warn("data: released = false, type = %d, data = 0x%x\n", data->type, (u32)data); pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n", data->type, data->mode, (u32)data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: ret = qseecom_unregister_listener(data); Loading @@ -2979,11 +3198,23 @@ static int qseecom_release(struct inode *inode, struct file *file) } } if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); if (data->mode != INACTIVE) { qseecom_unregister_bus_bandwidth_needs(data); if (qseecom.cumulative_mode == INACTIVE) { ret = __qseecom_set_msm_bus_request(INACTIVE); if (ret) pr_err("Fail to scale down bus\n"); } } mutex_unlock(&qsee_bw_mutex); } else { if (data->fast_load_enabled == true) qsee_disable_clock_vote(data, CLK_SFPB); if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } kfree(data); return ret; Loading Loading @@ -3126,6 +3357,10 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee.ce_core_src_clk = NULL; qseecom.qsee.ce_bus_clk = NULL; qseecom.cumulative_mode = 0; qseecom.current_mode = INACTIVE; qseecom.support_bus_scaling = false; qseecom.ce_drv.ce_core_clk = NULL; qseecom.ce_drv.ce_clk = NULL; qseecom.ce_drv.ce_core_src_clk = NULL; Loading Loading @@ -3205,7 +3440,9 @@ static int qseecom_probe(struct platform_device *pdev) /* register client for bus scaling */ if (pdev->dev.of_node) { qseecom.support_bus_scaling = of_property_read_bool((&pdev->dev)->of_node, "qcom,support-bus-scaling"); if (of_property_read_u32((&pdev->dev)->of_node, "qcom,disk-encrypt-pipe-pair", &qseecom.ce_info.disk_encrypt_pipe)) { Loading Loading @@ -3298,7 +3535,13 @@ static int qseecom_probe(struct platform_device *pdev) qseecom_platform_support = (struct msm_bus_scale_pdata *) pdev->dev.platform_data; } if (qseecom.support_bus_scaling) { init_timer(&(qseecom.bw_scale_down_timer)); INIT_WORK(&qseecom.bw_inactive_req_ws, qseecom_bw_inactive_req_work); qseecom.bw_scale_down_timer.function = qseecom_scale_bus_bandwidth_timer_callback; } qseecom.qsee_perf_client = msm_bus_scale_register_client( qseecom_platform_support); Loading
include/uapi/linux/qseecom.h +11 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,13 @@ enum qseecom_buffer_protection { QSEOS_UNPROTECT_PROTECTED_BUFFER, }; enum qseecom_bandwidth_request_mode { INACTIVE = 0, LOW, MEDIUM, HIGH, }; /* * struct qseecom_send_modfd_resp - for send command ioctl request * @req_len - command buffer length Loading Loading @@ -247,4 +254,8 @@ struct qseecom_send_modfd_listener_resp { #define QSEECOM_IOCTL_UNPROTECT_BUF \ _IOWR(QSEECOM_IOC_MAGIC, 22, int) #define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \ _IOWR(QSEECOM_IOC_MAGIC, 23, int) #endif /* _UAPI_QSEECOM_H_ */