video: tegra: host: Add syncpt sysfs entries
Terje Bergstrom [Tue, 27 Mar 2012 12:43:58 +0000 (15:43 +0300)]
Expose sync point current and max values through sysfs.

Bug 957639

Change-Id: I2a3b914d404bb8d7bbed86d383c859bd8237a278
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/92778
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>

drivers/video/tegra/host/dev.c
drivers/video/tegra/host/host1x/host1x_syncpt.c
drivers/video/tegra/host/nvhost_syncpt.c
drivers/video/tegra/host/nvhost_syncpt.h

index 531aa77..0a6479d 100644 (file)
@@ -368,20 +368,8 @@ static void nvhost_remove_chip_support(struct nvhost_master *host)
        kfree(host->channels);
        host->channels = 0;
 
-       kfree(host->syncpt.min_val);
-       host->syncpt.min_val = 0;
-
-       kfree(host->syncpt.max_val);
-       host->syncpt.max_val = 0;
-
-       kfree(host->syncpt.base_val);
-       host->syncpt.base_val = 0;
-
        kfree(host->intr.syncpt);
        host->intr.syncpt = 0;
-
-       kfree(host->syncpt.lock_counts);
-       host->syncpt.lock_counts = 0;
 }
 
 static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
@@ -406,24 +394,10 @@ static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
        host->channels = kzalloc(sizeof(struct nvhost_channel) *
                                 host->nb_channels, GFP_KERNEL);
 
-       host->syncpt.min_val = kzalloc(sizeof(atomic_t) *
-                                      host->syncpt.nb_pts, GFP_KERNEL);
-
-       host->syncpt.max_val = kzalloc(sizeof(atomic_t) *
-                                      host->syncpt.nb_pts, GFP_KERNEL);
-
-       host->syncpt.base_val = kzalloc(sizeof(u32) *
-                                       host->syncpt.nb_bases, GFP_KERNEL);
-
        host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
                                    host->syncpt.nb_pts, GFP_KERNEL);
 
-       host->syncpt.lock_counts = kzalloc(sizeof(atomic_t) *
-                                      host->syncpt.nb_mlocks, GFP_KERNEL);
-
-       if (!(host->channels && host->syncpt.min_val &&
-             host->syncpt.max_val && host->syncpt.base_val &&
-             host->intr.syncpt && host->syncpt.lock_counts)) {
+       if (!(host->channels && host->intr.syncpt)) {
                /* frees happen in the support removal phase */
                return -ENOMEM;
        }
@@ -540,6 +514,10 @@ static int __devinit nvhost_probe(struct nvhost_device *dev)
 
        nvhost_bus_add_host(host);
 
+       err = nvhost_syncpt_init(&tegra_grhost_device, &host->syncpt);
+       if (err)
+               goto fail;
+
        err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
        if (err)
                goto fail;
@@ -575,6 +553,7 @@ static int __exit nvhost_remove(struct nvhost_device *dev)
 {
        struct nvhost_master *host = nvhost_get_drvdata(dev);
        nvhost_intr_deinit(&host->intr);
+       nvhost_syncpt_deinit(&host->syncpt);
        nvhost_remove_chip_support(host);
        return 0;
 }
index b0fd997..b431fa3 100644 (file)
@@ -71,8 +71,10 @@ static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
 
        if (!nvhost_syncpt_check_max(sp, id, live))
                dev_err(&syncpt_to_dev(sp)->dev->dev,
-                               "%s failed: id=%u\n",
+                               "%s failed: id=%u, min=%d, max=%d\n",
                                __func__,
+                               nvhost_syncpt_read_min(sp, id),
+                               nvhost_syncpt_read_max(sp, id),
                                id);
 
        return live;
index eb5176e..13ad0fc 100644 (file)
 
 #include <linux/nvhost_ioctl.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include "nvhost_syncpt.h"
 #include "dev.h"
 
 #define MAX_STUCK_CHECK_COUNT 15
+#define MAX_SYNCPT_LENGTH 5
+/* Name of sysfs node for min and max value */
+static const char *min_name = "min";
+static const char *max_name = "max";
 
 /**
  * Resets syncpoint and waitbase values to sw shadows
@@ -317,3 +322,122 @@ int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
        return syncpt_op(sp).wait_check(sp, nvmap,
                        waitchk_mask, wait, num_waitchk);
 }
+
+/* Displays the current value of the sync point via sysfs */
+static ssize_t syncpt_min_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct nvhost_syncpt_attr *syncpt_attr =
+               container_of(attr, struct nvhost_syncpt_attr, attr);
+
+       return snprintf(buf, PAGE_SIZE, "%d",
+                       nvhost_syncpt_read(&syncpt_attr->host->syncpt,
+                               syncpt_attr->id));
+}
+
+static ssize_t syncpt_max_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       struct nvhost_syncpt_attr *syncpt_attr =
+               container_of(attr, struct nvhost_syncpt_attr, attr);
+
+       return snprintf(buf, PAGE_SIZE, "%d",
+                       nvhost_syncpt_read_max(&syncpt_attr->host->syncpt,
+                               syncpt_attr->id));
+}
+
+int nvhost_syncpt_init(struct nvhost_device *dev,
+               struct nvhost_syncpt *sp)
+{
+       int i;
+       struct nvhost_master *host = syncpt_to_dev(sp);
+       int err = 0;
+
+       /* Allocate structs for min, max and base values */
+       sp->min_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
+       sp->max_val = kzalloc(sizeof(atomic_t) * sp->nb_pts, GFP_KERNEL);
+       sp->base_val = kzalloc(sizeof(u32) * sp->nb_bases, GFP_KERNEL);
+       sp->lock_counts = kzalloc(sizeof(atomic_t) * sp->nb_mlocks, GFP_KERNEL);
+
+       if (!(sp->min_val && sp->max_val && sp->base_val && sp->lock_counts)) {
+               /* frees happen in the deinit */
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       sp->kobj = kobject_create_and_add("syncpt", &dev->dev.kobj);
+       if (!sp->kobj) {
+               err = -EIO;
+               goto fail;
+       }
+
+       /* Allocate two attributes for each sync point: min and max */
+       sp->syncpt_attrs = kzalloc(sizeof(*sp->syncpt_attrs) * sp->nb_pts * 2,
+                       GFP_KERNEL);
+       if (!sp->syncpt_attrs) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Fill in the attributes */
+       for (i = 0; i < sp->nb_pts; i++) {
+               char name[MAX_SYNCPT_LENGTH];
+               struct kobject *kobj;
+               struct nvhost_syncpt_attr *min = &sp->syncpt_attrs[i*2];
+               struct nvhost_syncpt_attr *max = &sp->syncpt_attrs[i*2+1];
+
+               /* Create one directory per sync point */
+               snprintf(name, sizeof(name), "%d", i);
+               kobj = kobject_create_and_add(name, sp->kobj);
+               if (!kobj) {
+                       err = -EIO;
+                       goto fail;
+               }
+
+               min->id = i;
+               min->host = host;
+               min->attr.attr.name = min_name;
+               min->attr.attr.mode = S_IRUGO;
+               min->attr.show = syncpt_min_show;
+               if (sysfs_create_file(kobj, &min->attr.attr)) {
+                       err = -EIO;
+                       goto fail;
+               }
+
+               max->id = i;
+               max->host = host;
+               max->attr.attr.name = max_name;
+               max->attr.attr.mode = S_IRUGO;
+               max->attr.show = syncpt_max_show;
+               if (sysfs_create_file(kobj, &max->attr.attr)) {
+                       err = -EIO;
+                       goto fail;
+               }
+       }
+
+       return err;
+
+fail:
+       nvhost_syncpt_deinit(sp);
+       return err;
+}
+
+void nvhost_syncpt_deinit(struct nvhost_syncpt *sp)
+{
+       kobject_put(sp->kobj);
+
+       kfree(sp->min_val);
+       sp->min_val = NULL;
+
+       kfree(sp->max_val);
+       sp->max_val = NULL;
+
+       kfree(sp->base_val);
+       sp->base_val = NULL;
+
+       kfree(sp->lock_counts);
+       sp->lock_counts = 0;
+
+       kfree(sp->syncpt_attrs);
+       sp->syncpt_attrs = NULL;
+}
index 5b33917..b71cb3e 100644 (file)
@@ -34,7 +34,15 @@ struct nvhost_waitchk;
 #define NVSYNCPT_GRAPHICS_HOST              (0)
 #define NVSYNCPT_INVALID                    (-1)
 
+/* Attribute struct for sysfs min and max attributes */
+struct nvhost_syncpt_attr {
+       struct kobj_attribute attr;
+       struct nvhost_master *host;
+       int id;
+};
+
 struct nvhost_syncpt {
+       struct kobject *kobj;
        atomic_t *min_val;
        atomic_t *max_val;
        u32 *base_val;
@@ -43,9 +51,12 @@ struct nvhost_syncpt {
        u32 client_managed;
        atomic_t *lock_counts;
        u32 nb_mlocks;
+       struct nvhost_syncpt_attr *syncpt_attrs;
 };
 
-int nvhost_syncpt_init(struct nvhost_syncpt *);
+int nvhost_syncpt_init(struct nvhost_device *, struct nvhost_syncpt *);
+void nvhost_syncpt_deinit(struct nvhost_syncpt *);
+
 #define client_managed(id) (BIT(id) & sp->client_managed)
 #define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
 #define syncpt_op(sp) (syncpt_to_dev(sp)->op.syncpt)