video: tegra: nvmap: Fix per client accounting
authorRebecca Schultz Zavin <rebecca@android.com>
Tue, 16 Nov 2010 01:02:16 +0000 (17:02 -0800)
committerRebecca Schultz Zavin <rebecca@android.com>
Mon, 6 Dec 2010 20:02:50 +0000 (12:02 -0800)
Fix the way the total number of carveout allocations is
managed per client.

Change-Id: I3e12e2a98a74cafc1f4c51a48e3c3c549e930160
Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
drivers/video/tegra/nvmap/nvmap_dev.c
drivers/video/tegra/nvmap/nvmap_handle.c

index a899bb4ef1b9e18ccb4e70cc563d11734a7faa61..1961c714efe596a93ba52ea734f90ceb793ae23d 100644 (file)
@@ -50,7 +50,7 @@ struct nvmap_carveout_node {
        struct nvmap_heap       *carveout;
        int                     index;
        struct list_head        clients;
-       struct mutex            clients_mutex;
+       spinlock_t              clients_lock;
 };
 
 struct nvmap_device {
@@ -277,8 +277,10 @@ void nvmap_carveout_commit_add(struct nvmap_client *client,
                               struct nvmap_carveout_node *node,
                               size_t len)
 {
-       mutex_lock(&node->clients_mutex);
+       unsigned long flags;
 
+       nvmap_ref_lock(client);
+       spin_lock_irqsave(&node->clients_lock, flags);
        BUG_ON(list_empty(&client->carveout_commit[node->index].list) &&
               client->carveout_commit[node->index].commit != 0);
 
@@ -289,23 +291,26 @@ void nvmap_carveout_commit_add(struct nvmap_client *client,
                list_add(&client->carveout_commit[node->index].list,
                         &node->clients);
        }
-       mutex_unlock(&node->clients_mutex);
+       spin_unlock_irqrestore(&node->clients_lock, flags);
+       nvmap_ref_unlock(client);
 }
 
 void nvmap_carveout_commit_subtract(struct nvmap_client *client,
                                    struct nvmap_carveout_node *node,
                                    size_t len)
 {
+       unsigned long flags;
+
        if (!client)
                return;
 
-       mutex_lock(&node->clients_mutex);
+       spin_lock_irqsave(&node->clients_lock, flags);
        client->carveout_commit[node->index].commit -= len;
        BUG_ON(client->carveout_commit[node->index].commit < 0);
        /* if no more allocation in this carveout for this node, delete it */
        if (!client->carveout_commit[node->index].commit)
                list_del_init(&client->carveout_commit[node->index].list);
-       mutex_unlock(&node->clients_mutex);
+       spin_unlock_irqrestore(&node->clients_lock, flags);
 }
 
 static struct nvmap_client* get_client_from_carveout_commit(
@@ -316,7 +321,6 @@ static struct nvmap_client* get_client_from_carveout_commit(
                                               carveout_commit);
 }
 
-
 struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
                                              size_t len, size_t align,
                                              unsigned long usage,
@@ -341,10 +345,8 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
                        if (nvmap_flush_heap_block(client, block, len)) {
                                nvmap_heap_free(block);
                                return NULL;
-                       } else {
-                               nvmap_carveout_commit_add(client, co_heap, len);
+                       } else
                                return block;
-                       }
                }
        }
 
@@ -764,32 +766,36 @@ static void client_stringify(struct nvmap_client *client, struct seq_file *s)
 static void allocations_stringify(struct nvmap_client *client,
                                  struct seq_file *s)
 {
-       struct rb_node *n = client->handle_refs.rb_node;
+       struct rb_node *n = rb_first(&client->handle_refs);
+       unsigned long long total = 0;
 
        for (; n != NULL; n = rb_next(n)) {
                struct nvmap_handle_ref *ref =
                        rb_entry(n, struct nvmap_handle_ref, node);
                struct nvmap_handle *handle = ref->handle;
-               if (!handle->heap_pgalloc)
+               if (handle->alloc && !handle->heap_pgalloc) {
                        seq_printf(s, " %8u@%8lx ", handle->size,
                                   handle->carveout->base);
+                       total += handle->size;
+               }
        }
-       seq_printf(s, "\n");
+       seq_printf(s, " total: %llu\n", total);
 }
 
 static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
 {
        struct nvmap_carveout_node *node = s->private;
        struct nvmap_carveout_commit *commit;
+       unsigned long flags;
 
-       mutex_lock(&node->clients_mutex);
+       spin_lock_irqsave(&node->clients_lock, flags);
        list_for_each_entry(commit, &node->clients, list) {
                struct nvmap_client *client =
                        get_client_from_carveout_commit(node, commit);
                client_stringify(client, s);
                allocations_stringify(client, s);
        }
-       mutex_unlock(&node->clients_mutex);
+       spin_unlock_irqrestore(&node->clients_lock, flags);
 
        return 0;
 }
@@ -811,15 +817,16 @@ static int nvmap_debug_clients_show(struct seq_file *s, void *unused)
 {
        struct nvmap_carveout_node *node = s->private;
        struct nvmap_carveout_commit *commit;
+       unsigned long flags;
 
-       mutex_lock(&node->clients_mutex);
+       spin_lock_irqsave(&node->clients_lock, flags);
        list_for_each_entry(commit, &node->clients, list) {
                struct nvmap_client *client =
                        get_client_from_carveout_commit(node, commit);
                client_stringify(client, s);
                seq_printf(s, " %8u\n", commit->commit);
        }
-       mutex_unlock(&node->clients_mutex);
+       spin_unlock_irqrestore(&node->clients_lock, flags);
 
        return 0;
 }
@@ -965,7 +972,7 @@ static int nvmap_probe(struct platform_device *pdev)
                        goto fail_heaps;
                }
                dev->nr_carveouts++;
-               mutex_init(&node->clients_mutex);
+               spin_lock_init(&node->clients_lock);
                node->index = i;
                INIT_LIST_HEAD(&node->clients);
                node->heap_bit = co->usage_mask;
index 09502bff4883bf3bc33447162cb9d8d885b3158c..4455c8d1cce10c590e06b1bf2a070b2141b6b8e7 100644 (file)
@@ -81,11 +81,6 @@ void _nvmap_handle_free(struct nvmap_handle *h)
                goto out;
 
        if (!h->heap_pgalloc) {
-               mutex_lock(&h->lock);
-               nvmap_carveout_commit_subtract(h->owner,
-                       nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
-                       h->size);
-               mutex_unlock(&h->lock);
                nvmap_heap_free(h->carveout);
                goto out;
        }
@@ -213,6 +208,9 @@ static void alloc_handle(struct nvmap_client *client, size_t align,
                        h->carveout = b;
                        h->heap_pgalloc = false;
                        h->alloc = true;
+                       nvmap_carveout_commit_add(client,
+                               nvmap_heap_to_arg(nvmap_block_to_heap(b)),
+                               h->size);
                }
        } else if (type & NVMAP_HEAP_IOVMM) {
                size_t reserved = PAGE_ALIGN(h->size);
@@ -367,6 +365,11 @@ void nvmap_free_handle_id(struct nvmap_client *client, unsigned long id)
        if (h->alloc && h->heap_pgalloc && !h->pgalloc.contig)
                atomic_sub(h->size, &client->iovm_commit);
 
+       if (h->alloc && !h->heap_pgalloc)
+               nvmap_carveout_commit_subtract(client,
+               nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
+               h->size);
+
        nvmap_ref_unlock(client);
 
        if (pins)
@@ -499,6 +502,11 @@ struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
                return ERR_PTR(-ENOMEM);
        }
 
+       if (!h->heap_pgalloc)
+               nvmap_carveout_commit_add(client,
+                       nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
+                       h->size);
+
        atomic_set(&ref->dupes, 1);
        ref->handle = h;
        atomic_set(&ref->pin, 0);