drm: samsung: add lock when access histogram drm event

There is race condition problem when composer and irq thread to access
dqe->state.event. Add lock protection to avoid this problem.

Bug: 233709834
Test: enable/disable histogram
Signed-off-by: Midas Chien <midaschieh@google.com>
Change-Id: I1727622adb036cdc2bbaae4d9c15526b3e11c67f
diff --git a/samsung/exynos_drm_dqe.c b/samsung/exynos_drm_dqe.c
index 03851d6..2db2875 100644
--- a/samsung/exynos_drm_dqe.c
+++ b/samsung/exynos_drm_dqe.c
@@ -97,6 +97,7 @@
 	struct decon_device *decon;
 	struct exynos_dqe *dqe;
 	uint32_t *crtc_id = data;
+	unsigned long flags;
 
 	obj = drm_mode_object_find(dev, file, *crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
@@ -118,16 +119,20 @@
 	 * TODO: Now only one observer is allowed at a time at the moment.
 	 * This will be allowed for multiple observer in the future.
 	 */
+	spin_lock_irqsave(&dqe->state.histogram_slock, flags);
 	if (dqe->state.event) {
 		pr_warn("decon%u histogram already registered\n", decon->id);
+		spin_unlock_irqrestore(&dqe->state.histogram_slock, flags);
 		return -EBUSY;
 	}
 	dqe->state.event = create_histogram_event(dev, file);
 	if (IS_ERR_OR_NULL(dqe->state.event)) {
 		dqe->state.event = NULL;
 		pr_err("failed to create a histogram event\n");
+		spin_unlock_irqrestore(&dqe->state.histogram_slock, flags);
 		return -EINVAL;
 	}
+	spin_unlock_irqrestore(&dqe->state.histogram_slock, flags);
 
 	pr_debug("created histogram event(0x%pK) of decon%u\n",
 			dqe->state.event, decon->id);
@@ -143,6 +148,7 @@
 	struct decon_device *decon;
 	struct exynos_dqe *dqe;
 	uint32_t *crtc_id = data;
+	unsigned long flags;
 
 	obj = drm_mode_object_find(dev, file, *crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
@@ -160,11 +166,13 @@
 		return -ENODEV;
 	}
 
+	spin_lock_irqsave(&dqe->state.histogram_slock, flags);
 	if (dqe->state.event) {
 		pr_debug("remained event(0x%pK)\n", dqe->state.event);
 		drm_event_cancel_free(dev, &dqe->state.event->base);
 		dqe->state.event = NULL;
 	}
+	spin_unlock_irqrestore(&dqe->state.histogram_slock, flags);
 
 	pr_debug("terminated histogram event of decon%u\n", decon->id);
 
@@ -173,7 +181,8 @@
 
 void handle_histogram_event(struct exynos_dqe *dqe)
 {
-	struct exynos_drm_pending_histogram_event *e = dqe->state.event;
+	/* This function runs in interrupt context */
+	struct exynos_drm_pending_histogram_event *e;
 	struct drm_device *dev = dqe->decon->drm_dev;
 	uint32_t id, crtc_id;
 
@@ -814,6 +823,7 @@
 	dqe->funcs = &dqe_funcs;
 	dqe->initialized = false;
 	dqe->decon = decon;
+	spin_lock_init(&dqe->state.histogram_slock);
 
 	scnprintf(dqe_name, MAX_DQE_NAME_SIZE, "dqe%u", decon->id);
 	dqe->dqe_class = class_create(THIS_MODULE, dqe_name);
diff --git a/samsung/exynos_drm_dqe.h b/samsung/exynos_drm_dqe.h
index 0d440d9..d578114 100644
--- a/samsung/exynos_drm_dqe.h
+++ b/samsung/exynos_drm_dqe.h
@@ -40,6 +40,7 @@
 	struct histogram_bins *bins;
 	struct exynos_drm_pending_histogram_event *event;
 	u32 histogram_threshold;
+	spinlock_t histogram_slock;
 	enum exynos_prog_pos histogram_pos;
 	bool rcd_enabled;
 	struct drm_gem_object *cgc_gem;