diff --git a/msm/msm_drv.c b/msm/msm_drv.c index d72da8797e..98e94e02f1 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1645,6 +1645,7 @@ int msm_ioctl_display_hint_ops(struct drm_device *dev, void *data, SDE_EVT32(display_hint->hint_flags); + /* Any new hint added will require a check for VM ownership before HW is accessed */ if (display_hint->hint_flags == DRM_MSM_DISPLAY_EARLY_WAKEUP_HINT) { if (!display_hint->data) { DRM_ERROR("early_wakeup: wrong parameter\n"); diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 04efc7ae89..151f08d8ab 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -131,7 +131,6 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) struct drm_event event; int rc = 0; struct sde_kms *sde_kms; - struct sde_vm_ops *vm_ops; sde_kms = _sde_connector_get_kms(&c_conn->base); if (!sde_kms) { @@ -167,8 +166,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) sde_vm_lock(sde_kms); - vm_ops = sde_vm_get_ops(sde_kms); - if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) { + if (!sde_vm_owns_hw(sde_kms)) { SDE_DEBUG("skipping bl update due to HW unavailablity\n"); goto done; } @@ -2077,7 +2075,6 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file, { struct drm_connector *connector = file->private_data; struct sde_connector *c_conn = NULL; - struct sde_vm_ops *vm_ops; struct sde_kms *sde_kms; char *input, *token, *input_copy, *input_dup = NULL; const char *delim = " "; @@ -2107,9 +2104,8 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file, if (!input) return -ENOMEM; - vm_ops = sde_vm_get_ops(sde_kms); sde_vm_lock(sde_kms); - if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) { + if (!sde_vm_owns_hw(sde_kms)) { SDE_DEBUG("op not supported due to HW unavailablity\n"); rc = -EOPNOTSUPP; goto end; diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 48b93af509..9580f3159f 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -6470,7 +6470,6 @@ static ssize_t _sde_crtc_misr_read(struct file *file, struct sde_crtc *sde_crtc; struct sde_kms *sde_kms; struct sde_crtc_mixer *m; - struct sde_vm_ops *vm_ops; int i = 0, rc; ssize_t len = 0; char buf[MISR_BUFF_SIZE + 1] = {'\0'}; @@ -6491,9 +6490,8 @@ static ssize_t _sde_crtc_misr_read(struct file *file, if (rc < 0) return rc; - vm_ops = sde_vm_get_ops(sde_kms); sde_vm_lock(sde_kms); - if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) { + if (!sde_vm_owns_hw(sde_kms)) { SDE_DEBUG("op not supported due to HW unavailability\n"); rc = -EOPNOTSUPP; goto end; diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 1b4d2579f2..f255969246 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -4040,9 +4040,13 @@ static void sde_encoder_early_wakeup_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, early_wakeup_work); + struct sde_kms *sde_kms = to_sde_kms(ddev_to_msm_kms(sde_enc->base.dev)); - if (!sde_enc) { - SDE_ERROR("invalid sde encoder\n"); + sde_vm_lock(sde_kms); + if (!sde_vm_owns_hw(sde_kms)) { + sde_vm_unlock(sde_kms); + SDE_DEBUG("skip early wakeup for ENC-%d, HW is owned by other VM\n", + DRMID(&sde_enc->base)); return; } @@ -4050,6 +4054,7 @@ static void sde_encoder_early_wakeup_work_handler(struct kthread_work *work) sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_EARLY_WAKEUP); SDE_ATRACE_END("encoder_early_wakeup"); + sde_vm_unlock(sde_kms); } void sde_encoder_early_wakeup(struct drm_encoder *drm_enc) @@ -4764,7 +4769,6 @@ static ssize_t _sde_encoder_misr_read(struct file *file, struct sde_encoder_virt *sde_enc; struct sde_kms *sde_kms = NULL; struct drm_encoder *drm_enc; - struct sde_vm_ops *vm_ops; int i = 0, len = 0; char buf[MISR_BUFF_SIZE + 1] = {'\0'}; int rc; @@ -4790,9 +4794,8 @@ static ssize_t _sde_encoder_misr_read(struct file *file, if (rc < 0) return rc; - vm_ops = sde_vm_get_ops(sde_kms); sde_vm_lock(sde_kms); - if (vm_ops && vm_ops->vm_owns_hw && !vm_ops->vm_owns_hw(sde_kms)) { + if (!sde_vm_owns_hw(sde_kms)) { SDE_DEBUG("op not supported due to HW unavailablity\n"); rc = -EOPNOTSUPP; goto end; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index b4fc41e4a3..614d7f397c 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2765,6 +2765,7 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, enum sde_crtc_vm_req old_vm_req = VM_REQ_NONE, new_vm_req = VM_REQ_NONE; struct sde_vm_ops *vm_ops; bool vm_req_active = false; + bool vm_owns_hw; enum sde_crtc_idle_pc_state idle_pc_state; struct sde_mdss_cfg *catalog; int rc = 0; @@ -2789,7 +2790,7 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, return -EINVAL; sde_vm_lock(sde_kms); - + vm_owns_hw = sde_vm_owns_hw(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; @@ -2814,8 +2815,7 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, 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); + old_vm_req, new_vm_req, vm_owns_hw, rc); goto end; } else if (old_vm_req == VM_REQ_ACQUIRE && new_vm_req == VM_REQ_NONE) { @@ -2852,9 +2852,8 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, crtc_encoder_cnt++; } - SDE_EVT32(old_vm_req, new_vm_req, vm_ops->vm_owns_hw(sde_kms)); - SDE_DEBUG("VM o_state:%d, n_state:%d, hw_owner:%d\n", old_vm_req, - new_vm_req, vm_ops->vm_owns_hw(sde_kms)); + SDE_EVT32(old_vm_req, new_vm_req, vm_owns_hw); + SDE_DEBUG("VM o_state:%d, n_state:%d, hw_owner:%d\n", old_vm_req, new_vm_req, vm_owns_hw); for_each_new_connector_in_state(state, connector, new_connstate, i) { int conn_mask = active_cstate->connector_mask; @@ -2903,13 +2902,12 @@ static int sde_kms_check_vm_request(struct msm_kms *kms, goto end; } - if ((new_vm_req == VM_REQ_ACQUIRE) && !vm_ops->vm_owns_hw(sde_kms)) { + if ((new_vm_req == VM_REQ_ACQUIRE) && !vm_owns_hw) { 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); + old_vm_req, new_vm_req, vm_owns_hw, rc); goto end; } @@ -5062,10 +5060,9 @@ static int _sde_kms_register_events(struct msm_kms *kms, struct drm_mode_object *obj, u32 event, bool en) { int ret = 0; - struct drm_crtc *crtc = NULL; - struct drm_connector *conn = NULL; - struct sde_kms *sde_kms = NULL; - struct sde_vm_ops *vm_ops; + struct drm_crtc *crtc; + struct drm_connector *conn; + struct sde_kms *sde_kms; if (!kms || !obj) { SDE_ERROR("invalid argument kms %pK obj %pK\n", kms, obj); @@ -5073,24 +5070,18 @@ static int _sde_kms_register_events(struct msm_kms *kms, } sde_kms = to_sde_kms(kms); + sde_vm_lock(sde_kms); + if (!sde_vm_owns_hw(sde_kms)) { + sde_vm_unlock(sde_kms); + SDE_DEBUG("HW is owned by other VM\n"); + return -EACCES; + } /* check vm ownership, if event registration requires HW access */ switch (obj->type) { case DRM_MODE_OBJECT_CRTC: - vm_ops = sde_vm_get_ops(sde_kms); - sde_vm_lock(sde_kms); - - if (vm_ops && vm_ops->vm_owns_hw - && !vm_ops->vm_owns_hw(sde_kms)) { - sde_vm_unlock(sde_kms); - SDE_DEBUG("HW is owned by other VM\n"); - return -EACCES; - } - crtc = obj_to_crtc(obj); ret = sde_crtc_register_custom_event(sde_kms, crtc, event, en); - - sde_vm_unlock(sde_kms); break; case DRM_MODE_OBJECT_CONNECTOR: conn = obj_to_connector(obj); @@ -5099,6 +5090,8 @@ static int _sde_kms_register_events(struct msm_kms *kms, break; } + sde_vm_unlock(sde_kms); + return ret; } diff --git a/msm/sde/sde_vm.h b/msm/sde/sde_vm.h index b5cc788fbd..3c35c9d742 100644 --- a/msm/sde/sde_vm.h +++ b/msm/sde/sde_vm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef __SDE_VM_H__ @@ -285,6 +285,23 @@ static inline struct sde_vm_ops *sde_vm_get_ops(struct sde_kms *sde_kms) return &sde_kms->vm->vm_ops; } + +/** + * sde_vm_owns_hw - checks if the executing VM currently has HW ownership (caller must be holding + * the sde_vm_lock) + * @sde_kms - pointer to sde_kms + * @return - true if this VM currently owns the HW + */ +static inline bool sde_vm_owns_hw(struct sde_kms *sde_kms) +{ + struct sde_vm_ops *vm_ops = sde_kms ? sde_vm_get_ops(sde_kms) : NULL; + + if (vm_ops && vm_ops->vm_owns_hw) + return vm_ops->vm_owns_hw(sde_kms); + + return true; +} + #else static inline int sde_vm_primary_init(struct sde_kms *kms) { @@ -314,5 +331,10 @@ static inline struct sde_vm_ops *sde_vm_get_ops(struct sde_kms *sde_kms) return NULL; } +static inline bool sde_vm_owns_hw(struct sde_kms *sde_kms) +{ + return true; +} + #endif /* IS_ENABLED(CONFIG_DRM_SDE_VM) */ #endif /* __SDE_VM_H__ */ diff --git a/msm/sde/sde_vm_common.c b/msm/sde/sde_vm_common.c index 5f4b131818..3aefdd252d 100644 --- a/msm/sde/sde_vm_common.c +++ b/msm/sde/sde_vm_common.c @@ -296,16 +296,13 @@ int sde_vm_request_valid(struct sde_kms *sde_kms, enum sde_crtc_vm_req old_state, enum sde_crtc_vm_req new_state) { - struct sde_vm_ops *vm_ops; int rc = 0; - - vm_ops = &sde_kms->vm->vm_ops; + bool vm_owns_hw = sde_vm_owns_hw(sde_kms); switch (new_state) { case VM_REQ_RELEASE: case VM_REQ_NONE: - if ((old_state == VM_REQ_RELEASE) || - !vm_ops->vm_owns_hw(sde_kms)) + if ((old_state == VM_REQ_RELEASE) || !vm_owns_hw) rc = -EINVAL; break; case VM_REQ_ACQUIRE: @@ -318,9 +315,8 @@ int sde_vm_request_valid(struct sde_kms *sde_kms, }; SDE_DEBUG("old req: %d new req: %d owns_hw: %d, rc: %d\n", - old_state, new_state, - vm_ops->vm_owns_hw(sde_kms), rc); - SDE_EVT32(old_state, new_state, vm_ops->vm_owns_hw(sde_kms), rc); + old_state, new_state, vm_owns_hw, rc); + SDE_EVT32(old_state, new_state, vm_owns_hw, rc); return rc; }