diff --git a/msm/msm_drv.c b/msm/msm_drv.c index d43673cd3e..adc78e50ae 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -911,9 +911,11 @@ static int msm_drm_component_init(struct device *dev) INIT_LIST_HEAD(&priv->client_event_list); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->vm_client_list); + INIT_LIST_HEAD(&priv->fence_error_client_list); mutex_init(&priv->mm_lock); mutex_init(&priv->vm_client_lock); + mutex_init(&priv->fence_error_client_lock); /* Bind all our sub-components: */ ret = msm_component_bind_all(dev, ddev); @@ -2082,6 +2084,65 @@ static int add_display_components(struct device *dev, return ret; } +void *msm_register_fence_error_event(struct drm_device *ddev, struct msm_fence_error_ops *ops, + void *priv_data) +{ + struct msm_drm_private *priv; + struct msm_fence_error_client_entry *client_entry; + + if (!ddev || !ddev->dev_private) { + DRM_ERROR("Invalid drm_device.\n"); + return ERR_PTR(-EINVAL); + } + priv = ddev->dev_private; + + if (!ops) { + DRM_ERROR("invalid msm_fence_error_ops.\n"); + return ERR_PTR(-EINVAL); + } + + client_entry = kzalloc(sizeof(*client_entry), GFP_KERNEL); + if (!client_entry) { + DRM_ERROR("invalid client_entry.\n"); + return ERR_PTR(-ENOMEM); + } + + mutex_lock(&priv->fence_error_client_lock); + memcpy(&client_entry->ops, ops, sizeof(*ops)); + client_entry->data = priv_data; + list_add(&client_entry->list, &priv->fence_error_client_list); + mutex_unlock(&priv->fence_error_client_lock); + + return (void *)client_entry; +} +EXPORT_SYMBOL(msm_register_fence_error_event); + +int msm_unregister_fence_error_event(struct drm_device *ddev, + struct msm_fence_error_client_entry *client_entry_handle) +{ + struct msm_drm_private *priv; + struct msm_fence_error_client_entry *client_entry = client_entry_handle; + + if (!ddev || !ddev->dev_private) { + DRM_ERROR("Invalid drm_device.\n"); + return -EINVAL; + } + priv = ddev->dev_private; + + if (IS_ERR_OR_NULL(client_entry_handle)) { + DRM_ERROR("Invalid client_entry handle.\n"); + return -EINVAL; + } + + mutex_lock(&priv->fence_error_client_lock); + list_del(&client_entry->list); + kfree(client_entry); + mutex_unlock(&priv->fence_error_client_lock); + + return 0; +} +EXPORT_SYMBOL(msm_unregister_fence_error_event); + struct msm_gem_address_space * msm_gem_smmu_address_space_get(struct drm_device *dev, unsigned int domain) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 34a92535e0..bd624ef227 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -976,6 +976,28 @@ struct msm_drm_thread { struct kthread_worker worker; }; +/** + * struct msm_fence_error_ops - hooks for communication with fence error clients + * @fence_error_handle_submodule: fence error handle for display submodule + */ +struct msm_fence_error_ops { + int (*fence_error_handle_submodule)(void *ctl_data, void *priv_data); +}; + +/** + * msm_fence_error_client_entry - defines the msm fence error client info + * @ops: client msm_fence_error_ops + * @dev: client device id + * @data: client custom data + * @list: linked list entry + */ +struct msm_fence_error_client_entry { + struct msm_fence_error_ops ops; + struct device *dev; + void *data; + struct list_head list; +}; + struct msm_drm_private { struct drm_device *dev; @@ -1102,6 +1124,9 @@ struct msm_drm_private { struct mutex vm_client_lock; struct list_head vm_client_list; + + struct mutex fence_error_client_lock; + struct list_head fence_error_client_list; }; /* get struct msm_kms * from drm_device * */ @@ -1138,6 +1163,25 @@ void msm_atomic_state_free(struct drm_atomic_state *state); void msm_atomic_flush_display_threads(struct msm_drm_private *priv); +/** + * msm_register_fence_error_event - api for display dependent drivers(clients) to + * register for fence error events + * @dev: msm device + * @ops: fence error event hooks + * @priv_data: client custom data + */ +void *msm_register_fence_error_event(struct drm_device *ddev, struct msm_fence_error_ops *ops, + void *priv_data); + +/** + * msm_unregister_fence_error_event - api for display dependent drivers(clients) to + * unregister for fence error events + * @dev: msm device + * @client_entry_handle: client_entry pointer + */ +int msm_unregister_fence_error_event(struct drm_device *ddev, + struct msm_fence_error_client_entry *client_entry_handle); + int msm_gem_init_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, int npages); void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 7954bfca02..9265cbd08f 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3867,6 +3867,10 @@ int sde_crtc_sw_fence_error_handle(struct drm_crtc *crtc, int err_status) struct sde_crtc *sde_crtc = NULL; struct drm_encoder *drm_encoder; bool handle_sw_fence_error_flag; + struct sde_kms *sde_kms; + struct sde_hw_ctl *hw_ctl; + struct msm_drm_private *priv; + struct msm_fence_error_client_entry *entry; int rc = 0; if (!crtc) { @@ -3894,6 +3898,29 @@ int sde_crtc_sw_fence_error_handle(struct drm_crtc *crtc, int err_status) } } + hw_ctl = _sde_crtc_get_hw_ctl(crtc); + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { + SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); + SDE_DEBUG("invalid parameters\n"); + return -EINVAL; + } + + priv = sde_kms->dev->dev_private; + + /* display submodule fence error handling, like pp, dsi, dp. */ + list_for_each_entry(entry, &priv->fence_error_client_list, list) { + if (!entry->ops.fence_error_handle_submodule) + continue; + + rc = entry->ops.fence_error_handle_submodule(hw_ctl, entry->data); + if (rc) { + SDE_ERROR("fence_error_handle_submodule failed for device: %d\n", + entry->dev->id); + SDE_EVT32(entry->dev->id, rc, SDE_EVTLOG_ERROR); + } + } + return rc; } diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 38ac9af4a2..9f69417d43 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2181,6 +2181,8 @@ int sde_encoder_hw_fence_error_handle(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys_enc; + struct msm_drm_private *priv; + struct msm_fence_error_client_entry *entry; int rc = 0; sde_enc = to_sde_encoder_virt(drm_enc); @@ -2204,6 +2206,25 @@ int sde_encoder_hw_fence_error_handle(struct drm_encoder *drm_enc) SDE_EVT32(DRMID(phys_enc->parent), rc, SDE_EVTLOG_ERROR); } + if (!phys_enc->sde_kms && !phys_enc->sde_kms->dev && !phys_enc->sde_kms->dev->dev_private) { + SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_ERROR); + return -EINVAL; + } + + priv = phys_enc->sde_kms->dev->dev_private; + list_for_each_entry(entry, &priv->fence_error_client_list, list) { + if (!entry->ops.fence_error_handle_submodule) + continue; + + SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_FUNC_CASE1); + rc = entry->ops.fence_error_handle_submodule(phys_enc->hw_ctl, entry->data); + if (rc) { + SDE_ERROR("fence_error_handle_submodule failed for device: %d\n", + entry->dev->id); + SDE_EVT32(DRMID(drm_enc), rc, SDE_EVTLOG_ERROR); + } + } + phys_enc->sde_hw_fence_error_status = false; SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_FUNC_EXIT); return rc;