---
 drivers/gpu/drm/msm/Makefile            |   1 +
 drivers/gpu/drm/msm/adreno/a3xx_gpu.c   |  20 ++-
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |   4 +-
 drivers/gpu/drm/msm/adreno/adreno_gpu.h |   2 -
 drivers/gpu/drm/msm/msm_drv.c           |  15 +-
 drivers/gpu/drm/msm/msm_drv.h           |   4 +
 drivers/gpu/drm/msm/msm_gpu.c           | 110 +++++++++++++
 drivers/gpu/drm/msm/msm_gpu.h           |  33 ++++
 drivers/gpu/drm/msm/msm_perf.c          | 270 ++++++++++++++++++++++++++++++++
 9 files changed, 448 insertions(+), 11 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/msm_perf.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index f945179..a19c731 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -23,6 +23,7 @@ msm-y := \
        msm_gem.o \
        msm_gem_submit.o \
        msm_gpu.o \
+       msm_perf.o \
        msm_rd.o \
        msm_ringbuffer.o
 
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c 
b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index 13d61bb..2e2950f 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -174,11 +174,11 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        /* Turn on performance counters: */
        gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
 
-       /* Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
-        * we will use this to augment our hang detection:
-        */
-       gpu_write(gpu, REG_A3XX_SP_PERFCOUNTER7_SELECT,
-                       SP_FS_FULL_ALU_INSTRUCTIONS);
+       /* Enable the perfcntrs that we use.. */
+       for (i = 0; i < gpu->num_perfcntrs; i++) {
+               const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
+               gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
+       }
 
        gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
 
@@ -383,6 +383,13 @@ static const struct adreno_gpu_funcs funcs = {
        },
 };
 
+static const struct msm_gpu_perfcntr perfcntrs[] = {
+       { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
+                       SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
+       { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
+                       SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
+};
+
 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
 {
        struct a3xx_gpu *a3xx_gpu = NULL;
@@ -417,6 +424,9 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
                        gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
 
+       gpu->perfcntrs = perfcntrs;
+       gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
+
        ret = adreno_gpu_init(dev, pdev, &a3xx_gpu->base,
                        &funcs, config->rev);
        if (ret)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 282163e..39a65af 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -119,8 +119,6 @@ int adreno_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
        struct msm_ringbuffer *ring = gpu->rb;
        unsigned i, ibs = 0;
 
-       adreno_gpu->last_fence = submit->fence;
-
        for (i = 0; i < submit->nr_cmds; i++) {
                switch (submit->cmd[i].type) {
                case MSM_SUBMIT_CMD_IB_TARGET_BUF:
@@ -225,7 +223,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
                        adreno_gpu->rev.patchid);
 
        seq_printf(m, "fence:    %d/%d\n", adreno_gpu->memptrs->fence,
-                       adreno_gpu->last_fence);
+                       gpu->submitted_fence);
        seq_printf(m, "rptr:     %d\n", adreno_gpu->memptrs->rptr);
        seq_printf(m, "wptr:     %d\n", adreno_gpu->memptrs->wptr);
        seq_printf(m, "rb wptr:  %d\n", get_wptr(gpu->rb));
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h 
b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 6b49c4f..1190a70 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -54,8 +54,6 @@ struct adreno_gpu {
        uint32_t revn;  /* numeric revision name */
        const struct adreno_gpu_funcs *funcs;
 
-       uint32_t last_fence;
-
        /* firmware: */
        const struct firmware *pm4, *pfp;
 
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index adcc68b..58f47a5 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -459,12 +459,25 @@ static int msm_debugfs_init(struct drm_minor *minor)
                return ret;
        }
 
-       return msm_rd_debugfs_init(minor);
+       ret = msm_rd_debugfs_init(minor);
+       if (ret) {
+               dev_err(dev->dev, "could not install rd debugfs\n");
+               return ret;
+       }
+
+       ret = msm_perf_debugfs_init(minor);
+       if (ret) {
+               dev_err(dev->dev, "could not install perf debugfs\n");
+               return ret;
+       }
+
+       return 0;
 }
 
 static void msm_debugfs_cleanup(struct drm_minor *minor)
 {
        msm_rd_debugfs_cleanup(minor);
+       msm_perf_debugfs_cleanup(minor);
        drm_debugfs_remove_files(msm_debugfs_list,
                        ARRAY_SIZE(msm_debugfs_list), minor);
 }
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index ea6f1c7..af91cab 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -45,6 +45,7 @@
 struct msm_kms;
 struct msm_gpu;
 struct msm_rd_state;
+struct msm_perf_state;
 struct msm_gem_submit;
 
 #define NUM_DOMAINS 2    /* one for KMS, then one per gpu core (?) */
@@ -71,6 +72,7 @@ struct msm_drm_private {
        wait_queue_head_t fence_event;
 
        struct msm_rd_state *rd;
+       struct msm_perf_state *perf;
 
        /* list of GEM objects: */
        struct list_head inactive_list;
@@ -186,6 +188,8 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, 
struct seq_file *m);
 int msm_rd_debugfs_init(struct drm_minor *minor);
 void msm_rd_debugfs_cleanup(struct drm_minor *minor);
 void msm_rd_dump_submit(struct msm_gem_submit *submit);
+int msm_perf_debugfs_init(struct drm_minor *minor);
+void msm_perf_debugfs_cleanup(struct drm_minor *minor);
 #else
 static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {}
 #endif
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 4775415..735d6d9 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -203,6 +203,107 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
 }
 
 /*
+ * Performance Counters:
+ */
+
+static bool msm_gpu_active(struct msm_gpu *gpu)
+{
+       return gpu->submitted_fence > gpu->funcs->last_fence(gpu);
+}
+
+/* called under perf_lock */
+static int update_hw_cntrs(struct msm_gpu *gpu, uint32_t ncntrs, uint32_t 
*cntrs)
+{
+       uint32_t current_cntrs[ARRAY_SIZE(gpu->last_cntrs)];
+       int i, n = min(ncntrs, gpu->num_perfcntrs);
+
+       /* read current values: */
+       for (i = 0; i < gpu->num_perfcntrs; i++)
+               current_cntrs[i] = gpu_read(gpu, gpu->perfcntrs[i].sample_reg);
+
+       /* update cntrs: */
+       for (i = 0; i < n; i++)
+               cntrs[i] = current_cntrs[i] - gpu->last_cntrs[i];
+
+       /* save current values: */
+       for (i = 0; i < gpu->num_perfcntrs; i++)
+               gpu->last_cntrs[i] = current_cntrs[i];
+
+       return n;
+}
+
+/* called under perf_lock */
+static void update_sw_cntrs(struct msm_gpu *gpu)
+{
+       ktime_t time;
+       uint32_t elapsed;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpu->perf_lock, flags);
+       if (!gpu->perfcntr_active)
+               goto out;
+
+       time = ktime_get();
+       elapsed = ktime_to_us(ktime_sub(time, gpu->last_sample.time));
+
+       gpu->totaltime += elapsed;
+       if (gpu->last_sample.active)
+               gpu->activetime += elapsed;
+
+       gpu->last_sample.active = msm_gpu_active(gpu);
+       gpu->last_sample.time = time;
+
+out:
+       spin_unlock_irqrestore(&gpu->perf_lock, flags);
+}
+
+void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpu->perf_lock, flags);
+       /* we could dynamically enable/disable perfcntr registers too.. */
+       gpu->last_sample.active = msm_gpu_active(gpu);
+       gpu->last_sample.time = ktime_get();
+       gpu->activetime = gpu->totaltime = 0;
+       gpu->perfcntr_active = true;
+       update_hw_cntrs(gpu, 0, NULL);
+       spin_unlock_irqrestore(&gpu->perf_lock, flags);
+}
+
+void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
+{
+       gpu->perfcntr_active = false;
+}
+
+/* returns -errno or # of cntrs sampled */
+int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
+               uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&gpu->perf_lock, flags);
+
+       if (!gpu->perfcntr_active) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       *activetime = gpu->activetime;
+       *totaltime = gpu->totaltime;
+
+       gpu->activetime = gpu->totaltime = 0;
+
+       ret = update_hw_cntrs(gpu, ncntrs, cntrs);
+
+out:
+       spin_unlock_irqrestore(&gpu->perf_lock, flags);
+
+       return ret;
+}
+
+/*
  * Cmdstream submission/retirement:
  */
 
@@ -240,6 +341,7 @@ void msm_gpu_retire(struct msm_gpu *gpu)
 {
        struct msm_drm_private *priv = gpu->dev->dev_private;
        queue_work(priv->wq, &gpu->retire_work);
+       update_sw_cntrs(gpu);
 }
 
 /* add bo's to gpu's ring, and kick gpu: */
@@ -256,6 +358,10 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct 
msm_gem_submit *submit,
 
        msm_rd_dump_submit(submit);
 
+       gpu->submitted_fence = submit->fence;
+
+       update_sw_cntrs(gpu);
+
        ret = gpu->funcs->submit(gpu, submit, ctx);
        priv->lastctx = ctx;
 
@@ -304,12 +410,16 @@ int msm_gpu_init(struct drm_device *drm, struct 
platform_device *pdev,
        struct resource *res;
        int i, ret;
 
+       if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs)))
+               gpu->num_perfcntrs = ARRAY_SIZE(gpu->last_cntrs);
+
        gpu->dev = drm;
        gpu->funcs = funcs;
        gpu->name = name;
 
        INIT_LIST_HEAD(&gpu->active_list);
        INIT_WORK(&gpu->retire_work, retire_worker);
+       spin_lock_init(&gpu->perf_lock);
 
        BUG_ON(ARRAY_SIZE(clk_names) != ARRAY_SIZE(gpu->grp_clks));
 
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 8d2cd6c..b537f7c 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -25,6 +25,7 @@
 #include "msm_ringbuffer.h"
 
 struct msm_gem_submit;
+struct msm_gpu_perfcntr;
 
 /* So far, with hardware that I've seen to date, we can have:
  *  + zero, one, or two z180 2d cores
@@ -63,12 +64,26 @@ struct msm_gpu {
        struct drm_device *dev;
        const struct msm_gpu_funcs *funcs;
 
+       /* performance counters (hw & sw): */
+       spinlock_t perf_lock;
+       bool perfcntr_active;
+       struct {
+               bool active;
+               ktime_t time;
+       } last_sample;
+       uint32_t totaltime, activetime;    /* sw counters */
+       uint32_t last_cntrs[5];            /* hw counters */
+       const struct msm_gpu_perfcntr *perfcntrs;
+       uint32_t num_perfcntrs;
+
        struct msm_ringbuffer *rb;
        uint32_t rb_iova;
 
        /* list of GEM active objects: */
        struct list_head active_list;
 
+       uint32_t submitted_fence;
+
        /* worker for handling active-list retiring: */
        struct work_struct retire_work;
 
@@ -85,6 +100,19 @@ struct msm_gpu {
        uint32_t bsc;
 };
 
+/* Perf-Counters:
+ * The select_reg and select_val are just there for the benefit of the child
+ * class that actually enables the perf counter..  but msm_gpu base class
+ * will handle sampling/displaying the counters.
+ */
+
+struct msm_gpu_perfcntr {
+       uint32_t select_reg;
+       uint32_t sample_reg;
+       uint32_t select_val;
+       const char *name;
+};
+
 static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
 {
        msm_writel(data, gpu->mmio + (reg << 2));
@@ -98,6 +126,11 @@ static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg)
 int msm_gpu_pm_suspend(struct msm_gpu *gpu);
 int msm_gpu_pm_resume(struct msm_gpu *gpu);
 
+void msm_gpu_perfcntr_start(struct msm_gpu *gpu);
+void msm_gpu_perfcntr_stop(struct msm_gpu *gpu);
+int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
+               uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs);
+
 void msm_gpu_retire(struct msm_gpu *gpu);
 int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                struct msm_file_private *ctx);
diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c
new file mode 100644
index 0000000..1937bd2
--- /dev/null
+++ b/drivers/gpu/drm/msm/msm_perf.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdcl...@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* For profiling, userspace can:
+ *
+ *   tail -f /sys/kernel/debug/dri/<minor>/gpu
+ *
+ * This will enable performance counters/profiling to track the busy time
+ * and any gpu specific performance counters that are supported.
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+
+#include "msm_drv.h"
+#include "msm_gpu.h"
+
+struct msm_perf_state {
+       struct drm_device *dev;
+
+       bool open;
+       int cnt;
+       struct mutex read_lock;
+
+       char buf[256];
+       int buftot, bufpos;
+
+       unsigned long next_jiffies;
+
+       struct dentry *ent;
+       struct drm_info_node *node;
+};
+
+#define SAMPLE_TIME (HZ/4)
+
+/* wait for next sample time: */
+static int wait_sample(struct msm_perf_state *perf)
+{
+       unsigned long start_jiffies = jiffies;
+
+       if (time_after(perf->next_jiffies, start_jiffies)) {
+               unsigned long remaining_jiffies =
+                       perf->next_jiffies - start_jiffies;
+               int ret = schedule_timeout_interruptible(remaining_jiffies);
+               if (ret > 0) {
+                       /* interrupted */
+                       return -ERESTARTSYS;
+               }
+       }
+       perf->next_jiffies += SAMPLE_TIME;
+       return 0;
+}
+
+static int refill_buf(struct msm_perf_state *perf)
+{
+       struct msm_drm_private *priv = perf->dev->dev_private;
+       struct msm_gpu *gpu = priv->gpu;
+       char *ptr = perf->buf;
+       int rem = sizeof(perf->buf);
+       int i, n;
+
+       if ((perf->cnt++ % 32) == 0) {
+               /* Header line: */
+               n = snprintf(ptr, rem, "%%BUSY");
+               ptr += n;
+               rem -= n;
+
+               for (i = 0; i < gpu->num_perfcntrs; i++) {
+                       const struct msm_gpu_perfcntr *perfcntr = 
&gpu->perfcntrs[i];
+                       n = snprintf(ptr, rem, "\t%s", perfcntr->name);
+                       ptr += n;
+                       rem -= n;
+               }
+       } else {
+               /* Sample line: */
+               uint32_t activetime = 0, totaltime = 0;
+               uint32_t cntrs[5];
+               uint32_t val;
+               int ret;
+
+               /* sleep until next sample time: */
+               ret = wait_sample(perf);
+               if (ret)
+                       return ret;
+
+               ret = msm_gpu_perfcntr_sample(gpu, &activetime, &totaltime,
+                               ARRAY_SIZE(cntrs), cntrs);
+               if (ret < 0)
+                       return ret;
+
+               val = totaltime ? 1000 * activetime / totaltime : 0;
+               n = snprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10);
+               ptr += n;
+               rem -= n;
+
+               for (i = 0; i < ret; i++) {
+                       /* cycle counters (I think).. convert to MHz.. */
+                       val = cntrs[i] / 10000;
+                       n = snprintf(ptr, rem, "\t%5d.%02d",
+                                       val / 100, val % 100);
+                       ptr += n;
+                       rem -= n;
+               }
+       }
+
+       n = snprintf(ptr, rem, "\n");
+       ptr += n;
+       rem -= n;
+
+       perf->bufpos = 0;
+       perf->buftot = ptr - perf->buf;
+
+       return 0;
+}
+
+static ssize_t perf_read(struct file *file, char __user *buf,
+               size_t sz, loff_t *ppos)
+{
+       struct msm_perf_state *perf = file->private_data;
+       int n = 0, ret;
+
+       mutex_lock(&perf->read_lock);
+
+       if (perf->bufpos >= perf->buftot) {
+               ret = refill_buf(perf);
+               if (ret)
+                       goto out;
+       }
+
+       n = min((int)sz, perf->buftot - perf->bufpos);
+       ret = copy_to_user(buf, &perf->buf[perf->bufpos], n);
+       if (ret)
+               goto out;
+
+       perf->bufpos += n;
+       *ppos += n;
+
+out:
+       mutex_unlock(&perf->read_lock);
+       if (ret)
+               return ret;
+       return n;
+}
+
+static int perf_open(struct inode *inode, struct file *file)
+{
+       struct msm_perf_state *perf = inode->i_private;
+       struct drm_device *dev = perf->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct msm_gpu *gpu = priv->gpu;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+
+priv->perf = perf; // XXX this isn't really good..
+
+       if (perf->open || !gpu) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       file->private_data = perf;
+       perf->open = true;
+       perf->cnt = 0;
+       perf->buftot = 0;
+       perf->bufpos = 0;
+       msm_gpu_perfcntr_start(gpu);
+       perf->next_jiffies = jiffies + SAMPLE_TIME;
+
+out:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+static int perf_release(struct inode *inode, struct file *file)
+{
+       struct msm_perf_state *perf = inode->i_private;
+       struct msm_drm_private *priv = perf->dev->dev_private;
+       msm_gpu_perfcntr_stop(priv->gpu);
+       perf->open = false;
+       return 0;
+}
+
+
+static const struct file_operations perf_debugfs_fops = {
+       .owner = THIS_MODULE,
+       .open = perf_open,
+       .read = perf_read,
+       .llseek = no_llseek,
+       .release = perf_release,
+};
+
+int msm_perf_debugfs_init(struct drm_minor *minor)
+{
+       struct msm_drm_private *priv = minor->dev->dev_private;
+       struct msm_perf_state *perf;
+
+       perf = kzalloc(sizeof(*perf), GFP_KERNEL);
+       if (!perf)
+               return -ENOMEM;
+
+       perf->dev = minor->dev;
+
+       mutex_init(&perf->read_lock);
+DBG("********** perf->dev=%p, priv=%p", perf->dev, priv);
+//     priv->perf = perf;
+
+       perf->node = kzalloc(sizeof(*perf->node), GFP_KERNEL);
+       if (!perf->node)
+               goto fail;
+
+       perf->ent = debugfs_create_file("perf", S_IFREG | S_IRUGO,
+                       minor->debugfs_root, perf, &perf_debugfs_fops);
+       if (!perf->ent) {
+               DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/perf\n",
+                               minor->debugfs_root->d_name.name);
+               goto fail;
+       }
+
+       perf->node->minor = minor;
+       perf->node->dent  = perf->ent;
+       perf->node->info_ent = NULL;
+
+       mutex_lock(&minor->debugfs_lock);
+       list_add(&perf->node->list, &minor->debugfs_list);
+       mutex_unlock(&minor->debugfs_lock);
+
+       return 0;
+
+fail:
+       msm_perf_debugfs_cleanup(minor);
+       return -1;
+}
+
+void msm_perf_debugfs_cleanup(struct drm_minor *minor)
+{
+       struct msm_drm_private *priv = minor->dev->dev_private;
+       struct msm_perf_state *perf = priv->perf;
+
+       if (perf->ent)
+               debugfs_remove(perf->ent);
+
+       if (perf->node) {
+               mutex_lock(&minor->debugfs_lock);
+               list_del(&perf->node->list);
+               mutex_unlock(&minor->debugfs_lock);
+               kfree(perf->node);
+       }
+
+       mutex_destroy(&perf->read_lock);
+
+       kfree(perf);
+}
+
+#endif
-- 
1.8.3.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to