OSDN Git Service

drm/msm/sde: add debugfs nodes for underruns debug
authorLakshmi Narayana Kalavala <lkalaval@codeaurora.org>
Wed, 21 Feb 2018 01:55:26 +0000 (17:55 -0800)
committerLakshmi Narayana Kalavala <lkalaval@codeaurora.org>
Sat, 17 Mar 2018 00:23:52 +0000 (17:23 -0700)
This change adds debugfs nodes for debugging underruns,
after this change following commands are supported:
1. To enable the underrun ftrace:
echo 1 > /d/tracing/events/sde/sde_encoder_underrun/enable
2. To enable feature that disables the ftraces once the
underrun happens:
echo 1 > /d/dri/0/debug/dbg_ctrl
3. To enable the panic in the device when underrun happens:
echo 2 > /d/dri/0/debug/dbg_ctrl
4. To enable both of the above options:
echo 3 > /d/dri/0/debug/dbg_ctrl

Change-Id: Id9f407edb0908a5f8454f08d63c356dc8f04d353
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
Signed-off-by: Jayant Shekhar <jshekhar@codeaurora.org>
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
drivers/gpu/drm/msm/sde/sde_encoder.c
drivers/gpu/drm/msm/sde/sde_trace.h
drivers/gpu/drm/msm/sde_dbg.c
drivers/gpu/drm/msm/sde_dbg.h

index 6e4de62..fa17768 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -602,6 +602,12 @@ static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc,
        SDE_ATRACE_BEGIN("encoder_underrun_callback");
        atomic_inc(&phy_enc->underrun_cnt);
        SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt));
+
+       trace_sde_encoder_underrun(DRMID(drm_enc),
+               atomic_read(&phy_enc->underrun_cnt));
+       SDE_DBG_CTRL("stop_ftrace");
+       SDE_DBG_CTRL("panic_underrun");
+
        SDE_ATRACE_END("encoder_underrun_callback");
 }
 
index 2a4e6b5..d28562e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -125,6 +125,22 @@ TRACE_EVENT(sde_cmd_release_bw,
        TP_printk("crtc:%d", __entry->crtc_id)
 );
 
+TRACE_EVENT(sde_encoder_underrun,
+       TP_PROTO(u32 enc_id, u32 underrun_cnt),
+       TP_ARGS(enc_id, underrun_cnt),
+       TP_STRUCT__entry(
+                       __field(u32, enc_id)
+                       __field(u32, underrun_cnt)
+       ),
+       TP_fast_assign(
+                       __entry->enc_id = enc_id;
+                       __entry->underrun_cnt = underrun_cnt;
+
+       ),
+       TP_printk("enc:%d underrun_cnt:%d", __entry->enc_id,
+               __entry->underrun_cnt)
+);
+
 TRACE_EVENT(sde_mark_write,
        TP_PROTO(int pid, const char *name, bool trace_begin),
        TP_ARGS(pid, name, trace_begin),
index ea13361..0984ce8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2018, 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
@@ -57,6 +57,9 @@
 
 /* print debug ranges in groups of 4 u32s */
 #define REG_DUMP_ALIGN         16
+#define DBG_CTRL_STOP_FTRACE        BIT(0)
+#define DBG_CTRL_PANIC_UNDERRUN     BIT(1)
+#define DBG_CTRL_MAX                BIT(2)
 
 /**
  * struct sde_dbg_reg_offset - tracking for start and end of region
@@ -180,6 +183,7 @@ static struct sde_dbg_base {
 
        struct sde_dbg_sde_debug_bus dbgbus_sde;
        struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt;
+       u32 debugfs_ctrl;
 } sde_dbg_base;
 
 /* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
@@ -1557,6 +1561,45 @@ void sde_dbg_dump(bool queue_work, const char *name, ...)
        }
 }
 
+void sde_dbg_ctrl(const char *name, ...)
+{
+       int i = 0;
+       va_list args;
+       char *blk_name = NULL;
+
+
+       /* no debugfs controlled events are enabled, just return */
+       if (!sde_dbg_base.debugfs_ctrl)
+               return;
+
+       va_start(args, name);
+
+       while ((blk_name = va_arg(args, char*))) {
+               if (i++ >= SDE_EVTLOG_MAX_DATA) {
+                       pr_err("could not parse all dbg arguments\n");
+                       break;
+               }
+
+               if (IS_ERR_OR_NULL(blk_name))
+                       break;
+
+               if (!strcmp(blk_name, "stop_ftrace") &&
+                               sde_dbg_base.debugfs_ctrl &
+                               DBG_CTRL_STOP_FTRACE) {
+                       pr_debug("tracing off\n");
+                       tracing_off();
+               }
+
+               if (!strcmp(blk_name, "panic_underrun") &&
+                               sde_dbg_base.debugfs_ctrl &
+                               DBG_CTRL_PANIC_UNDERRUN) {
+                       pr_debug("panic underrun\n");
+                       panic("underrun");
+               }
+       }
+
+}
+
 /*
  * sde_dbg_debugfs_open - debugfs open handler for evtlog dump
  * @inode: debugfs inode
@@ -1621,6 +1664,82 @@ static const struct file_operations sde_evtlog_fops = {
        .write = sde_evtlog_dump_write,
 };
 
+/**
+ * sde_dbg_ctrl_read - debugfs read handler for debug ctrl read
+ * @file: file handler
+ * @buff: user buffer content for debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_ctrl_read(struct file *file, char __user *buff,
+               size_t count, loff_t *ppos)
+{
+       ssize_t len = 0;
+       char buf[24] = {'\0'};
+
+       if (!buff || !ppos)
+               return -EINVAL;
+
+       if (*ppos)
+               return 0;       /* the end */
+
+       len = snprintf(buf, sizeof(buf), "0x%x\n", sde_dbg_base.debugfs_ctrl);
+       pr_debug("%s: ctrl:0x%x len:0x%zx\n",
+               __func__, sde_dbg_base.debugfs_ctrl, len);
+
+       if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) {
+               pr_err("error copying the buffer! count:0x%zx\n", count);
+               return -EFAULT;
+       }
+
+       *ppos += len;   /* increase offset */
+       return len;
+}
+
+/**
+ * sde_dbg_ctrl_write - debugfs read handler for debug ctrl write
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_ctrl_write(struct file *file,
+       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       u32 dbg_ctrl = 0;
+       char buf[24];
+
+       if (!file) {
+               pr_err("DbgDbg: %s: error no file --\n", __func__);
+               return -EINVAL;
+       }
+
+       if (count >= sizeof(buf))
+               return -EFAULT;
+
+
+       if (copy_from_user(buf, user_buf, count))
+               return -EFAULT;
+
+       buf[count] = 0; /* end of string */
+
+       if (kstrtouint(buf, 0, &dbg_ctrl)) {
+               pr_err("%s: error in the number of bytes\n", __func__);
+               return -EFAULT;
+       }
+
+       pr_debug("dbg_ctrl_read:0x%x\n", dbg_ctrl);
+       sde_dbg_base.debugfs_ctrl = dbg_ctrl;
+
+       return count;
+}
+
+static const struct file_operations sde_dbg_ctrl_fops = {
+       .open = sde_dbg_debugfs_open,
+       .read = sde_dbg_ctrl_read,
+       .write = sde_dbg_ctrl_write,
+};
+
 void sde_dbg_init_dbg_buses(u32 hwversion)
 {
        static struct sde_dbg_base *dbg = &sde_dbg_base;
@@ -1695,6 +1814,8 @@ int sde_dbg_init(struct dentry *debugfs_root, struct device *dev,
        for (i = 0; i < SDE_EVTLOG_ENTRY; i++)
                sde_dbg_base.evtlog->logs[i].counter = i;
 
+       debugfs_create_file("dbg_ctrl", 0600, sde_dbg_base.root, NULL,
+                       &sde_dbg_ctrl_fops);
        debugfs_create_file("dump", 0600, sde_dbg_base.root, NULL,
                                                &sde_evtlog_fops);
        debugfs_create_u32("enable", 0600, sde_dbg_base.root,
index 74fd4c9..95528ef 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -123,6 +123,13 @@ extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
 #define SDE_DBG_DUMP_WQ(...) sde_dbg_dump(true, __func__, ##__VA_ARGS__, \
                SDE_DBG_DUMP_DATA_LIMITER)
 
+/**
+ * SDE_DBG_EVT_CTRL - trigger a different driver events
+ *  event: event that trigger different behavior in the driver
+ */
+#define SDE_DBG_CTRL(...) sde_dbg_ctrl(__func__, ##__VA_ARGS__, \
+               SDE_DBG_DUMP_DATA_LIMITER)
+
 #if defined(CONFIG_DEBUG_FS)
 
 /**
@@ -214,6 +221,15 @@ void sde_dbg_destroy(void);
 void sde_dbg_dump(bool queue_work, const char *name, ...);
 
 /**
+ * sde_dbg_ctrl - trigger specific actions for the driver with debugging
+ *             purposes. Those actions need to be enabled by the debugfs entry
+ *             so the driver executes those actions in the corresponding calls.
+ * @va_args:   list of actions to trigger
+ * Returns:    none
+ */
+void sde_dbg_ctrl(const char *name, ...);
+
+/**
  * sde_dbg_reg_register_base - register a hw register address section for later
  *     dumping. call this before calling sde_dbg_reg_register_dump_range
  *     to be able to specify sub-ranges within the base hw range.
@@ -295,6 +311,10 @@ static inline void sde_dbg_dump(bool queue_work, const char *name, ...)
 {
 }
 
+static inline void sde_dbg_ctrl(const char *name, ...)
+{
+}
+
 static inline int sde_dbg_reg_register_base(const char *name,
                void __iomem *base, size_t max_offset)
 {