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;