video: tegra: host: Host1x tickcount
Terje Bergstrom [Thu, 23 Aug 2012 06:18:23 +0000 (09:18 +0300)]
Add support for host1x tick counters. Adds under debugfs entries
that export the tickcount, which is global, and stallcount and
xfercount which are per channel counters.

The counters are reset when host1x loses power.

Bug 1036465

Change-Id: I2342078f98f6b67a376130bb68fbae84e070c0eb
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/127117
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/chip_support.h
drivers/video/tegra/host/debug.c
drivers/video/tegra/host/host1x/host1x.c
drivers/video/tegra/host/host1x/host1x.h
drivers/video/tegra/host/host1x/host1x_tickctrl.c [new file with mode: 0644]
drivers/video/tegra/host/host1x/hw_host1x02_channel.h
drivers/video/tegra/host/t114/t114.c
include/linux/nvhost.h

index fca8a38..5ec200a 100644 (file)
@@ -604,6 +604,11 @@ int nvhost_client_device_init(struct nvhost_device *dev)
        if (err)
                goto fail;
 
+       if (tickctrl_op().init_channel)
+               tickctrl_op().init_channel(dev);
+
+       nvhost_device_debug_init(dev);
+
        dev_info(&dev->dev, "initialized\n");
 
        return 0;
index ba07da6..26be55c 100644 (file)
@@ -164,6 +164,16 @@ struct nvhost_actmon_ops {
        int (*isr)(u32 hintstatus, void __iomem *sync_regs);
 };
 
+struct nvhost_tickctrl_ops {
+       int (*init_host)(struct nvhost_master *host);
+       void (*deinit_host)(struct nvhost_master *host);
+       int (*init_channel)(struct nvhost_device *dev);
+       void (*deinit_channel)(struct nvhost_device *dev);
+       int (*tickcount)(struct nvhost_device *dev, u64 *val);
+       int (*stallcount)(struct nvhost_device *dev, u64 *val);
+       int (*xfercount)(struct nvhost_device *dev, u64 *val);
+};
+
 struct nvhost_chip_support {
        const char * soc_name;
        struct nvhost_channel_ops channel;
@@ -175,6 +185,7 @@ struct nvhost_chip_support {
        struct nvhost_dev_ops nvhost_dev;
        struct nvhost_mem_ops mem;
        struct nvhost_actmon_ops actmon;
+       struct nvhost_tickctrl_ops tickctrl;
 };
 
 struct nvhost_chip_support *nvhost_get_chip_ops(void);
@@ -188,6 +199,7 @@ struct nvhost_chip_support *nvhost_get_chip_ops(void);
 #define cdma_pb_op()           nvhost_get_chip_ops()->push_buffer
 #define mem_op()               (nvhost_get_chip_ops()->mem)
 #define actmon_op()            (nvhost_get_chip_ops()->actmon)
+#define tickctrl_op()          (nvhost_get_chip_ops()->tickctrl)
 
 int nvhost_init_chip_support(struct nvhost_master *host);
 
index 9c9fd20..7a431a9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2010 Google, Inc.
  * Author: Erik Gilling <konkers@android.com>
  *
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (C) 2011-2012 NVIDIA Corporation
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -256,10 +256,108 @@ static const struct file_operations actmon_avg_fops = {
        .release        = single_release,
 };
 
+static int tickcount_show(struct seq_file *s, void *unused)
+{
+       struct nvhost_device *dev = s->private;
+       u64 cnt;
+       int err;
+
+       err = tickctrl_op().tickcount(dev, &cnt);
+       if (!err)
+               seq_printf(s, "%lld\n", cnt);
+       return err;
+}
+
+static int tickcount_open(struct inode *inode, struct file *file)
+{
+       if (!tickctrl_op().tickcount)
+               return -ENODEV;
+
+       return single_open(file, tickcount_show, inode->i_private);
+}
+
+static const struct file_operations tickcount_fops = {
+       .open           = tickcount_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int stallcount_show(struct seq_file *s, void *unused)
+{
+       struct nvhost_device *dev = s->private;
+       u64 cnt;
+       int err;
+
+       err = tickctrl_op().stallcount(dev, &cnt);
+       if (!err)
+               seq_printf(s, "%lld\n", cnt);
+       return err;
+}
+
+static int stallcount_open(struct inode *inode, struct file *file)
+{
+       if (!tickctrl_op().stallcount)
+               return -ENODEV;
+
+       return single_open(file, stallcount_show, inode->i_private);
+}
+
+static const struct file_operations stallcount_fops = {
+       .open           = stallcount_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int xfercount_show(struct seq_file *s, void *unused)
+{
+       struct nvhost_device *dev = s->private;
+       u64 cnt;
+       int err;
+
+       err = tickctrl_op().xfercount(dev, &cnt);
+       if (!err)
+               seq_printf(s, "%lld\n", cnt);
+       return err;
+}
+
+static int xfercount_open(struct inode *inode, struct file *file)
+{
+       if (!tickctrl_op().xfercount)
+               return -ENODEV;
+
+       return single_open(file, xfercount_show, inode->i_private);
+}
+
+static const struct file_operations xfercount_fops = {
+       .open           = xfercount_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+void nvhost_device_debug_init(struct nvhost_device *dev)
+{
+       struct dentry *de = nvhost_get_parent(dev)->debugfs;
+
+       de = debugfs_create_dir(dev->name, de);
+       debugfs_create_file("stallcount", S_IRUGO, de, dev, &stallcount_fops);
+       debugfs_create_file("xfercount", S_IRUGO, de, dev, &xfercount_fops);
+
+       dev->debugfs = de;
+}
+
 void nvhost_debug_init(struct nvhost_master *master)
 {
        struct dentry *de = debugfs_create_dir("tegra_host", NULL);
 
+       if (!de)
+               return;
+
+       /* Store the created entry */
+       master->dev->debugfs = de;
+
        debugfs_create_file("status", S_IRUGO, de,
                        master, &nvhost_debug_fops);
        debugfs_create_file("status_all", S_IRUGO, de,
@@ -286,6 +384,8 @@ void nvhost_debug_init(struct nvhost_master *master)
                        master, &actmon_above_wmark_fops);
        debugfs_create_file("3d_actmon_below_wmark", S_IRUGO, de,
                        master, &actmon_below_wmark_fops);
+       debugfs_create_file("tickcount", S_IRUGO, de,
+                       master->dev, &tickcount_fops);
 }
 #else
 void nvhost_debug_init(struct nvhost_master *master)
index 95c6dad..01dc03f 100644 (file)
@@ -300,11 +300,15 @@ static void power_on_host(struct nvhost_device *dev)
        struct nvhost_master *host = nvhost_get_drvdata(dev);
        nvhost_syncpt_reset(&host->syncpt);
        nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
+       if (tickctrl_op().init_host)
+               tickctrl_op().init_host(host);
 }
 
 static int power_off_host(struct nvhost_device *dev)
 {
        struct nvhost_master *host = nvhost_get_drvdata(dev);
+       if (tickctrl_op().deinit_host)
+               tickctrl_op().deinit_host(host);
        nvhost_syncpt_save(&host->syncpt);
        nvhost_intr_stop(&host->intr);
        return 0;
@@ -470,6 +474,9 @@ static int __devinit nvhost_probe(struct nvhost_device *dev,
 
        nvhost_debug_init(host);
 
+       if (tickctrl_op().init_host)
+               tickctrl_op().init_host(host);
+
        dev_info(&dev->dev, "initialized\n");
        return 0;
 
index 49916b0..44bbf2c 100644 (file)
@@ -61,6 +61,7 @@ struct nvhost_master {
 extern struct nvhost_master *nvhost;
 
 void nvhost_debug_init(struct nvhost_master *master);
+void nvhost_device_debug_init(struct nvhost_device *dev);
 void nvhost_debug_dump(struct nvhost_master *master);
 
 struct nvhost_channel *nvhost_alloc_channel(struct nvhost_device *dev);
diff --git a/drivers/video/tegra/host/host1x/host1x_tickctrl.c b/drivers/video/tegra/host/host1x/host1x_tickctrl.c
new file mode 100644 (file)
index 0000000..c73ebfd
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * drivers/video/tegra/host/host1x/host1x_counter.c
+ *
+ * Tegra Graphics Host Counter support
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/>.
+ */
+
+#include <linux/nvhost.h>
+#include <linux/io.h>
+#include "dev.h"
+#include "chip_support.h"
+
+static int host1x_tickctrl_init_host(struct nvhost_master *host)
+{
+       void __iomem *regs = host->aperture;
+
+       /* Initialize counter */
+       writel(0, regs + host1x_channel_tickcount_hi_r());
+       writel(0, regs + host1x_channel_tickcount_lo_r());
+
+       writel(host1x_channel_channelctrl_enabletickcnt_f(1),
+                       regs + host1x_channel_channelctrl_r());
+
+       return 0;
+}
+
+static void host1x_tickctrl_deinit_host(struct nvhost_master *host)
+{
+       void __iomem *regs = host->aperture;
+
+       writel(host1x_channel_channelctrl_enabletickcnt_f(0),
+                       regs + host1x_channel_channelctrl_r());
+}
+
+static int host1x_tickctrl_init_channel(struct nvhost_device *dev)
+{
+       void __iomem *regs = dev->channel->aperture;
+
+       /* Initialize counter */
+       writel(0, regs + host1x_channel_stallcount_hi_r());
+       writel(0, regs + host1x_channel_stallcount_lo_r());
+       writel(0, regs + host1x_channel_xfercount_hi_r());
+       writel(0, regs + host1x_channel_xfercount_lo_r());
+
+       writel(host1x_channel_stallctrl_enable_channel_stall_f(1),
+                       regs + host1x_channel_stallctrl_r());
+       writel(host1x_channel_xferctrl_enable_channel_xfer_f(1),
+                       regs + host1x_channel_xferctrl_r());
+
+       return 0;
+}
+
+static void host1x_tickctrl_deinit_channel(struct nvhost_device *dev)
+{
+       void __iomem *regs = dev->channel->aperture;
+
+       writel(host1x_channel_stallctrl_enable_channel_stall_f(0),
+                       regs + host1x_channel_stallctrl_r());
+       writel(host1x_channel_xferctrl_enable_channel_xfer_f(0),
+                       regs + host1x_channel_xferctrl_r());
+}
+
+static u64 readl64(void __iomem *reg_hi, void __iomem *reg_lo)
+{
+       u32 hi, lo, hi2;
+       do {
+               hi = readl(reg_hi);
+               lo = readl(reg_lo);
+               hi2 = readl(reg_hi);
+       } while (hi2 != hi);
+       return ((u64)hi << 32) | (u64)lo;
+}
+
+static int host1x_tickctrl_tickcount(struct nvhost_device *dev, u64 *val)
+{
+       void __iomem *regs = nvhost_get_host(dev)->aperture;
+
+       *val = readl64(regs + host1x_channel_tickcount_hi_r(),
+               regs + host1x_channel_tickcount_lo_r());
+       rmb();
+
+       return 0;
+}
+
+static int host1x_tickctrl_stallcount(struct nvhost_device *dev, u64 *val)
+{
+       void __iomem *regs = dev->channel->aperture;
+
+       *val = readl64(regs + host1x_channel_stallcount_hi_r(),
+               regs + host1x_channel_stallcount_lo_r());
+       rmb();
+
+       return 0;
+}
+
+static int host1x_tickctrl_xfercount(struct nvhost_device *dev, u64 *val)
+{
+       void __iomem *regs = dev->channel->aperture;
+
+       *val = readl64(regs + host1x_channel_xfercount_hi_r(),
+               regs + host1x_channel_xfercount_lo_r());
+       rmb();
+
+       return 0;
+}
+
+static const struct nvhost_tickctrl_ops host1x_tickctrl_ops = {
+       .init_host = host1x_tickctrl_init_host,
+       .deinit_host = host1x_tickctrl_deinit_host,
+       .init_channel = host1x_tickctrl_init_channel,
+       .deinit_channel = host1x_tickctrl_deinit_channel,
+       .tickcount = host1x_tickctrl_tickcount,
+       .stallcount = host1x_tickctrl_stallcount,
+       .xfercount = host1x_tickctrl_xfercount,
+};
index e0133e3..0192b86 100644 (file)
@@ -178,5 +178,105 @@ static inline u32 host1x_channel_dmactrl_dmainitget_v(u32 r)
 {
        return (r >> 2) & 0x1;
 }
+static inline u32 host1x_channel_tickcount_hi_r(void)
+{
+       return 0x90;
+}
+static inline u32 host1x_channel_tickcount_lo_r(void)
+{
+       return 0x94;
+}
+static inline u32 host1x_channel_channelctrl_r(void)
+{
+       return 0x98;
+}
+static inline u32 host1x_channel_channelctrl_enabletickcnt_s(void)
+{
+       return 1;
+}
+static inline u32 host1x_channel_channelctrl_enabletickcnt_f(u32 v)
+{
+       return (v & 0x1) << 0;
+}
+static inline u32 host1x_channel_channelctrl_enabletickcnt_m(void)
+{
+       return 0x1 << 0;
+}
+static inline u32 host1x_channel_channelctrl_enabletickcnt_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+static inline u32 host1x_channel_stallctrl_r(void)
+{
+       return 0xa0;
+}
+static inline u32 host1x_channel_stallctrl_enable_channel_stall_s(void)
+{
+       return 1;
+}
+static inline u32 host1x_channel_stallctrl_enable_channel_stall_f(u32 v)
+{
+       return (v & 0x1) << 0;
+}
+static inline u32 host1x_channel_stallctrl_enable_channel_stall_m(void)
+{
+       return 0x1 << 0;
+}
+static inline u32 host1x_channel_stallctrl_enable_channel_stall_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+static inline u32 host1x_channel_stallcount_hi_r(void)
+{
+       return 0xa4;
+}
+static inline u32 host1x_channel_stallcount_hi_stallcount_hi_s(void)
+{
+       return 32;
+}
+static inline u32 host1x_channel_stallcount_hi_stallcount_hi_f(u32 v)
+{
+       return (v & 0xffffffff) << 0;
+}
+static inline u32 host1x_channel_stallcount_hi_stallcount_hi_m(void)
+{
+       return 0xffffffff << 0;
+}
+static inline u32 host1x_channel_stallcount_hi_stallcount_hi_v(u32 r)
+{
+       return (r >> 0) & 0xffffffff;
+}
+static inline u32 host1x_channel_stallcount_lo_r(void)
+{
+       return 0xa8;
+}
+static inline u32 host1x_channel_xferctrl_r(void)
+{
+       return 0xac;
+}
+static inline u32 host1x_channel_xferctrl_enable_channel_xfer_s(void)
+{
+       return 1;
+}
+static inline u32 host1x_channel_xferctrl_enable_channel_xfer_f(u32 v)
+{
+       return (v & 0x1) << 0;
+}
+static inline u32 host1x_channel_xferctrl_enable_channel_xfer_m(void)
+{
+       return 0x1 << 0;
+}
+static inline u32 host1x_channel_xferctrl_enable_channel_xfer_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+static inline u32 host1x_channel_xfercount_hi_r(void)
+{
+       return 0xb0;
+}
+static inline u32 host1x_channel_xfercount_lo_r(void)
+{
+       return 0xb4;
+}
 
 #endif /* __hw_host1x_channel_host1x_h__ */
index e47b5dd..97f9dd4 100644 (file)
@@ -305,6 +305,7 @@ static struct nvhost_channel *t114_alloc_nvhost_channel(
 #include "host1x/host1x_syncpt.c"
 #include "host1x/host1x_intr.c"
 #include "host1x/host1x_actmon.c"
+#include "host1x/host1x_tickctrl.c"
 
 int nvhost_init_t114_support(struct nvhost_master *host,
        struct nvhost_chip_support *op)
@@ -325,6 +326,7 @@ int nvhost_init_t114_support(struct nvhost_master *host,
        op->nvhost_dev.alloc_nvhost_channel = t114_alloc_nvhost_channel;
        op->nvhost_dev.free_nvhost_channel = t114_free_nvhost_channel;
        op->actmon = host1x_actmon_ops;
+       op->tickctrl = host1x_tickctrl_ops;
 
        return 0;
 }
index 83cd02a..cea65ed 100644 (file)
@@ -120,6 +120,7 @@ struct nvhost_device {
        struct nvhost_channel *channel; /* Channel assigned for the module */
        struct kobject *power_kobj;     /* kobject to hold power sysfs entries */
        struct nvhost_device_power_attr *power_attrib;  /* sysfs attributes */
+       struct dentry *debugfs;         /* debugfs directory */
 };
 
 struct nvhost_device_power_attr {