diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 8e5fe0c258..6c720ceb24 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2502,6 +2502,12 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, if (!vm_ops) return 0; + if (!vm_ops->vm_request_valid || !vm_ops->vm_owns_hw || + !vm_ops->vm_acquire) + return -EINVAL; + + sde_vm_lock(sde_kms); + for_each_oldnew_crtc_in_state(state, crtc, old_cstate, new_cstate, i) { struct sde_crtc_state *old_state = NULL, *new_state = NULL; @@ -2516,12 +2522,27 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, old_vm_req = sde_crtc_get_property(old_state, CRTC_PROP_VM_REQ_STATE); - /** + /* * No active request if the transition is from * VM_REQ_NONE to VM_REQ_NONE */ - if (new_vm_req || old_vm_req) - vm_req_active = true; + if (old_vm_req || new_vm_req) { + rc = vm_ops->vm_request_valid(sde_kms, + old_vm_req, new_vm_req); + if (rc) { + SDE_ERROR( + "VM transition check failed; o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n", + old_vm_req, new_vm_req, + vm_ops->vm_owns_hw(sde_kms), rc); + goto end; + } else if (old_vm_req == VM_REQ_ACQUIRE && + new_vm_req == VM_REQ_NONE) { + SDE_DEBUG( + "VM transition valid; ignore further checks\n"); + } else { + vm_req_active = true; + } + } idle_pc_state = sde_crtc_get_property(new_state, CRTC_PROP_IDLE_PC_STATE); @@ -2530,6 +2551,10 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, commit_crtc_cnt++; } + /* return early if no active vm request */ + if (!vm_req_active) + goto end; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->state->active) continue; @@ -2539,36 +2564,39 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, } /* Check for single crtc commits only on valid VM requests */ - if (vm_req_active && active_crtc && global_active_crtc && + if (active_crtc && global_active_crtc && (commit_crtc_cnt > sde_kms->catalog->max_trusted_vm_displays || global_crtc_cnt > sde_kms->catalog->max_trusted_vm_displays || active_crtc != global_active_crtc)) { SDE_ERROR( - "failed to switch VM due to CRTC concurrencies: MAX_CNT: %d active_cnt: %d global_cnt: %d active_crtc: %d global_crtc: %d\n", + "VM switch failed; MAX:%d a_cnt:%d g_cnt:%d a_crtc:%d g_crtc:%d\n", sde_kms->catalog->max_trusted_vm_displays, - commit_crtc_cnt, global_crtc_cnt, active_crtc, - global_active_crtc); - return -E2BIG; + commit_crtc_cnt, global_crtc_cnt, DRMID(active_crtc), + DRMID(global_active_crtc)); + rc = -E2BIG; + goto end; } - if (!vm_req_active) - return 0; - /* disable idle-pc before releasing the HW */ if ((new_vm_req == VM_REQ_RELEASE) && (idle_pc_state == IDLE_PC_ENABLE)) { - SDE_ERROR("failed to switch VM since idle-pc is enabled\n"); - return -EINVAL; + SDE_ERROR("VM switch failed since idle-pc is enabled\n"); + rc = -EINVAL; + goto end; } - sde_vm_lock(sde_kms); + if ((new_vm_req == VM_REQ_ACQUIRE) && !vm_ops->vm_owns_hw(sde_kms)) { + rc = vm_ops->vm_acquire(sde_kms); + if (rc) { + SDE_ERROR( + "VM acquire failed; o_state:%d, n_state:%d, hw_owner:%d, rc:%d\n", + old_vm_req, new_vm_req, + vm_ops->vm_owns_hw(sde_kms), rc); + goto end; + } + } - if (vm_ops->vm_request_valid) - rc = vm_ops->vm_request_valid(sde_kms, old_vm_req, new_vm_req); - if (rc) - SDE_ERROR( - "failed to complete vm transition request. old_state = %d, new_state = %d, hw_ownership: %d\n", - old_vm_req, new_vm_req, vm_ops->vm_owns_hw(sde_kms)); +end: sde_vm_unlock(sde_kms); return rc; diff --git a/msm/sde/sde_vm_common.c b/msm/sde/sde_vm_common.c index d48ce18ec0..5026a8aa64 100644 --- a/msm/sde/sde_vm_common.c +++ b/msm/sde/sde_vm_common.c @@ -306,14 +306,8 @@ int sde_vm_request_valid(struct sde_kms *sde_kms, rc = -EINVAL; break; case VM_REQ_ACQUIRE: - if (old_state != VM_REQ_RELEASE) { + if (old_state != VM_REQ_RELEASE) rc = -EINVAL; - } else if (!vm_ops->vm_owns_hw(sde_kms)) { - if (vm_ops->vm_acquire) - rc = vm_ops->vm_acquire(sde_kms); - else - rc = -EINVAL; - } break; default: SDE_ERROR("invalid vm request\n");