video: tegra: nvmap: Add debugfs for iovmm allocations.
Krishna Reddy [Thu, 4 Aug 2011 22:14:49 +0000 (15:14 -0700)]
Original-Change-Id: Ic50111924d7adf7838926cb534bbf841b7e8003a
Reviewed-on: http://git-master/r/45358
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>

Rebase-Id: R6399e487b817aa16c39e685d3f7860d1eefa8b09

drivers/video/tegra/nvmap/nvmap.h
drivers/video/tegra/nvmap/nvmap_dev.c
drivers/video/tegra/nvmap/nvmap_handle.c

index 8bc70a9..8798949 100644 (file)
@@ -114,6 +114,7 @@ struct nvmap_client {
        bool                            super;
        atomic_t                        count;
        struct task_struct              *task;
+       struct list_head                list;
        struct nvmap_carveout_commit    carveout_commit[0];
 };
 
index 1ebb1f4..d30100d 100644 (file)
@@ -79,6 +79,8 @@ struct nvmap_device {
        struct nvmap_carveout_node *heaps;
        int nr_carveouts;
        struct nvmap_share iovmm_master;
+       struct list_head clients;
+       spinlock_t      clients_lock;
 };
 
 struct nvmap_device *nvmap_dev;
@@ -652,6 +654,9 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
        mutex_init(&client->ref_lock);
        atomic_set(&client->count, 1);
 
+       spin_lock(&dev->clients_lock);
+       list_add(&client->list, &dev->clients);
+       spin_unlock(&dev->clients_lock);
        return client;
 }
 
@@ -699,6 +704,9 @@ static void destroy_client(struct nvmap_client *client)
        if (client->task)
                put_task_struct(client->task);
 
+       spin_lock(&client->dev->clients_lock);
+       list_del(&client->list);
+       spin_unlock(&client->dev->clients_lock);
        kfree(client);
 }
 
@@ -956,17 +964,18 @@ static void client_stringify(struct nvmap_client *client, struct seq_file *s)
 {
        char task_comm[TASK_COMM_LEN];
        if (!client->task) {
-               seq_printf(s, "%-16s %16s %8u", client->name, "kernel", 0);
+               seq_printf(s, "%-18s %18s %8u", client->name, "kernel", 0);
                return;
        }
        get_task_comm(task_comm, client->task);
-       seq_printf(s, "%-16s %16s %8u", client->name, task_comm,
+       seq_printf(s, "%-18s %18s %8u", client->name, task_comm,
                   client->task->pid);
 }
 
 static void allocations_stringify(struct nvmap_client *client,
                                  struct seq_file *s)
 {
+       unsigned long base = 0;
        struct rb_node *n = rb_first(&client->handle_refs);
 
        for (; n != NULL; n = rb_next(n)) {
@@ -974,9 +983,12 @@ static void allocations_stringify(struct nvmap_client *client,
                        rb_entry(n, struct nvmap_handle_ref, node);
                struct nvmap_handle *handle = ref->handle;
                if (handle->alloc && !handle->heap_pgalloc) {
-                       seq_printf(s, "%-16s %-16s %8lx %10u\n", "", "",
+                       seq_printf(s, "%-18s %-18s %8lx %10u\n", "", "",
                                        (unsigned long)(handle->carveout->base),
                                        handle->size);
+               } else if (handle->alloc && handle->heap_pgalloc) {
+                       seq_printf(s, "%-18s %-18s %8lx %10u\n", "", "",
+                                       base, handle->size);
                }
        }
 }
@@ -989,6 +1001,10 @@ static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
        unsigned int total = 0;
 
        spin_lock_irqsave(&node->clients_lock, flags);
+       seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
+               "SIZE");
+       seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
+                                       "BASE", "SIZE");
        list_for_each_entry(commit, &node->clients, list) {
                struct nvmap_client *client =
                        get_client_from_carveout_commit(node, commit);
@@ -998,7 +1014,7 @@ static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
                seq_printf(s, "\n");
                total += commit->commit;
        }
-       seq_printf(s, "%-16s %-16s %8u %10u\n", "total", "", 0, total);
+       seq_printf(s, "%-18s %-18s %8u %10u\n", "total", "", 0, total);
        spin_unlock_irqrestore(&node->clients_lock, flags);
 
        return 0;
@@ -1025,6 +1041,8 @@ static int nvmap_debug_clients_show(struct seq_file *s, void *unused)
        unsigned int total = 0;
 
        spin_lock_irqsave(&node->clients_lock, flags);
+       seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
+               "SIZE");
        list_for_each_entry(commit, &node->clients, list) {
                struct nvmap_client *client =
                        get_client_from_carveout_commit(node, commit);
@@ -1032,7 +1050,7 @@ static int nvmap_debug_clients_show(struct seq_file *s, void *unused)
                seq_printf(s, " %10u\n", commit->commit);
                total += commit->commit;
        }
-       seq_printf(s, "%-16s %-16s %8u %10u\n", "total", "", 0, total);
+       seq_printf(s, "%-18s %18s %8u %10u\n", "total", "", 0, total);
        spin_unlock_irqrestore(&node->clients_lock, flags);
 
        return 0;
@@ -1050,6 +1068,80 @@ static struct file_operations debug_clients_fops = {
        .release = single_release,
 };
 
+static int nvmap_debug_iovmm_clients_show(struct seq_file *s, void *unused)
+{
+       unsigned long flags;
+       unsigned int total = 0;
+       struct nvmap_client *client;
+       struct nvmap_device *dev = s->private;
+
+       spin_lock_irqsave(&dev->clients_lock, flags);
+       seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
+               "SIZE");
+       list_for_each_entry(client, &dev->clients, list) {
+               client_stringify(client, s);
+               seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
+               total += atomic_read(&client->iovm_commit);
+       }
+       seq_printf(s, "%-18s %18s %8u %10u\n", "total", "", 0, total);
+       spin_unlock_irqrestore(&dev->clients_lock, flags);
+
+       return 0;
+}
+
+static int nvmap_debug_iovmm_clients_open(struct inode *inode,
+                                           struct file *file)
+{
+       return single_open(file, nvmap_debug_iovmm_clients_show,
+                           inode->i_private);
+}
+
+static const struct file_operations debug_iovmm_clients_fops = {
+       .open = nvmap_debug_iovmm_clients_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int nvmap_debug_iovmm_allocations_show(struct seq_file *s, void *unused)
+{
+       unsigned long flags;
+       unsigned int total = 0;
+       struct nvmap_client *client;
+       struct nvmap_device *dev = s->private;
+
+       spin_lock_irqsave(&dev->clients_lock, flags);
+       seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
+               "SIZE");
+       seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
+                                       "BASE", "SIZE");
+       list_for_each_entry(client, &dev->clients, list) {
+               client_stringify(client, s);
+               seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
+               allocations_stringify(client, s);
+               seq_printf(s, "\n");
+               total += atomic_read(&client->iovm_commit);
+       }
+       seq_printf(s, "%-18s %-18s %8u %10u\n", "total", "", 0, total);
+       spin_unlock_irqrestore(&dev->clients_lock, flags);
+
+       return 0;
+}
+
+static int nvmap_debug_iovmm_allocations_open(struct inode *inode,
+                                               struct file *file)
+{
+       return single_open(file, nvmap_debug_iovmm_allocations_show,
+                           inode->i_private);
+}
+
+static const struct file_operations debug_iovmm_allocations_fops = {
+       .open = nvmap_debug_iovmm_allocations_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static int nvmap_probe(struct platform_device *pdev)
 {
        struct nvmap_platform_data *plat = pdev->dev.platform_data;
@@ -1112,6 +1204,8 @@ static int nvmap_probe(struct platform_device *pdev)
 
        spin_lock_init(&dev->ptelock);
        spin_lock_init(&dev->handle_lock);
+       INIT_LIST_HEAD(&dev->clients);
+       spin_lock_init(&dev->clients_lock);
 
        for (i = 0; i < NVMAP_NUM_PTES; i++) {
                unsigned long addr;
@@ -1204,6 +1298,16 @@ static int nvmap_probe(struct platform_device *pdev)
                        }
                }
        }
+       if (!IS_ERR_OR_NULL(nvmap_debug_root)) {
+               struct dentry *iovmm_root =
+                       debugfs_create_dir("iovmm", nvmap_debug_root);
+               if (!IS_ERR_OR_NULL(iovmm_root)) {
+                       debugfs_create_file("clients", 0664, iovmm_root,
+                               dev, &debug_iovmm_clients_fops);
+                       debugfs_create_file("allocations", 0664, iovmm_root,
+                               dev, &debug_iovmm_allocations_fops);
+               }
+       }
 
        platform_set_drvdata(pdev, dev);
        nvmap_dev = dev;
index a4412af..e536867 100644 (file)
@@ -270,11 +270,10 @@ static void alloc_handle(struct nvmap_client *client,
                /* increment the committed IOVM space prior to allocation
                 * to avoid race conditions with other threads simultaneously
                 * allocating. */
-               if (!client->super)
-                       commit = atomic_add_return(reserved,
-                                                  &client->iovm_commit);
+               commit = atomic_add_return(reserved,
+                                           &client->iovm_commit);
 
-               if (commit < client->iovm_limit)
+               if (commit < client->iovm_limit || client->super)
                        ret = handle_page_alloc(client, h, false);
                else
                        ret = -ENOMEM;
@@ -283,8 +282,7 @@ static void alloc_handle(struct nvmap_client *client,
                        h->heap_pgalloc = true;
                        h->alloc = true;
                } else {
-                       if (!client->super)
-                               atomic_sub(reserved, &client->iovm_commit);
+                       atomic_sub(reserved, &client->iovm_commit);
                }
 
        } else if (type & NVMAP_HEAP_SYSMEM) {
@@ -442,7 +440,7 @@ void nvmap_free_handle_id(struct nvmap_client *client, unsigned long id)
        pins = atomic_read(&ref->pin);
        rb_erase(&ref->node, &client->handle_refs);
 
-       if (h->alloc && h->heap_pgalloc && !h->pgalloc.contig && !client->super)
+       if (h->alloc && h->heap_pgalloc && !h->pgalloc.contig)
                atomic_sub(h->size, &client->iovm_commit);
 
        if (h->alloc && !h->heap_pgalloc) {
@@ -572,10 +570,10 @@ struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
 
        /* verify that adding this handle to the process' access list
         * won't exceed the IOVM limit */
-       if (h->heap_pgalloc && !h->pgalloc.contig && !client->super) {
+       if (h->heap_pgalloc && !h->pgalloc.contig) {
                int oc;
                oc = atomic_add_return(h->size, &client->iovm_commit);
-               if (oc > client->iovm_limit) {
+               if (oc > client->iovm_limit && !client->super) {
                        atomic_sub(h->size, &client->iovm_commit);
                        nvmap_handle_put(h);
                        nvmap_err(client, "duplicating %p in %s over-commits"