Loading drivers/video/msm/mdss/mdss_rotator.c +145 −56 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "mdss_rotator_internal.h" #include "mdss_mdp.h" #include "mdss_debug.h" /* waiting for hw time out, 3 vsync for 30fps*/ #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100 Loading Loading @@ -72,6 +73,7 @@ static int mdss_rotator_bus_scale_set_quota(struct mdss_rot_bus_data_type *bus, u64 quota) { int new_uc_idx; int ret; if (bus->bus_hdl < 1) { pr_err("invalid bus handle %d\n", bus->bus_hdl); Loading Loading @@ -113,8 +115,13 @@ static int mdss_rotator_bus_scale_set_quota(struct mdss_rot_bus_data_type *bus, bus->curr_quota_val = quota; pr_debug("uc_idx=%d quota=%llu\n", new_uc_idx, quota); return msm_bus_scale_client_update_request(bus->bus_hdl, MDSS_XLOG(new_uc_idx, ((quota >> 32) & 0xFFFFFFFF), (quota & 0xFFFFFFFF)); ATRACE_BEGIN("msm_bus_scale_req_rot"); ret = msm_bus_scale_client_update_request(bus->bus_hdl, new_uc_idx); ATRACE_END("msm_bus_scale_req_rot"); return ret; } static int mdss_rotator_enable_reg_bus(struct mdss_rot_mgr *mgr, u64 quota) Loading @@ -136,9 +143,12 @@ static int mdss_rotator_enable_reg_bus(struct mdss_rot_mgr *mgr, u64 quota) pr_debug("%s, changed=%d register bus %s\n", __func__, changed, quota ? "Enable":"Disable"); if (changed) if (changed) { ATRACE_BEGIN("msm_bus_scale_req_rot_reg"); ret = msm_bus_scale_client_update_request(mgr->reg_bus.bus_hdl, usecase_ndx); ATRACE_END("msm_bus_scale_req_rot_reg"); } return ret; } Loading @@ -160,12 +170,13 @@ static unsigned long mdss_rotator_clk_rate_calc( mutex_lock(&private->perf_lock); list_for_each_entry(perf, &private->perf_list, list) { bool rate_accounted_for = false; mutex_lock(&perf->work_dis_lock); /* * If there is one session that has two work items across * different hw blocks rate is accounted for in both blocks. */ for (i = 0; i < mgr->queue_count; i++) { if (atomic_read(&perf->work_distribution[i])) { if (perf->work_distribution[i]) { clk_rate[i] += perf->clk_rate; rate_accounted_for = true; } Loading @@ -180,6 +191,7 @@ static unsigned long mdss_rotator_clk_rate_calc( if ((!rate_accounted_for) && (wb_idx >= 0) && (wb_idx < mgr->queue_count)) clk_rate[wb_idx] += perf->clk_rate; mutex_unlock(&perf->work_dis_lock); } mutex_unlock(&private->perf_lock); Loading Loading @@ -214,10 +226,12 @@ static void mdss_rotator_set_clk_rate(struct mdss_rot_mgr *mgr, pr_err("unable to round rate err=%ld\n", clk_rate); } else if (clk_rate != clk_get_rate(clk)) { ret = clk_set_rate(clk, clk_rate); if (IS_ERR_VALUE(ret)) if (IS_ERR_VALUE(ret)) { pr_err("clk_set_rate failed, err:%d\n", ret); else } else { pr_debug("rotator clk rate=%lu\n", clk_rate); MDSS_XLOG(clk_rate); } } mutex_unlock(&mgr->clk_lock); } else { Loading Loading @@ -321,6 +335,7 @@ int mdss_rotator_resource_ctrl(struct mdss_rot_mgr *mgr, int enable) pr_debug("%s: res_cnt=%d changed=%d enable=%d\n", __func__, mgr->res_ref_cnt, changed, enable); MDSS_XLOG(mgr->res_ref_cnt, changed, enable); if (changed) { if (enable) { Loading @@ -335,14 +350,14 @@ int mdss_rotator_resource_ctrl(struct mdss_rot_mgr *mgr, int enable) return ret; } /* caller is expected to hold perf->work_dis_lock lock */ static bool mdss_rotator_is_work_pending(struct mdss_rot_mgr *mgr, struct mdss_rot_perf *perf) { int i; for (i = 0; i < mgr->queue_count; i++) { atomic_t *wrk_dis = &perf->work_distribution[i]; if (atomic_read(wrk_dis)) { if (perf->work_distribution[i]) { pr_debug("Work is still scheduled to complete\n"); return true; } Loading Loading @@ -394,6 +409,7 @@ static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) entry->output_fence_fd = fd; entry->output_fence = fence; pr_debug("output sync point created at val=%u\n", val); return 0; Loading Loading @@ -502,9 +518,12 @@ static int mdss_rotator_map_and_check_data(struct mdss_rot_entry *entry) rotation = (entry->item.flags & MDP_ROTATION_90) ? true : false; ATRACE_BEGIN(__func__); ret = mdss_iommu_ctrl(1); if (IS_ERR_VALUE(ret)) if (IS_ERR_VALUE(ret)) { ATRACE_END(__func__); return ret; } /* if error during map, the caller will release the data */ ret = mdss_mdp_data_map(&entry->src_buf, true, DMA_TO_DEVICE); Loading Loading @@ -561,32 +580,40 @@ static int mdss_rotator_map_and_check_data(struct mdss_rot_entry *entry) end: mdss_iommu_ctrl(0); ATRACE_END(__func__); return ret; } static struct mdss_rot_perf *mdss_rotator_find_session( static struct mdss_rot_perf *__mdss_rotator_find_session( struct mdss_rot_file_private *private, u32 session_id) { struct mdss_rot_perf *perf, *perf_next; bool found = false; mutex_lock(&private->perf_lock); list_for_each_entry_safe(perf, perf_next, &private->perf_list, list) { if (perf->config.session_id == session_id) { found = true; break; } } mutex_unlock(&private->perf_lock); if (!found) perf = NULL; return perf; } static struct mdss_rot_perf *mdss_rotator_find_session( struct mdss_rot_file_private *private, u32 session_id) { struct mdss_rot_perf *perf; mutex_lock(&private->perf_lock); perf = __mdss_rotator_find_session(private, session_id); mutex_unlock(&private->perf_lock); return perf; } static void mdss_rotator_release_data(struct mdss_rot_entry *entry) { mdss_mdp_data_free(&entry->src_buf, true, DMA_TO_DEVICE); Loading Loading @@ -946,7 +973,6 @@ static void mdss_rotator_queue_request(struct mdss_rot_mgr *mgr, struct mdss_rot_entry *entry; struct mdss_rot_queue *queue; unsigned long clk_rate; atomic_t *wrk_dis; u32 wb_idx; int i; Loading @@ -954,8 +980,9 @@ static void mdss_rotator_queue_request(struct mdss_rot_mgr *mgr, entry = req->entries + i; queue = entry->queue; wb_idx = queue->hw->wb_id; wrk_dis = &entry->perf->work_distribution[wb_idx]; atomic_inc(wrk_dis); mutex_lock(&entry->perf->work_dis_lock); entry->perf->work_distribution[wb_idx]++; mutex_unlock(&entry->perf->work_dis_lock); entry->work_assigned = true; } Loading Loading @@ -1022,6 +1049,8 @@ static int mdss_rotator_update_perf(struct mdss_rot_mgr *mgr) int not_in_suspend_mode; u64 total_bw = 0; ATRACE_BEGIN(__func__); not_in_suspend_mode = !atomic_read(&mgr->device_suspended); if (not_in_suspend_mode) { Loading @@ -1037,9 +1066,12 @@ static int mdss_rotator_update_perf(struct mdss_rot_mgr *mgr) } mutex_lock(&mgr->bus_lock); total_bw += mgr->pending_close_bw_vote; mdss_rotator_enable_reg_bus(mgr, total_bw); mdss_rotator_bus_scale_set_quota(&mgr->data_bus, total_bw); mutex_unlock(&mgr->bus_lock); ATRACE_END(__func__); return 0; } Loading @@ -1048,17 +1080,30 @@ static void mdss_rotator_release_from_work_distribution( struct mdss_rot_entry *entry) { if (entry->work_assigned) { atomic_t *wrk_dis; bool free_perf = false; u32 wb_idx = entry->queue->hw->wb_id; wrk_dis = &entry->perf->work_distribution[wb_idx]; atomic_add_unless(wrk_dis, -1, 0); mutex_lock(&entry->perf->work_dis_lock); if (entry->perf->work_distribution[wb_idx]) entry->perf->work_distribution[wb_idx]--; if (!entry->perf->work_distribution[wb_idx] && list_empty(&entry->perf->list)) { /* close session has offloaded perf free to us */ free_perf = true; } mutex_unlock(&entry->perf->work_dis_lock); entry->work_assigned = false; if (entry->perf->waiting_for_completion && !mdss_rotator_is_work_pending(mgr, entry->perf)) { complete(&entry->perf->stop_comp); entry->perf->waiting_for_completion = false; if (free_perf) { mutex_lock(&mgr->bus_lock); mgr->pending_close_bw_vote -= entry->perf->bw; mutex_unlock(&mgr->bus_lock); mdss_rotator_resource_ctrl(mgr, false); devm_kfree(&mgr->pdev->dev, entry->perf->work_distribution); devm_kfree(&mgr->pdev->dev, entry->perf); mdss_rotator_update_perf(mgr); entry->perf = NULL; } } } Loading Loading @@ -1332,7 +1377,6 @@ static int mdss_rotator_validate_entry(struct mdss_rot_mgr *mgr, pr_err("fail to configure downscale factor\n"); return ret; } return ret; } Loading Loading @@ -1393,6 +1437,14 @@ static int mdss_rotator_add_request(struct mdss_rot_mgr *mgr, return ret; } item->output.fence = entry->output_fence_fd; pr_debug("Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%u\n" "dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->wb_idx, item->src_rect.x, item->src_rect.y, item->src_rect.w, item->src_rect.h, item->input.format, item->dst_rect.x, item->dst_rect.y, item->dst_rect.w, item->dst_rect.h, item->output.format, item->session_id); } mutex_lock(&private->req_lock); Loading Loading @@ -1446,6 +1498,7 @@ static void mdss_rotator_cancel_all_requests(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private) { struct mdss_rot_entry_container *req, *req_next; pr_debug("Canceling all rotator requests\n"); mutex_lock(&private->req_lock); list_for_each_entry_safe(req, req_next, &private->req_list, list) Loading Loading @@ -1474,6 +1527,7 @@ static void mdss_rotator_release_rotator_perf_session( { struct mdss_rot_perf *perf, *perf_next; pr_debug("Releasing all rotator request\n"); mdss_rotator_cancel_all_requests(mgr, private); mutex_lock(&private->perf_lock); Loading Loading @@ -1568,6 +1622,7 @@ static int mdss_rotator_config_hw(struct mdss_rot_hw_resource *hw, struct mdp_rotation_item *item; int ret; ATRACE_BEGIN(__func__); pipe = hw->pipe; item = &entry->item; Loading @@ -1584,11 +1639,22 @@ static int mdss_rotator_config_hw(struct mdss_rot_hw_resource *hw, ret = mdss_mdp_smp_reserve(pipe); if (ret) { pr_debug("unable to mdss_mdp_smp_reserve rot data\n"); return ret; pr_err("unable to mdss_mdp_smp_reserve rot data\n"); goto done; } ret = mdss_mdp_pipe_queue_data(pipe, &entry->src_buf); pr_debug("Config pipe. src{%u,%u,%u,%u}f=%u\n" "dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->src_rect.x, item->src_rect.y, item->src_rect.w, item->src_rect.h, item->input.format, item->dst_rect.x, item->dst_rect.y, item->dst_rect.w, item->dst_rect.h, item->output.format, item->session_id); MDSS_XLOG(item->input.format, pipe->img_width, pipe->img_height, pipe->flags); done: ATRACE_END(__func__); return ret; } Loading Loading @@ -1742,7 +1808,7 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, { struct mdp_rotation_config config; struct mdss_rot_perf *perf; int ret, i; int ret; ret = copy_from_user(&config, (void __user *)arg, sizeof(config)); if (ret) { Loading @@ -1762,8 +1828,9 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, return -ENOMEM; } ATRACE_BEGIN(__func__); /* Open session votes for bw */ perf->work_distribution = devm_kzalloc(&mgr->pdev->dev, sizeof(atomic_t) * mgr->queue_count, GFP_KERNEL); sizeof(u32) * mgr->queue_count, GFP_KERNEL); if (!perf->work_distribution) { pr_err("fail to allocate work_distribution\n"); ret = -ENOMEM; Loading @@ -1773,9 +1840,7 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, config.session_id = mdss_rotator_generator_session_id(mgr); perf->config = config; perf->last_wb_idx = -1; init_completion(&perf->stop_comp); for (i = 0; i < mgr->queue_count; i++) atomic_set(&perf->work_distribution[i], 0); mutex_init(&perf->work_dis_lock); INIT_LIST_HEAD(&perf->list); Loading Loading @@ -1806,8 +1871,12 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, pr_err("fail to open session, not enough clk/bw\n"); goto perf_err; } pr_debug("open session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n", config.session_id, config.input.width, config.input.height, config.input.format, config.output.width, config.output.height, config.output.format); return ret; goto done; perf_err: mdss_rotator_resource_ctrl(mgr, false); resource_err: Loading @@ -1818,6 +1887,8 @@ copy_user_err: devm_kfree(&mgr->pdev->dev, perf->work_distribution); alloc_err: devm_kfree(&mgr->pdev->dev, perf); done: ATRACE_END(__func__); return ret; } Loading @@ -1825,47 +1896,51 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private, unsigned long arg) { struct mdss_rot_perf *perf; bool offload_release_work = false; u32 id; id = (u32)arg; perf = mdss_rotator_find_session(private, id); mutex_lock(&mgr->lock); mutex_lock(&private->perf_lock); perf = __mdss_rotator_find_session(private, id); if (!perf) { mutex_unlock(&private->perf_lock); mutex_unlock(&mgr->lock); pr_err("Trying to close session that does not exist\n"); return -EINVAL; } /* * Client should not be calling close session when there * are pending rotation work. Driver will attempt to * wait for request to complete. */ if (mdss_rotator_is_work_pending(mgr, perf)) { pr_debug("Work is still pending, attempting to wait\n"); reinit_completion(&perf->stop_comp); perf->waiting_for_completion = true; wait_for_completion_timeout(&perf->stop_comp, 3 * KOFF_TIMEOUT); ATRACE_BEGIN(__func__); mutex_lock(&perf->work_dis_lock); if (mdss_rotator_is_work_pending(mgr, perf)) { pr_err("Calling session close, rot work is pending\n"); return -EBUSY; } pr_debug("Work is still pending, offload free to wq\n"); mutex_lock(&mgr->bus_lock); mgr->pending_close_bw_vote += perf->bw; mutex_unlock(&mgr->bus_lock); offload_release_work = true; } mdss_rotator_resource_ctrl(mgr, false); mutex_lock(&private->perf_lock); list_del_init(&perf->list); mutex_unlock(&perf->work_dis_lock); mutex_unlock(&private->perf_lock); mutex_unlock(&mgr->lock); if (offload_release_work) goto done; mdss_rotator_resource_ctrl(mgr, false); devm_kfree(&mgr->pdev->dev, perf->work_distribution); devm_kfree(&mgr->pdev->dev, perf); mdss_rotator_update_perf(mgr); done: pr_debug("Closed session id:%u", id); ATRACE_END(__func__); return 0; } static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private, unsigned long arg) { int ret; int ret = 0; struct mdss_rot_perf *perf; struct mdp_rotation_config config; Loading @@ -1883,9 +1958,13 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, } perf = mdss_rotator_find_session(private, config.session_id); if (!perf) if (!perf) { pr_err("No session with id=%u could be found\n", config.session_id); return -EINVAL; } ATRACE_BEGIN(__func__); mutex_lock(&private->perf_lock); perf->config = config; ret = mdss_rotator_calc_perf(perf); Loading @@ -1893,11 +1972,17 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, if (ret) { pr_err("error in configuring the session %d\n", ret); return ret; goto done; } ret = mdss_rotator_update_perf(mgr); pr_debug("reconfig session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n", config.session_id, config.input.width, config.input.height, config.input.format, config.output.width, config.output.height, config.output.format); done: ATRACE_END(__func__); return ret; } Loading Loading @@ -2199,7 +2284,9 @@ static long mdss_rotator_compat_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case MDSS_ROTATION_REQUEST: ATRACE_BEGIN("rotator_request32"); ret = mdss_rotator_handle_request32(rot_mgr, private, arg); ATRACE_END("rotator_request32"); break; case MDSS_ROTATION_OPEN: ret = mdss_rotator_open_session(rot_mgr, private, arg); Loading Loading @@ -2245,7 +2332,9 @@ static long mdss_rotator_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case MDSS_ROTATION_REQUEST: ATRACE_BEGIN("rotator_request"); ret = mdss_rotator_handle_request(rot_mgr, private, arg); ATRACE_END("rotator_request"); break; case MDSS_ROTATION_OPEN: ret = mdss_rotator_open_session(rot_mgr, private, arg); Loading drivers/video/msm/mdss/mdss_rotator_internal.h +3 −3 Original line number Diff line number Diff line Loading @@ -110,9 +110,8 @@ struct mdss_rot_perf { struct mdp_rotation_config config; unsigned long clk_rate; u64 bw; bool waiting_for_completion; struct completion stop_comp; atomic_t *work_distribution; struct mutex work_dis_lock; u32 *work_distribution; int last_wb_idx; /* last known wb index, used when above count is 0 */ }; Loading Loading @@ -164,6 +163,7 @@ struct mdss_rot_mgr { struct list_head file_list; struct mutex bus_lock; u64 pending_close_bw_vote; struct mdss_rot_bus_data_type data_bus; struct mdss_rot_bus_data_type reg_bus; Loading Loading
drivers/video/msm/mdss/mdss_rotator.c +145 −56 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "mdss_rotator_internal.h" #include "mdss_mdp.h" #include "mdss_debug.h" /* waiting for hw time out, 3 vsync for 30fps*/ #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100 Loading Loading @@ -72,6 +73,7 @@ static int mdss_rotator_bus_scale_set_quota(struct mdss_rot_bus_data_type *bus, u64 quota) { int new_uc_idx; int ret; if (bus->bus_hdl < 1) { pr_err("invalid bus handle %d\n", bus->bus_hdl); Loading Loading @@ -113,8 +115,13 @@ static int mdss_rotator_bus_scale_set_quota(struct mdss_rot_bus_data_type *bus, bus->curr_quota_val = quota; pr_debug("uc_idx=%d quota=%llu\n", new_uc_idx, quota); return msm_bus_scale_client_update_request(bus->bus_hdl, MDSS_XLOG(new_uc_idx, ((quota >> 32) & 0xFFFFFFFF), (quota & 0xFFFFFFFF)); ATRACE_BEGIN("msm_bus_scale_req_rot"); ret = msm_bus_scale_client_update_request(bus->bus_hdl, new_uc_idx); ATRACE_END("msm_bus_scale_req_rot"); return ret; } static int mdss_rotator_enable_reg_bus(struct mdss_rot_mgr *mgr, u64 quota) Loading @@ -136,9 +143,12 @@ static int mdss_rotator_enable_reg_bus(struct mdss_rot_mgr *mgr, u64 quota) pr_debug("%s, changed=%d register bus %s\n", __func__, changed, quota ? "Enable":"Disable"); if (changed) if (changed) { ATRACE_BEGIN("msm_bus_scale_req_rot_reg"); ret = msm_bus_scale_client_update_request(mgr->reg_bus.bus_hdl, usecase_ndx); ATRACE_END("msm_bus_scale_req_rot_reg"); } return ret; } Loading @@ -160,12 +170,13 @@ static unsigned long mdss_rotator_clk_rate_calc( mutex_lock(&private->perf_lock); list_for_each_entry(perf, &private->perf_list, list) { bool rate_accounted_for = false; mutex_lock(&perf->work_dis_lock); /* * If there is one session that has two work items across * different hw blocks rate is accounted for in both blocks. */ for (i = 0; i < mgr->queue_count; i++) { if (atomic_read(&perf->work_distribution[i])) { if (perf->work_distribution[i]) { clk_rate[i] += perf->clk_rate; rate_accounted_for = true; } Loading @@ -180,6 +191,7 @@ static unsigned long mdss_rotator_clk_rate_calc( if ((!rate_accounted_for) && (wb_idx >= 0) && (wb_idx < mgr->queue_count)) clk_rate[wb_idx] += perf->clk_rate; mutex_unlock(&perf->work_dis_lock); } mutex_unlock(&private->perf_lock); Loading Loading @@ -214,10 +226,12 @@ static void mdss_rotator_set_clk_rate(struct mdss_rot_mgr *mgr, pr_err("unable to round rate err=%ld\n", clk_rate); } else if (clk_rate != clk_get_rate(clk)) { ret = clk_set_rate(clk, clk_rate); if (IS_ERR_VALUE(ret)) if (IS_ERR_VALUE(ret)) { pr_err("clk_set_rate failed, err:%d\n", ret); else } else { pr_debug("rotator clk rate=%lu\n", clk_rate); MDSS_XLOG(clk_rate); } } mutex_unlock(&mgr->clk_lock); } else { Loading Loading @@ -321,6 +335,7 @@ int mdss_rotator_resource_ctrl(struct mdss_rot_mgr *mgr, int enable) pr_debug("%s: res_cnt=%d changed=%d enable=%d\n", __func__, mgr->res_ref_cnt, changed, enable); MDSS_XLOG(mgr->res_ref_cnt, changed, enable); if (changed) { if (enable) { Loading @@ -335,14 +350,14 @@ int mdss_rotator_resource_ctrl(struct mdss_rot_mgr *mgr, int enable) return ret; } /* caller is expected to hold perf->work_dis_lock lock */ static bool mdss_rotator_is_work_pending(struct mdss_rot_mgr *mgr, struct mdss_rot_perf *perf) { int i; for (i = 0; i < mgr->queue_count; i++) { atomic_t *wrk_dis = &perf->work_distribution[i]; if (atomic_read(wrk_dis)) { if (perf->work_distribution[i]) { pr_debug("Work is still scheduled to complete\n"); return true; } Loading Loading @@ -394,6 +409,7 @@ static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) entry->output_fence_fd = fd; entry->output_fence = fence; pr_debug("output sync point created at val=%u\n", val); return 0; Loading Loading @@ -502,9 +518,12 @@ static int mdss_rotator_map_and_check_data(struct mdss_rot_entry *entry) rotation = (entry->item.flags & MDP_ROTATION_90) ? true : false; ATRACE_BEGIN(__func__); ret = mdss_iommu_ctrl(1); if (IS_ERR_VALUE(ret)) if (IS_ERR_VALUE(ret)) { ATRACE_END(__func__); return ret; } /* if error during map, the caller will release the data */ ret = mdss_mdp_data_map(&entry->src_buf, true, DMA_TO_DEVICE); Loading Loading @@ -561,32 +580,40 @@ static int mdss_rotator_map_and_check_data(struct mdss_rot_entry *entry) end: mdss_iommu_ctrl(0); ATRACE_END(__func__); return ret; } static struct mdss_rot_perf *mdss_rotator_find_session( static struct mdss_rot_perf *__mdss_rotator_find_session( struct mdss_rot_file_private *private, u32 session_id) { struct mdss_rot_perf *perf, *perf_next; bool found = false; mutex_lock(&private->perf_lock); list_for_each_entry_safe(perf, perf_next, &private->perf_list, list) { if (perf->config.session_id == session_id) { found = true; break; } } mutex_unlock(&private->perf_lock); if (!found) perf = NULL; return perf; } static struct mdss_rot_perf *mdss_rotator_find_session( struct mdss_rot_file_private *private, u32 session_id) { struct mdss_rot_perf *perf; mutex_lock(&private->perf_lock); perf = __mdss_rotator_find_session(private, session_id); mutex_unlock(&private->perf_lock); return perf; } static void mdss_rotator_release_data(struct mdss_rot_entry *entry) { mdss_mdp_data_free(&entry->src_buf, true, DMA_TO_DEVICE); Loading Loading @@ -946,7 +973,6 @@ static void mdss_rotator_queue_request(struct mdss_rot_mgr *mgr, struct mdss_rot_entry *entry; struct mdss_rot_queue *queue; unsigned long clk_rate; atomic_t *wrk_dis; u32 wb_idx; int i; Loading @@ -954,8 +980,9 @@ static void mdss_rotator_queue_request(struct mdss_rot_mgr *mgr, entry = req->entries + i; queue = entry->queue; wb_idx = queue->hw->wb_id; wrk_dis = &entry->perf->work_distribution[wb_idx]; atomic_inc(wrk_dis); mutex_lock(&entry->perf->work_dis_lock); entry->perf->work_distribution[wb_idx]++; mutex_unlock(&entry->perf->work_dis_lock); entry->work_assigned = true; } Loading Loading @@ -1022,6 +1049,8 @@ static int mdss_rotator_update_perf(struct mdss_rot_mgr *mgr) int not_in_suspend_mode; u64 total_bw = 0; ATRACE_BEGIN(__func__); not_in_suspend_mode = !atomic_read(&mgr->device_suspended); if (not_in_suspend_mode) { Loading @@ -1037,9 +1066,12 @@ static int mdss_rotator_update_perf(struct mdss_rot_mgr *mgr) } mutex_lock(&mgr->bus_lock); total_bw += mgr->pending_close_bw_vote; mdss_rotator_enable_reg_bus(mgr, total_bw); mdss_rotator_bus_scale_set_quota(&mgr->data_bus, total_bw); mutex_unlock(&mgr->bus_lock); ATRACE_END(__func__); return 0; } Loading @@ -1048,17 +1080,30 @@ static void mdss_rotator_release_from_work_distribution( struct mdss_rot_entry *entry) { if (entry->work_assigned) { atomic_t *wrk_dis; bool free_perf = false; u32 wb_idx = entry->queue->hw->wb_id; wrk_dis = &entry->perf->work_distribution[wb_idx]; atomic_add_unless(wrk_dis, -1, 0); mutex_lock(&entry->perf->work_dis_lock); if (entry->perf->work_distribution[wb_idx]) entry->perf->work_distribution[wb_idx]--; if (!entry->perf->work_distribution[wb_idx] && list_empty(&entry->perf->list)) { /* close session has offloaded perf free to us */ free_perf = true; } mutex_unlock(&entry->perf->work_dis_lock); entry->work_assigned = false; if (entry->perf->waiting_for_completion && !mdss_rotator_is_work_pending(mgr, entry->perf)) { complete(&entry->perf->stop_comp); entry->perf->waiting_for_completion = false; if (free_perf) { mutex_lock(&mgr->bus_lock); mgr->pending_close_bw_vote -= entry->perf->bw; mutex_unlock(&mgr->bus_lock); mdss_rotator_resource_ctrl(mgr, false); devm_kfree(&mgr->pdev->dev, entry->perf->work_distribution); devm_kfree(&mgr->pdev->dev, entry->perf); mdss_rotator_update_perf(mgr); entry->perf = NULL; } } } Loading Loading @@ -1332,7 +1377,6 @@ static int mdss_rotator_validate_entry(struct mdss_rot_mgr *mgr, pr_err("fail to configure downscale factor\n"); return ret; } return ret; } Loading Loading @@ -1393,6 +1437,14 @@ static int mdss_rotator_add_request(struct mdss_rot_mgr *mgr, return ret; } item->output.fence = entry->output_fence_fd; pr_debug("Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%u\n" "dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->wb_idx, item->src_rect.x, item->src_rect.y, item->src_rect.w, item->src_rect.h, item->input.format, item->dst_rect.x, item->dst_rect.y, item->dst_rect.w, item->dst_rect.h, item->output.format, item->session_id); } mutex_lock(&private->req_lock); Loading Loading @@ -1446,6 +1498,7 @@ static void mdss_rotator_cancel_all_requests(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private) { struct mdss_rot_entry_container *req, *req_next; pr_debug("Canceling all rotator requests\n"); mutex_lock(&private->req_lock); list_for_each_entry_safe(req, req_next, &private->req_list, list) Loading Loading @@ -1474,6 +1527,7 @@ static void mdss_rotator_release_rotator_perf_session( { struct mdss_rot_perf *perf, *perf_next; pr_debug("Releasing all rotator request\n"); mdss_rotator_cancel_all_requests(mgr, private); mutex_lock(&private->perf_lock); Loading Loading @@ -1568,6 +1622,7 @@ static int mdss_rotator_config_hw(struct mdss_rot_hw_resource *hw, struct mdp_rotation_item *item; int ret; ATRACE_BEGIN(__func__); pipe = hw->pipe; item = &entry->item; Loading @@ -1584,11 +1639,22 @@ static int mdss_rotator_config_hw(struct mdss_rot_hw_resource *hw, ret = mdss_mdp_smp_reserve(pipe); if (ret) { pr_debug("unable to mdss_mdp_smp_reserve rot data\n"); return ret; pr_err("unable to mdss_mdp_smp_reserve rot data\n"); goto done; } ret = mdss_mdp_pipe_queue_data(pipe, &entry->src_buf); pr_debug("Config pipe. src{%u,%u,%u,%u}f=%u\n" "dst{%u,%u,%u,%u}f=%u session_id=%u\n", item->src_rect.x, item->src_rect.y, item->src_rect.w, item->src_rect.h, item->input.format, item->dst_rect.x, item->dst_rect.y, item->dst_rect.w, item->dst_rect.h, item->output.format, item->session_id); MDSS_XLOG(item->input.format, pipe->img_width, pipe->img_height, pipe->flags); done: ATRACE_END(__func__); return ret; } Loading Loading @@ -1742,7 +1808,7 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, { struct mdp_rotation_config config; struct mdss_rot_perf *perf; int ret, i; int ret; ret = copy_from_user(&config, (void __user *)arg, sizeof(config)); if (ret) { Loading @@ -1762,8 +1828,9 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, return -ENOMEM; } ATRACE_BEGIN(__func__); /* Open session votes for bw */ perf->work_distribution = devm_kzalloc(&mgr->pdev->dev, sizeof(atomic_t) * mgr->queue_count, GFP_KERNEL); sizeof(u32) * mgr->queue_count, GFP_KERNEL); if (!perf->work_distribution) { pr_err("fail to allocate work_distribution\n"); ret = -ENOMEM; Loading @@ -1773,9 +1840,7 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, config.session_id = mdss_rotator_generator_session_id(mgr); perf->config = config; perf->last_wb_idx = -1; init_completion(&perf->stop_comp); for (i = 0; i < mgr->queue_count; i++) atomic_set(&perf->work_distribution[i], 0); mutex_init(&perf->work_dis_lock); INIT_LIST_HEAD(&perf->list); Loading Loading @@ -1806,8 +1871,12 @@ static int mdss_rotator_open_session(struct mdss_rot_mgr *mgr, pr_err("fail to open session, not enough clk/bw\n"); goto perf_err; } pr_debug("open session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n", config.session_id, config.input.width, config.input.height, config.input.format, config.output.width, config.output.height, config.output.format); return ret; goto done; perf_err: mdss_rotator_resource_ctrl(mgr, false); resource_err: Loading @@ -1818,6 +1887,8 @@ copy_user_err: devm_kfree(&mgr->pdev->dev, perf->work_distribution); alloc_err: devm_kfree(&mgr->pdev->dev, perf); done: ATRACE_END(__func__); return ret; } Loading @@ -1825,47 +1896,51 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private, unsigned long arg) { struct mdss_rot_perf *perf; bool offload_release_work = false; u32 id; id = (u32)arg; perf = mdss_rotator_find_session(private, id); mutex_lock(&mgr->lock); mutex_lock(&private->perf_lock); perf = __mdss_rotator_find_session(private, id); if (!perf) { mutex_unlock(&private->perf_lock); mutex_unlock(&mgr->lock); pr_err("Trying to close session that does not exist\n"); return -EINVAL; } /* * Client should not be calling close session when there * are pending rotation work. Driver will attempt to * wait for request to complete. */ if (mdss_rotator_is_work_pending(mgr, perf)) { pr_debug("Work is still pending, attempting to wait\n"); reinit_completion(&perf->stop_comp); perf->waiting_for_completion = true; wait_for_completion_timeout(&perf->stop_comp, 3 * KOFF_TIMEOUT); ATRACE_BEGIN(__func__); mutex_lock(&perf->work_dis_lock); if (mdss_rotator_is_work_pending(mgr, perf)) { pr_err("Calling session close, rot work is pending\n"); return -EBUSY; } pr_debug("Work is still pending, offload free to wq\n"); mutex_lock(&mgr->bus_lock); mgr->pending_close_bw_vote += perf->bw; mutex_unlock(&mgr->bus_lock); offload_release_work = true; } mdss_rotator_resource_ctrl(mgr, false); mutex_lock(&private->perf_lock); list_del_init(&perf->list); mutex_unlock(&perf->work_dis_lock); mutex_unlock(&private->perf_lock); mutex_unlock(&mgr->lock); if (offload_release_work) goto done; mdss_rotator_resource_ctrl(mgr, false); devm_kfree(&mgr->pdev->dev, perf->work_distribution); devm_kfree(&mgr->pdev->dev, perf); mdss_rotator_update_perf(mgr); done: pr_debug("Closed session id:%u", id); ATRACE_END(__func__); return 0; } static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, struct mdss_rot_file_private *private, unsigned long arg) { int ret; int ret = 0; struct mdss_rot_perf *perf; struct mdp_rotation_config config; Loading @@ -1883,9 +1958,13 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, } perf = mdss_rotator_find_session(private, config.session_id); if (!perf) if (!perf) { pr_err("No session with id=%u could be found\n", config.session_id); return -EINVAL; } ATRACE_BEGIN(__func__); mutex_lock(&private->perf_lock); perf->config = config; ret = mdss_rotator_calc_perf(perf); Loading @@ -1893,11 +1972,17 @@ static int mdss_rotator_config_session(struct mdss_rot_mgr *mgr, if (ret) { pr_err("error in configuring the session %d\n", ret); return ret; goto done; } ret = mdss_rotator_update_perf(mgr); pr_debug("reconfig session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n", config.session_id, config.input.width, config.input.height, config.input.format, config.output.width, config.output.height, config.output.format); done: ATRACE_END(__func__); return ret; } Loading Loading @@ -2199,7 +2284,9 @@ static long mdss_rotator_compat_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case MDSS_ROTATION_REQUEST: ATRACE_BEGIN("rotator_request32"); ret = mdss_rotator_handle_request32(rot_mgr, private, arg); ATRACE_END("rotator_request32"); break; case MDSS_ROTATION_OPEN: ret = mdss_rotator_open_session(rot_mgr, private, arg); Loading Loading @@ -2245,7 +2332,9 @@ static long mdss_rotator_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case MDSS_ROTATION_REQUEST: ATRACE_BEGIN("rotator_request"); ret = mdss_rotator_handle_request(rot_mgr, private, arg); ATRACE_END("rotator_request"); break; case MDSS_ROTATION_OPEN: ret = mdss_rotator_open_session(rot_mgr, private, arg); Loading
drivers/video/msm/mdss/mdss_rotator_internal.h +3 −3 Original line number Diff line number Diff line Loading @@ -110,9 +110,8 @@ struct mdss_rot_perf { struct mdp_rotation_config config; unsigned long clk_rate; u64 bw; bool waiting_for_completion; struct completion stop_comp; atomic_t *work_distribution; struct mutex work_dis_lock; u32 *work_distribution; int last_wb_idx; /* last known wb index, used when above count is 0 */ }; Loading Loading @@ -164,6 +163,7 @@ struct mdss_rot_mgr { struct list_head file_list; struct mutex bus_lock; u64 pending_close_bw_vote; struct mdss_rot_bus_data_type data_bus; struct mdss_rot_bus_data_type reg_bus; Loading