Pārlūkot izejas kodu

disp: msm: add support for display clients to register for fence error

Add framework for display submodules like PP, DSI, DP to register
for fence error and call the client callback funtion when fence
error occurs.

Change-Id: I70cc6b01907177e6c4238c4398fe2c085a000322
Signed-off-by: GG Hou <[email protected]>
GG Hou 2 gadi atpakaļ
vecāks
revīzija
d2812ee4e7
4 mainītis faili ar 154 papildinājumiem un 1 dzēšanām
  1. 62 1
      msm/msm_drv.c
  2. 44 0
      msm/msm_drv.h
  3. 27 0
      msm/sde/sde_crtc.c
  4. 21 0
      msm/sde/sde_encoder.c

+ 62 - 1
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 <[email protected]>
@@ -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)

+ 44 - 0
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,

+ 27 - 0
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;
 }
 

+ 21 - 0
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;