drm/msm/sde: match xlog features in evtlog

Upgrade event log facility with xlog feature set which supports
variable arguments and other features required. evtlog now
registers debugfs at /sys/kernel/debug/dri/0/evtlog. It can be
enabled by echo 1 into the enable node, and dumped using the
dump node. Move evtlog support into sde layer since only sde
uses it.

Change-Id: I51f8577a0e626ab53601e07a16cefe8da90125e1
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index cb3b6ab..8ef30cc 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -44,7 +44,8 @@
 	sde/sde_connector.o \
 	sde/sde_backlight.o \
 	sde/sde_color_processing.o \
-	sde/sde_vbif.o
+	sde/sde_vbif.o \
+	sde_dbg_evtlog.o
 
 # use drm gpu driver only if qcom_kgsl driver not available
 ifneq ($(CONFIG_QCOM_KGSL),y)
@@ -136,7 +137,6 @@
 	msm_perf.o \
 	msm_rd.o \
 	msm_ringbuffer.o \
-	msm_evtlog.o \
 	msm_prop.o
 
 obj-$(CONFIG_DRM_MSM)	+= msm_drm.o
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index d127f2c..e6d8ffe 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -248,7 +248,9 @@
 			       priv->vram.paddr, attrs);
 	}
 
-	component_unbind_all(dev, ddev);
+	sde_evtlog_destroy();
+
+	component_unbind_all(dev->dev, dev);
 
 	msm_mdss_destroy(ddev);
 
@@ -431,7 +433,11 @@
 	if (ret)
 		goto fail;
 
-	msm_gem_shrinker_init(ddev);
+	ret = sde_evtlog_init(dev->primary->debugfs_root);
+	if (ret) {
+		dev_err(dev->dev, "failed to init evtlog: %d\n", ret);
+		goto fail;
+	}
 
 	switch (get_mdp_ver(pdev)) {
 	case KMS_MDP4:
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 6ff191f..d8de7e0 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -44,7 +44,6 @@
 #include <drm/msm_drm.h>
 #include <drm/drm_gem.h>
 
-#include "msm_evtlog.h"
 #include "sde_power_handle.h"
 
 #define GET_MAJOR_REV(rev)		((rev) >> 28)
@@ -317,28 +316,10 @@
 
 	struct msm_vblank_ctrl vblank_ctrl;
 
-	/* task holding struct_mutex.. currently only used in submit path
-	 * to detect and reject faults from copy_from_user() for submit
-	 * ioctl.
-	 */
-	struct task_struct *struct_mutex_task;
-
-	struct msm_evtlog evtlog;
+	/* list of clients waiting for events */
+	struct list_head client_event_list;
 };
 
-/* Helper macro for accessing msm_drm_private's event log */
-#define MSM_EVTMSG(dev, msg, x, y)  do {                                       \
-		if ((dev) && ((struct drm_device *)(dev))->dev_private)        \
-			msm_evtlog_sample(&((struct msm_drm_private *)         \
-					((struct drm_device *)                 \
-					(dev))->dev_private)->evtlog, __func__,\
-					(msg), (uint64_t)(x), (uint64_t)(y),   \
-					__LINE__);                             \
-	} while (0)
-
-/* Helper macro for accessing msm_drm_private's event log */
-#define MSM_EVT(dev, x, y) MSM_EVTMSG((dev), 0, (x), (y))
-
 struct msm_format {
 	uint32_t pixel_format;
 };
@@ -363,6 +344,7 @@
 		struct drm_atomic_state *state, bool nonblock);
 
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
+void msm_unregister_all_mmu(struct drm_device *dev);
 
 void msm_gem_submit_free(struct msm_gem_submit *submit);
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/msm/msm_evtlog.h b/drivers/gpu/drm/msm/msm_evtlog.h
deleted file mode 100644
index 8351289..0000000
--- a/drivers/gpu/drm/msm/msm_evtlog.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef MSM_MSM_EVTLOG_H_
-#define MSM_MSM_EVTLOG_H_
-
-#include <linux/ktime.h>
-#include <linux/atomic.h>
-#include <linux/dcache.h>
-
-/**
- * struct msm_evtlog_evt - Event log entry
- * @ktime:     Timestamp of event
- * @func:      Calling function name
- * @msg:       User provided string
- * @val1:      User provided value
- * @val2:      User provided value
- * @line:      Line number of caller
- * @pid:       Process id of logger
- */
-struct msm_evtlog_evt {
-	ktime_t ktime;
-	const char *func;
-	const char *msg;
-	uint64_t val1;
-	uint64_t val2;
-	uint32_t line;
-	uint32_t pid;
-};
-
-/**
- * struct msm_evtlog - current driver state information
- * @events:    Pointer to dynamically allocated event log buffer
- * @cnt:       Atomic number of events since clear. Can be used to calculate
- *             the current index. Note: The count does not wrap.
- *             Reset the event log by setting to zero.
- *             Used for lock-less producer synchronization.
- * @size:      Size of events array. Must be power of 2 to facilitate fast
- *             increments by using a bitmask to get rollover.
- * @dentry:    Filesystem entry of debugfs registration
- */
-struct msm_evtlog {
-	struct msm_evtlog_evt *events;
-	atomic_t cnt;
-	unsigned long size;
-	struct dentry *dentry;
-};
-
-/**
- * msm_evtlog_init() - Create an event log, registered with debugfs.
- * @log:     Event log handle
- * @size:    Max # of events in buffer. Will be rounded up to power of 2.
- * @parent:  Parent directory entry for debugfs registration
- *
- * Return: error code.
- */
-int msm_evtlog_init(struct msm_evtlog *log, int size, struct dentry *parent);
-
-/**
- * msm_evtlog_destroy() - Destroy event log
- * @log:            Event log handle
- *
- * Unregisters debugfs node and frees memory.
- * Caller needs to make sure that log sampling has stopped.
- */
-void msm_evtlog_destroy(struct msm_evtlog *log);
-
-/**
- * msm_evtlog_sample() - Add entry to the event log
- * @evtlog:            Event log handle
- * @func:              Calling function name
- * @msg:               User provided string
- * @val1:              User provided value
- * @val2:              User provided value
- * @line:              Line number of caller
- */
-void msm_evtlog_sample(
-		struct msm_evtlog *log,
-		const char *func,
-		const char *msg,
-		uint64_t val1,
-		uint64_t val2,
-		uint32_t line);
-
-#endif /* MSM_MSM_EVTLOG_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 6bc69cb..ac9997c 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -519,7 +519,8 @@
 			"conn%u",
 			c_conn->base.base.id);
 
-	rc = sde_fence_init(dev, &c_conn->retire_fence, c_conn->name);
+	rc = sde_fence_init(&c_conn->retire_fence, c_conn->name,
+			c_conn->base.base.id);
 	if (rc) {
 		SDE_ERROR("failed to init fence, %d\n", rc);
 		goto error_cleanup_conn;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index 0d100e7..502a7fa 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -95,7 +95,7 @@
 			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
 
 	spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
-	MSM_EVTMSG(sde_kms->dev, NULL, irq_idx,
+	SDE_EVT32(irq_idx,
 			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
 	if (atomic_inc_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 1) {
 		ret = sde_kms->hw_intr->ops.enable_irq(
@@ -157,7 +157,7 @@
 			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
 
 	spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
-	MSM_EVTMSG(sde_kms->dev, NULL, irq_idx,
+	SDE_EVT32(irq_idx,
 			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
 	if (atomic_dec_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) {
 		ret = sde_kms->hw_intr->ops.disable_irq(
@@ -218,7 +218,7 @@
 	SDE_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
 
 	spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
-	MSM_EVTMSG(sde_kms->dev, NULL, irq_idx, register_irq_cb);
+	SDE_EVT32(irq_idx, register_irq_cb);
 	list_del_init(&register_irq_cb->list);
 	list_add_tail(&register_irq_cb->list,
 			&sde_kms->irq_obj.irq_cb_tbl[irq_idx]);
@@ -246,7 +246,7 @@
 	SDE_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx);
 
 	spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
-	MSM_EVTMSG(sde_kms->dev, NULL, irq_idx, register_irq_cb);
+	SDE_EVT32(irq_idx, register_irq_cb);
 	list_del_init(&register_irq_cb->list);
 	/* empty callback list but interrupt is still enabled */
 	if (list_empty(&sde_kms->irq_obj.irq_cb_tbl[irq_idx]) &&
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 0c0a5c3..237d9f4 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -310,7 +310,7 @@
 
 	sde_crtc = to_sde_crtc(crtc);
 	cstate = to_sde_crtc_state(crtc->state);
-	MSM_EVT(crtc->dev, crtc->base.id, 0);
+	SDE_EVT32(DRMID(crtc));
 
 	/* identify connectors attached to this crtc */
 	cstate->is_rt = false;
@@ -359,7 +359,7 @@
 			sde_crtc->event = NULL;
 			DRM_DEBUG_VBL("%s: send event: %pK\n",
 						sde_crtc->name, event);
-			MSM_EVT(crtc->dev, crtc->base.id, 0);
+			SDE_EVT32(DRMID(crtc));
 			drm_crtc_send_vblank_event(crtc, event);
 		}
 	}
@@ -379,7 +379,7 @@
 
 	drm_crtc_handle_vblank(crtc);
 	DRM_DEBUG_VBL("crtc%d\n", crtc->base.id);
-	MSM_EVT(crtc->dev, crtc->base.id, 0);
+	SDE_EVT32_IRQ(DRMID(crtc));
 }
 
 void sde_crtc_complete_commit(struct drm_crtc *crtc,
@@ -396,7 +396,7 @@
 
 	sde_crtc = to_sde_crtc(crtc);
 	cstate = to_sde_crtc_state(crtc->state);
-	MSM_EVT(crtc->dev, crtc->base.id, 0);
+	SDE_EVT32(DRMID(crtc));
 
 	/* signal output fence(s) at end of commit */
 	sde_fence_signal(&sde_crtc->output_fence, 0);
@@ -995,7 +995,7 @@
 		if (encoder->crtc != crtc)
 			continue;
 
-		MSM_EVT(crtc->dev, crtc->base.id, en);
+		SDE_EVT32(DRMID(crtc), en);
 
 		if (en)
 			sde_encoder_register_vblank_callback(encoder,
@@ -1376,8 +1376,8 @@
 	snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id);
 
 	/* initialize output fence support */
-	sde_fence_init(dev, &sde_crtc->output_fence, sde_crtc->name);
 	mutex_init(&sde_crtc->crtc_lock);
+	sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id);
 
 	/* initialize debugfs support */
 	_sde_crtc_init_debugfs(sde_crtc, kms);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 365d6f1..4032b98 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -286,7 +286,7 @@
 	sde_kms = to_sde_kms(priv->kms);
 	mode = &crtc_state->mode;
 	adj_mode = &crtc_state->adjusted_mode;
-	MSM_EVT(drm_enc->dev, 0, 0);
+	SDE_EVT32(DRMID(drm_enc));
 
 	/* perform atomic check on the first physical encoder (master) */
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -317,7 +317,7 @@
 		drm_mode_set_crtcinfo(adj_mode, 0);
 	}
 
-	MSM_EVT(drm_enc->dev, adj_mode->flags, adj_mode->private_flags);
+	SDE_EVT32(DRMID(drm_enc), adj_mode->flags, adj_mode->private_flags);
 
 	return ret;
 }
@@ -346,7 +346,7 @@
 	sde_kms = to_sde_kms(priv->kms);
 	connector_list = &sde_kms->dev->mode_config.connector_list;
 
-	MSM_EVT(drm_enc->dev, 0, 0);
+	SDE_EVT32(DRMID(drm_enc));
 
 	list_for_each_entry(conn_iter, connector_list, head)
 		if (conn_iter->encoder == drm_enc)
@@ -417,8 +417,7 @@
 	sde_kms = to_sde_kms(priv->kms);
 
 	SDE_DEBUG_ENC(sde_enc, "\n");
-
-	MSM_EVT(drm_enc->dev, 0, 0);
+	SDE_EVT32(DRMID(drm_enc));
 
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
 
@@ -472,7 +471,7 @@
 	priv = drm_enc->dev->dev_private;
 	sde_kms = to_sde_kms(priv->kms);
 
-	MSM_EVT(drm_enc->dev, 0, 0);
+	SDE_EVT32(DRMID(drm_enc));
 
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -576,7 +575,7 @@
 		return;
 	}
 	SDE_DEBUG_ENC(sde_enc, "\n");
-	MSM_EVT(drm_enc->dev, enable, 0);
+	SDE_EVT32(DRMID(drm_enc), enable);
 
 	spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
 	sde_enc->crtc_vblank_cb = vbl_cb;
@@ -606,7 +605,7 @@
 			sde_enc->pending_kickoff_mask &= ~(1 << i);
 			mask = sde_enc->pending_kickoff_mask;
 			spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
-			MSM_EVT(drm_enc->dev, i, mask);
+			SDE_EVT32(DRMID(drm_enc), i, mask);
 		}
 	}
 
@@ -641,7 +640,7 @@
 		ctl->ops.update_pending_flush(ctl, extra_flush_bits);
 
 	ctl->ops.trigger_flush(ctl);
-	MSM_EVT(drm_enc->dev, drm_enc->base.id, ctl->idx);
+	SDE_EVT32(DRMID(drm_enc), ctl->idx);
 }
 
 /**
@@ -676,9 +675,7 @@
 	}
 
 	if (phys_enc && phys_enc->parent)
-		MSM_EVT(phys_enc->parent->dev,
-				phys_enc->parent->base.id,
-				ctl_idx);
+		SDE_EVT32(DRMID(phys_enc->parent), ctl_idx);
 }
 
 /**
@@ -744,7 +741,7 @@
 	sde_enc = to_sde_encoder_virt(drm_enc);
 
 	SDE_DEBUG_ENC(sde_enc, "\n");
-	MSM_EVT(drm_enc->dev, 0, 0);
+	SDE_EVT32(DRMID(drm_enc));
 
 	spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
 	sde_enc->pending_kickoff_mask = 0;
@@ -765,7 +762,7 @@
 	}
 
 	spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
-	MSM_EVT(drm_enc->dev, sde_enc->pending_kickoff_mask, 0);
+	SDE_EVT32(DRMID(drm_enc), sde_enc->pending_kickoff_mask);
 	spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
 
 	/* Wait for the busy phys encs to be ready */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 3be4d27..37b949d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -34,8 +34,6 @@
 #define to_sde_encoder_phys_cmd(x) \
 	container_of(x, struct sde_encoder_phys_cmd, base)
 
-#define DEV(phy_enc) (phy_enc->parent->dev)
-
 #define WAIT_TIMEOUT_MSEC			100
 
 /*
@@ -111,7 +109,8 @@
 
 	phys_enc = &cmd_enc->base;
 	new_pending_cnt = atomic_dec_return(&cmd_enc->pending_cnt);
-	MSM_EVT(DEV(phys_enc), phys_enc->hw_pp->idx, new_pending_cnt);
+	SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx,
+		new_pending_cnt);
 
 	/* Signal any waiting atomic commit thread */
 	wake_up_all(&cmd_enc->pp_tx_done_wq);
@@ -384,7 +383,7 @@
 			__builtin_return_address(0),
 			enable, atomic_read(&phys_enc->vblank_refcount));
 
-	MSM_EVTMSG(phys_enc->parent->dev, NULL, enable,
+	SDE_EVT32(DRMID(phys_enc->parent), enable,
 			atomic_read(&phys_enc->vblank_refcount));
 
 	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
@@ -575,7 +574,8 @@
 				"pp %d needs to wait, new_pending_cnt %d",
 				phys_enc->hw_pp->idx - PINGPONG_0,
 				new_pending_cnt);
-	MSM_EVT(DEV(phys_enc), phys_enc->hw_pp->idx, new_pending_cnt);
+	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx,
+			new_pending_cnt);
 }
 
 static void sde_encoder_phys_cmd_init_ops(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index e45a62d..89b0d8e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -36,8 +36,6 @@
 #define to_sde_encoder_phys_vid(x) \
 	container_of(x, struct sde_encoder_phys_vid, base)
 
-#define DEV(phy_enc) (phy_enc->parent->dev)
-
 #define WAIT_TIMEOUT_MSEC 100
 
 static bool sde_encoder_phys_vid_is_master(
@@ -500,7 +498,7 @@
 			__builtin_return_address(0),
 			enable, atomic_read(&phys_enc->vblank_refcount));
 
-	MSM_EVTMSG(phys_enc->parent->dev, NULL, enable,
+	SDE_EVT32(DRMID(phys_enc->parent), enable,
 			atomic_read(&phys_enc->vblank_refcount));
 
 	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
@@ -685,18 +683,20 @@
 		return -EWOULDBLOCK;
 	}
 
-	MSM_EVTMSG(DEV(phys_enc), "waiting", 0, 0);
+	SDE_EVT32(DRMID(phys_enc->parent), vid_enc->hw_intf->idx,
+			SDE_EVTLOG_FUNC_ENTRY);
 
 	ret = wait_for_completion_timeout(&vid_enc->vblank_completion,
 			msecs_to_jiffies(WAIT_TIMEOUT_MSEC));
 	if (!ret) {
 		SDE_DEBUG_VIDENC(vid_enc, "wait %u ms timed out\n",
 				WAIT_TIMEOUT_MSEC);
-		MSM_EVTMSG(DEV(phys_enc), "wait_timeout", 0, 0);
+		SDE_EVT32(DRMID(phys_enc->parent), WAIT_TIMEOUT_MSEC);
 		return -ETIMEDOUT;
 	}
 
-	MSM_EVTMSG(DEV(phys_enc), "wait_done", 0, 0);
+	SDE_EVT32(DRMID(phys_enc->parent), vid_enc->hw_intf->idx,
+			SDE_EVTLOG_FUNC_EXIT);
 
 	return 0;
 }
@@ -734,7 +734,7 @@
 	 * Video encoders need to turn on their interfaces now
 	 */
 	if (phys_enc->enable_state == SDE_ENC_ENABLING) {
-		MSM_EVT(DEV(phys_enc), 0, 0);
+		SDE_EVT32(DRMID(phys_enc->parent), vid_enc->hw_intf->idx);
 		spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
 		vid_enc->hw_intf->ops.enable_timing(vid_enc->hw_intf, 1);
 		spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 1e5e186..970969b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -31,7 +31,7 @@
 #define to_sde_encoder_phys_wb(x) \
 	container_of(x, struct sde_encoder_phys_wb, base)
 
-#define DEV(phy_enc) (phy_enc->parent->dev)
+#define WBID(wb_enc) ((wb_enc) ? wb_enc->wb_dev->wb_idx : -1)
 
 /**
  * sde_encoder_phys_wb_is_master - report wb always as master encoder
@@ -676,13 +676,14 @@
 	if (WARN_ON(phys_enc->enable_state != SDE_ENC_ENABLED))
 		return -EWOULDBLOCK;
 
-	MSM_EVT(DEV(phys_enc), wb_enc->frame_count, 0);
+	SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count);
 
 	ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
 			msecs_to_jiffies(wb_enc->wbdone_timeout));
 
 	if (!ret) {
-		MSM_EVT(DEV(phys_enc), wb_enc->frame_count, 0);
+		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
+				wb_enc->frame_count);
 
 		irq_status = sde_core_irq_read(phys_enc->sde_kms,
 				wb_enc->irq_idx, true);
@@ -720,7 +721,8 @@
 			wb_enc->wb_dev->wb_idx - WB_0, wb_time);
 	}
 
-	MSM_EVT(DEV(phys_enc), wb_enc->frame_count, wb_time);
+	SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count,
+			wb_time);
 
 	return rc;
 }
@@ -760,7 +762,8 @@
 	/* vote for iommu/clk/bus */
 	wb_enc->start_time = ktime_get();
 
-	MSM_EVT(DEV(phys_enc), *need_to_wait, wb_enc->kickoff_count);
+	SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), *need_to_wait,
+			wb_enc->kickoff_count);
 }
 
 /**
@@ -774,7 +777,7 @@
 
 	SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
 
-	MSM_EVT(DEV(phys_enc), 0, 0);
+	SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc));
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index 23e5614..6db6f98 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -105,14 +105,15 @@
 /**
  * SDE_FENCE_TIMELINE_NAME - macro for accessing s/w timeline's name
  * @fence: Pointer to sde fence structure
+ * @drm_id: ID number of owning DRM Object
  * Returns: Pointer to timeline name string
  */
 #define SDE_FENCE_TIMELINE_NAME(fence) \
 	(((struct sw_sync_timeline *)fence->timeline)->obj.name)
 
-int sde_fence_init(void *dev,
-		struct sde_fence *fence,
-		const char *name)
+int sde_fence_init(struct sde_fence *fence,
+		const char *name,
+		uint32_t drm_id)
 {
 	if (!fence) {
 		SDE_ERROR("invalid argument(s)\n");
@@ -125,9 +126,9 @@
 		return -ENOMEM;
 	}
 
-	fence->dev = dev;
 	fence->commit_count = 0;
 	fence->done_count = 0;
+	fence->drm_id = drm_id;
 
 	mutex_init(&fence->fence_lock);
 	return 0;
@@ -155,10 +156,7 @@
 
 	mutex_lock(&fence->fence_lock);
 	++fence->commit_count;
-	MSM_EVTMSG(fence->dev,
-			SDE_FENCE_TIMELINE_NAME(fence),
-			fence->commit_count,
-			fence->done_count);
+	SDE_EVT32(fence->drm_id, fence->commit_count, fence->done_count);
 	mutex_unlock(&fence->fence_lock);
 	return 0;
 }
@@ -187,10 +185,7 @@
 				trigger_value);
 		*val = fd;
 
-		MSM_EVTMSG(fence->dev,
-				SDE_FENCE_TIMELINE_NAME(fence),
-				trigger_value,
-				fd);
+		SDE_EVT32(fence->drm_id, trigger_value, fd);
 		mutex_unlock(&fence->fence_lock);
 
 		if (fd >= 0)
@@ -228,11 +223,10 @@
 		else
 			sw_sync_timeline_inc(fence->timeline, (int)val);
 	}
-	MSM_EVTMSG(fence->dev,
-			SDE_FENCE_TIMELINE_NAME(fence),
-			fence->done_count,
-			((struct sw_sync_timeline *)
-				fence->timeline)->value);
+
+	SDE_EVT32(fence->drm_id, fence->done_count,
+			((struct sw_sync_timeline *) fence->timeline)->value);
+
 	mutex_unlock(&fence->fence_lock);
 }
 #endif
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index b5980b4..113d16b 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -85,30 +85,30 @@
 /**
  * struct sde_fence - output fence container structure
  * @timeline: Pointer to fence timeline
- * @dev: Pointer to drm device structure
  * @commit_count: Number of detected commits since bootup
  * @done_count: Number of completed commits since bootup
+ * @drm_id: ID number of owning DRM Object
  * @fence_lock: Mutex object to protect local fence variables
  */
 struct sde_fence {
 	void *timeline;
-	void *dev;
 	int32_t commit_count;
 	int32_t done_count;
+	uint32_t drm_id;
 	struct mutex fence_lock;
 };
 
 #if IS_ENABLED(CONFIG_SW_SYNC)
 /**
  * sde_fence_init - initialize fence object
- * @dev: Pointer to drm device structure
  * @fence: Pointer to crtc fence object
+ * @drm_id: ID number of owning DRM Object
  * @name: Timeline name
  * Returns: Zero on success
  */
-int sde_fence_init(void *dev,
-		struct sde_fence *fence,
-		const char *name);
+int sde_fence_init(struct sde_fence *fence,
+		const char *name,
+		uint32_t drm_id);
 
 /**
  * sde_fence_deinit - deinit fence container
@@ -139,9 +139,9 @@
  */
 void sde_fence_signal(struct sde_fence *fence, bool is_error);
 #else
-static inline int sde_fence_init(void *dev,
-		struct sde_fence *fence,
-		const char *name)
+static inline int sde_fence_init(struct sde_fence *fence,
+		const char *name,
+		uint32_t drm_id)
 {
 	/* do nothing */
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index e8816e6..77691a1 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -244,16 +244,16 @@
 
 static void sde_commit(struct msm_kms *kms, struct drm_atomic_state *old_state)
 {
-	struct sde_kms *sde_kms = to_sde_kms(kms);
 	struct drm_crtc *crtc;
 	struct drm_crtc_state *old_crtc_state;
 	int i;
 
-	MSM_EVT(sde_kms->dev, 0, 0);
-
-	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
-		if (crtc->state->active)
+	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+		if (crtc->state->active) {
+			SDE_EVT32(DRMID(crtc));
 			sde_crtc_commit_kickoff(crtc);
+		}
+	}
 }
 
 static void sde_complete_commit(struct msm_kms *kms,
@@ -270,7 +270,7 @@
 		sde_crtc_complete_commit(crtc, old_crtc_state);
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
 
-	MSM_EVT(sde_kms->dev, 0, 0);
+	SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
 }
 
 static void sde_wait_for_commit_done(struct msm_kms *kms,
@@ -303,7 +303,7 @@
 		 * For example, wait for vsync in case of video mode panels
 		 * This should be a no-op for command mode panels
 		 */
-		MSM_EVT(crtc->dev, crtc->base.id, 0);
+		SDE_EVT32(DRMID(crtc));
 		ret = sde_encoder_wait_for_commit_done(encoder);
 		if (ret && ret != -EWOULDBLOCK) {
 			DRM_ERROR("wait for commit done returned %d\n", ret);
@@ -906,9 +906,6 @@
 	 *       'primary' is already created.
 	 */
 	sde_debugfs_init(sde_kms);
-	msm_evtlog_init(&priv->evtlog, SDE_EVTLOG_SIZE,
-			sde_debugfs_get_root(sde_kms));
-	MSM_EVT(dev, 0, 0);
 
 	/*
 	 * modeset_init should create the DRM related objects i.e. CRTCs,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index c35a32d..c77647e 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -16,6 +16,7 @@
 #include "msm_drv.h"
 #include "msm_kms.h"
 #include "msm_mmu.h"
+#include "sde_dbg.h"
 #include "sde_hw_catalog.h"
 #include "sde_hw_ctl.h"
 #include "sde_hw_lm.h"
@@ -26,6 +27,8 @@
 #include "sde_power_handle.h"
 #include "sde_irq.h"
 
+#define DRMID(x) ((x) ? (x)->base.id : -1)
+
 /**
  * SDE_DEBUG - macro for kms/plane/crtc/encoder/connector logs
  * @fmt: Pointer to format string
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ee98bb0..8dc31a5 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -491,10 +491,7 @@
 			prefix = sde_sync_get_name_prefix(input_fence);
 			ret = sde_sync_wait(input_fence, wait_ms);
 
-			MSM_EVT(plane->dev,
-				plane->base.id,
-				(uint64_t)-ret << (sizeof(uint32_t) * CHAR_BIT)
-				| prefix);
+			SDE_EVT32(DRMID(plane), -ret, prefix);
 
 			switch (ret) {
 			case 0:
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index e1e63dd..075e9d6 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -92,29 +92,50 @@
 	void *hw;
 };
 
-static void _sde_rm_print_rsvps(struct sde_rm *rm, const char *msg)
+/**
+ * sde_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging
+ */
+enum sde_rm_dbg_rsvp_stage {
+	SDE_RM_STAGE_BEGIN,
+	SDE_RM_STAGE_AFTER_CLEAR,
+	SDE_RM_STAGE_AFTER_RSVPNEXT,
+	SDE_RM_STAGE_FINAL
+};
+
+static void _sde_rm_print_rsvps(
+		struct sde_rm *rm,
+		enum sde_rm_dbg_rsvp_stage stage)
 {
 	struct sde_rm_rsvp *rsvp;
 	struct sde_rm_hw_blk *blk;
 	enum sde_hw_blk_type type;
 
-	SDE_DEBUG("%s\n", msg);
+	SDE_DEBUG("%d\n", stage);
 
-	list_for_each_entry(rsvp, &rm->rsvps, list)
-		SDE_DEBUG("%s rsvp[s%ue%u] topology %d\n", msg, rsvp->seq,
+	list_for_each_entry(rsvp, &rm->rsvps, list) {
+		SDE_DEBUG("%d rsvp[s%ue%u] topology %d\n", stage, rsvp->seq,
 				rsvp->enc_id, rsvp->topology);
+		SDE_EVT32(stage, rsvp->seq, rsvp->enc_id, rsvp->topology);
+	}
 
 	for (type = 0; type < SDE_HW_BLK_MAX; type++) {
 		list_for_each_entry(blk, &rm->hw_blks[type], list) {
 			if (!blk->rsvp && !blk->rsvp_nxt)
 				continue;
 
-			SDE_DEBUG("%s rsvp[s%ue%u->s%ue%u] %s %d\n", msg,
+			SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %s %d\n", stage,
 				(blk->rsvp) ? blk->rsvp->seq : 0,
 				(blk->rsvp) ? blk->rsvp->enc_id : 0,
 				(blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
 				(blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
 				blk->type_name, blk->id);
+
+			SDE_EVT32(stage,
+				(blk->rsvp) ? blk->rsvp->seq : 0,
+				(blk->rsvp) ? blk->rsvp->enc_id : 0,
+				(blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
+				(blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
+				blk->type, blk->id);
 		}
 	}
 }
@@ -623,13 +644,11 @@
 
 		lm[i]->rsvp_nxt = rsvp;
 		pp[i]->rsvp_nxt = rsvp;
-		MSM_EVTMSG(rm->dev, lm[i]->type_name, rsvp->enc_id, lm[i]->id);
-		MSM_EVTMSG(rm->dev, pp[i]->type_name, rsvp->enc_id, pp[i]->id);
-		if (dspp[i]) {
+		if (dspp[i])
 			dspp[i]->rsvp_nxt = rsvp;
-			MSM_EVTMSG(rm->dev, dspp[i]->type_name, rsvp->enc_id,
-					dspp[i]->id);
-		}
+
+		SDE_EVT32(lm[i]->type, rsvp->enc_id, lm[i]->id, pp[i]->id,
+				dspp[i] ? dspp[i]->id : 0);
 	}
 
 	return 0;
@@ -678,8 +697,7 @@
 
 	for (i = 0; i < ARRAY_SIZE(ctls) && i < reqs->num_ctl; i++) {
 		ctls[i]->rsvp_nxt = rsvp;
-		MSM_EVTMSG(rm->dev, ctls[i]->type_name, rsvp->enc_id,
-				ctls[i]->id);
+		SDE_EVT32(ctls[i]->type, rsvp->enc_id, ctls[i]->id);
 	}
 
 	return 0;
@@ -716,8 +734,7 @@
 			continue;
 
 		iter.blk->rsvp_nxt = rsvp;
-		MSM_EVTMSG(rm->dev, iter.blk->type_name, rsvp->enc_id,
-				iter.blk->id);
+		SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id);
 		break;
 	}
 
@@ -751,8 +768,7 @@
 		}
 
 		iter.blk->rsvp_nxt = rsvp;
-		MSM_EVTMSG(rm->dev, iter.blk->type_name,
-				rsvp->enc_id, iter.blk->id);
+		SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id);
 		break;
 	}
 
@@ -951,9 +967,10 @@
 			mode->hdisplay, rm->lm_max_width);
 	SDE_DEBUG("num_lm %d num_ctl %d topology_name %d\n", reqs->num_lm,
 			reqs->num_ctl, reqs->top_name);
-	MSM_EVT(rm->dev, mode->hdisplay, rm->lm_max_width);
-	MSM_EVT(rm->dev, reqs->num_lm, reqs->top_ctrl);
-	MSM_EVT(rm->dev, reqs->top_name, 0);
+	SDE_DEBUG("num_lm %d topology_name %d\n", reqs->num_lm,
+			reqs->top_name);
+	SDE_EVT32(mode->hdisplay, rm->lm_max_width, reqs->num_lm,
+			reqs->top_ctrl, reqs->top_name, reqs->num_ctl);
 
 	return 0;
 }
@@ -1111,7 +1128,7 @@
 	if (!ret) {
 		SDE_DEBUG("rsrv enc %d topology %d\n", rsvp->enc_id,
 				rsvp->topology);
-		MSM_EVT(rm->dev, rsvp->enc_id, rsvp->topology);
+		SDE_EVT32(rsvp->enc_id, rsvp->topology);
 	}
 
 	return ret;
@@ -1151,9 +1168,9 @@
 	SDE_DEBUG("reserving hw for conn %d enc %d crtc %d test_only %d\n",
 			conn_state->connector->base.id, enc->base.id,
 			crtc_state->crtc->base.id, test_only);
-	MSM_EVT(rm->dev, enc->base.id, conn_state->connector->base.id);
+	SDE_EVT32(enc->base.id, conn_state->connector->base.id);
 
-	_sde_rm_print_rsvps(rm, "begin_reserve");
+	_sde_rm_print_rsvps(rm, SDE_RM_STAGE_BEGIN);
 
 	ret = _sde_rm_populate_requirements(rm, enc, crtc_state,
 			conn_state, &reqs);
@@ -1188,14 +1205,14 @@
 				rsvp_cur->seq, rsvp_cur->enc_id);
 		_sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector);
 		rsvp_cur = NULL;
-		_sde_rm_print_rsvps(rm, "post_clear");
+		_sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_CLEAR);
 	}
 
 	/* Check the proposed reservation, store it in hw's "next" field */
 	ret = _sde_rm_make_next_rsvp(rm, enc, crtc_state, conn_state,
 			rsvp_nxt, &reqs);
 
-	_sde_rm_print_rsvps(rm, "new_rsvp_next");
+	_sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_RSVPNEXT);
 
 	if (ret) {
 		SDE_ERROR("failed to reserve hw resources: %d\n", ret);
@@ -1219,7 +1236,7 @@
 		ret = _sde_rm_commit_rsvp(rm, rsvp_nxt, conn_state);
 	}
 
-	_sde_rm_print_rsvps(rm, "final");
+	_sde_rm_print_rsvps(rm, SDE_RM_STAGE_FINAL);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index 6060bde..3171fcb 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -198,7 +198,7 @@
 
 	ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id);
 	if (ret)
-		MSM_EVT(sde_kms->dev, vbif->idx, params->xin_id);
+		SDE_EVT32(vbif->idx, params->xin_id);
 
 	vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);
 
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
new file mode 100644
index 0000000..f543168
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SDE_DBG_H_
+#define SDE_DBG_H_
+
+#include <stdarg.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+
+#define SDE_EVTLOG_DATA_LIMITER	(-1)
+#define SDE_EVTLOG_FUNC_ENTRY	0x1111
+#define SDE_EVTLOG_FUNC_EXIT	0x2222
+
+enum sde_dbg_evtlog_flag {
+	SDE_EVTLOG_DEFAULT = BIT(0),
+	SDE_EVTLOG_IRQ = BIT(1),
+	SDE_EVTLOG_ALL = BIT(7)
+};
+
+/**
+ * SDE_EVT32 - Write an list of 32bit values as an event into the event log
+ * ... - variable arguments
+ */
+#define SDE_EVT32(...) sde_evtlog(__func__, __LINE__, SDE_EVTLOG_DEFAULT, \
+		##__VA_ARGS__, SDE_EVTLOG_DATA_LIMITER)
+#define SDE_EVT32_IRQ(...) sde_evtlog(__func__, __LINE__, SDE_EVTLOG_IRQ, \
+		##__VA_ARGS__, SDE_EVTLOG_DATA_LIMITER)
+
+
+#if defined(CONFIG_DEBUG_FS)
+
+int sde_evtlog_init(struct dentry *debugfs_root);
+void sde_evtlog_destroy(void);
+void sde_evtlog(const char *name, int line, int flag, ...);
+#else
+
+static inline int sde_evtlog_init(struct dentry *debugfs_root)
+{
+	return 0;
+}
+static inline void sde_evtlog(const char *name, int line,  flag, ...) { }
+void sde_evtlog_destroy(void) { }
+#endif
+
+#endif /* SDE_DBG_H_ */
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
new file mode 100644
index 0000000..d27e144
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"sde_evtlog:[%s] " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/dma-buf.h>
+
+#include "sde_dbg.h"
+#include "sde_trace.h"
+
+#ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG
+#define EVTLOG_DEFAULT_ENABLE 1
+#else
+#define EVTLOG_DEFAULT_ENABLE 0
+#endif
+
+#define EVTLOG_DEFAULT_PANIC 1
+
+/*
+ * evtlog will print this number of entries when it is called through
+ * sysfs node or panic. This prevents kernel log from evtlog message
+ * flood.
+ */
+#define SDE_EVTLOG_PRINT_ENTRY	256
+
+/*
+ * evtlog keeps this number of entries in memory for debug purpose. This
+ * number must be greater than print entry to prevent out of bound evtlog
+ * entry array access.
+ */
+#define SDE_EVTLOG_ENTRY	(SDE_EVTLOG_PRINT_ENTRY * 4)
+#define SDE_EVTLOG_MAX_DATA 15
+#define SDE_EVTLOG_BUF_MAX 512
+#define SDE_EVTLOG_BUF_ALIGN 32
+
+DEFINE_SPINLOCK(sde_evtloglock);
+
+struct tlog {
+	u32 counter;
+	s64 time;
+	const char *name;
+	int line;
+	u32 data[SDE_EVTLOG_MAX_DATA];
+	u32 data_cnt;
+	int pid;
+};
+
+static struct sde_dbg_evtlog {
+	struct tlog logs[SDE_EVTLOG_ENTRY];
+	u32 first;
+	u32 last;
+	u32 curr;
+	struct dentry *evtlog;
+	u32 evtlog_enable;
+	u32 panic_on_err;
+} sde_dbg_evtlog;
+
+static inline bool sde_evtlog_is_enabled(u32 flag)
+{
+	return (flag & sde_dbg_evtlog.evtlog_enable) ||
+		(flag == SDE_EVTLOG_ALL && sde_dbg_evtlog.evtlog_enable);
+}
+
+void sde_evtlog(const char *name, int line, int flag, ...)
+{
+	unsigned long flags;
+	int i, val = 0;
+	va_list args;
+	struct tlog *log;
+
+	if (!sde_evtlog_is_enabled(flag))
+		return;
+
+	spin_lock_irqsave(&sde_evtloglock, flags);
+	log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.curr];
+	log->time = ktime_to_us(ktime_get());
+	log->name = name;
+	log->line = line;
+	log->data_cnt = 0;
+	log->pid = current->pid;
+
+	va_start(args, flag);
+	for (i = 0; i < SDE_EVTLOG_MAX_DATA; i++) {
+
+		val = va_arg(args, int);
+		if (val == SDE_EVTLOG_DATA_LIMITER)
+			break;
+
+		log->data[i] = val;
+	}
+	va_end(args);
+	log->data_cnt = i;
+	sde_dbg_evtlog.curr = (sde_dbg_evtlog.curr + 1) % SDE_EVTLOG_ENTRY;
+	sde_dbg_evtlog.last++;
+
+	trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
+			i > 1 ? log->data[1] : 0);
+
+	spin_unlock_irqrestore(&sde_evtloglock, flags);
+}
+
+/* always dump the last entries which are not dumped yet */
+static bool __sde_evtlog_dump_calc_range(void)
+{
+	static u32 next;
+	bool need_dump = true;
+	unsigned long flags;
+	struct sde_dbg_evtlog *evtlog = &sde_dbg_evtlog;
+
+	spin_lock_irqsave(&sde_evtloglock, flags);
+
+	evtlog->first = next;
+
+	if (evtlog->last == evtlog->first) {
+		need_dump = false;
+		goto dump_exit;
+	}
+
+	if (evtlog->last < evtlog->first) {
+		evtlog->first %= SDE_EVTLOG_ENTRY;
+		if (evtlog->last < evtlog->first)
+			evtlog->last += SDE_EVTLOG_ENTRY;
+	}
+
+	if ((evtlog->last - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) {
+		pr_warn("evtlog buffer overflow before dump: %d\n",
+			evtlog->last - evtlog->first);
+		evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY;
+	}
+	next = evtlog->first + 1;
+
+dump_exit:
+	spin_unlock_irqrestore(&sde_evtloglock, flags);
+
+	return need_dump;
+}
+
+static ssize_t sde_evtlog_dump_entry(char *evtlog_buf, ssize_t evtlog_buf_size)
+{
+	int i;
+	ssize_t off = 0;
+	struct tlog *log, *prev_log;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sde_evtloglock, flags);
+
+	log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.first %
+		SDE_EVTLOG_ENTRY];
+
+	prev_log = &sde_dbg_evtlog.logs[(sde_dbg_evtlog.first - 1) %
+		SDE_EVTLOG_ENTRY];
+
+	off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d",
+		log->name, log->line);
+
+	if (off < SDE_EVTLOG_BUF_ALIGN) {
+		memset((evtlog_buf + off), 0x20, (SDE_EVTLOG_BUF_ALIGN - off));
+		off = SDE_EVTLOG_BUF_ALIGN;
+	}
+
+	off += snprintf((evtlog_buf + off), (evtlog_buf_size - off),
+		"=>[%-8d:%-11llu:%9llu][%-4d]:", sde_dbg_evtlog.first,
+		log->time, (log->time - prev_log->time), log->pid);
+
+	for (i = 0; i < log->data_cnt; i++)
+		off += snprintf((evtlog_buf + off), (evtlog_buf_size - off),
+			"%x ", log->data[i]);
+
+	off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n");
+
+	spin_unlock_irqrestore(&sde_evtloglock, flags);
+
+	return off;
+}
+
+static void sde_evtlog_dump_all(void)
+{
+	char evtlog_buf[SDE_EVTLOG_BUF_MAX];
+
+	while (__sde_evtlog_dump_calc_range()) {
+		sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX);
+		pr_info("%s", evtlog_buf);
+	}
+}
+
+static int sde_evtlog_dump_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff,
+		size_t count, loff_t *ppos)
+{
+	ssize_t len = 0;
+	char evtlog_buf[SDE_EVTLOG_BUF_MAX];
+
+	if (__sde_evtlog_dump_calc_range()) {
+		len = sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX);
+		if (copy_to_user(buff, evtlog_buf, len))
+			return -EFAULT;
+		*ppos += len;
+	}
+
+	return len;
+}
+
+static ssize_t sde_evtlog_dump_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	sde_evtlog_dump_all();
+
+	if (sde_dbg_evtlog.panic_on_err)
+		panic("sde");
+
+	return count;
+}
+
+static const struct file_operations sde_evtlog_fops = {
+	.open = sde_evtlog_dump_open,
+	.read = sde_evtlog_dump_read,
+	.write = sde_evtlog_dump_write,
+};
+
+int sde_evtlog_init(struct dentry *debugfs_root)
+{
+	int i;
+
+	sde_dbg_evtlog.evtlog = debugfs_create_dir("evt_dbg", debugfs_root);
+	if (IS_ERR_OR_NULL(sde_dbg_evtlog.evtlog)) {
+		pr_err("debugfs_create_dir fail, error %ld\n",
+		       PTR_ERR(sde_dbg_evtlog.evtlog));
+		sde_dbg_evtlog.evtlog = NULL;
+		return -ENODEV;
+	}
+
+	for (i = 0; i < SDE_EVTLOG_ENTRY; i++)
+		sde_dbg_evtlog.logs[i].counter = i;
+
+	debugfs_create_file("dump", 0644, sde_dbg_evtlog.evtlog, NULL,
+						&sde_evtlog_fops);
+	debugfs_create_u32("enable", 0644, sde_dbg_evtlog.evtlog,
+			    &sde_dbg_evtlog.evtlog_enable);
+	debugfs_create_u32("panic", 0644, sde_dbg_evtlog.evtlog,
+			    &sde_dbg_evtlog.panic_on_err);
+
+	sde_dbg_evtlog.evtlog_enable = EVTLOG_DEFAULT_ENABLE;
+	sde_dbg_evtlog.panic_on_err = EVTLOG_DEFAULT_PANIC;
+
+	pr_info("evtlog_status: enable:%d, panic:%d\n",
+		sde_dbg_evtlog.evtlog_enable, sde_dbg_evtlog.panic_on_err);
+
+	return 0;
+}
+
+void sde_evtlog_destroy(void)
+{
+	debugfs_remove(sde_dbg_evtlog.evtlog);
+}