summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/nvmap
diff options
context:
space:
mode:
authorRebecca Schultz Zavin <rebecca@android.com>2010-10-26 16:41:40 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:36:35 -0800
commite795bb28790bab34aeb3346949bd6fddfb746f6e (patch)
treec53aafe8b316b6e5aaab0b2aed77832d599d1ba8 /drivers/video/tegra/nvmap
parente849e2c1de2e3a2882b6a35c3b658e15b46d7a86 (diff)
video: tegra: nvmap: Track carveout clients
This patch adds the ability to track the total allocations in a given carveout heap by client. It also adds a sys file to print the list of clients, their pids and their respective carveout sizes Change-Id: I34fc97c3be574d2bd30d7594320ff05f6e13c476 Signed-off-by: Rebecca Schultz Zavin <rebecca@android.com>
Diffstat (limited to 'drivers/video/tegra/nvmap')
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h31
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c155
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c3
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c5
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.h2
5 files changed, 154 insertions, 42 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
index 5ba5793d3257..fd4bcd7a7081 100644
--- a/drivers/video/tegra/nvmap/nvmap.h
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -92,15 +92,22 @@ struct nvmap_share {
#endif
};
+struct nvmap_carveout_commit {
+ size_t commit;
+ struct list_head list;
+};
+
struct nvmap_client {
- struct nvmap_device *dev;
- struct nvmap_share *share;
- struct rb_root handle_refs;
- atomic_t iovm_commit;
- size_t iovm_limit;
- spinlock_t ref_lock;
- bool super;
- atomic_t count;
+ struct nvmap_device *dev;
+ struct nvmap_share *share;
+ struct rb_root handle_refs;
+ atomic_t iovm_commit;
+ size_t iovm_limit;
+ spinlock_t ref_lock;
+ bool super;
+ atomic_t count;
+ struct task_struct *task;
+ struct nvmap_carveout_commit carveout_commit[0];
};
/* handle_ref objects are client-local references to an nvmap_handle;
@@ -146,6 +153,14 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *dev,
unsigned long nvmap_carveout_usage(struct nvmap_client *c,
struct nvmap_heap_block *b);
+struct nvmap_carveout_node;
+void nvmap_carveout_commit_add(struct nvmap_client *client,
+ struct nvmap_carveout_node *node, size_t len);
+
+void nvmap_carveout_commit_subtract(struct nvmap_client *client,
+ struct nvmap_carveout_node *node,
+ size_t len);
+
struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
unsigned long handle);
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index c6669ed86c24..681c84413ed3 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -44,9 +44,11 @@
#define NVMAP_NUM_PTES 64
struct nvmap_carveout_node {
- struct list_head heap_list;
unsigned int heap_bit;
struct nvmap_heap *carveout;
+ int index;
+ struct list_head clients;
+ struct mutex clients_mutex;
};
struct nvmap_device {
@@ -61,7 +63,8 @@ struct nvmap_device {
wait_queue_head_t pte_wait;
struct miscdevice dev_super;
struct miscdevice dev_user;
- struct list_head heaps;
+ struct nvmap_carveout_node *heaps;
+ int nr_carveouts;
struct nvmap_share iovmm_master;
};
@@ -220,8 +223,10 @@ unsigned long nvmap_carveout_usage(struct nvmap_client *c,
{
struct nvmap_heap *h = nvmap_block_to_heap(b);
struct nvmap_carveout_node *n;
+ int i;
- list_for_each_entry(n, &c->dev->heaps, heap_list) {
+ for (i = 0; i < c->dev->nr_carveouts; i++) {
+ n = &c->dev->heaps[i];
if (n->carveout == h)
return n->heap_bit;
}
@@ -261,6 +266,47 @@ static int nvmap_flush_heap_block(struct nvmap_client *client,
return 0;
}
+void nvmap_carveout_commit_add(struct nvmap_client *client,
+ struct nvmap_carveout_node *node,
+ size_t len)
+{
+ mutex_lock(&node->clients_mutex);
+
+ BUG_ON(list_empty(&client->carveout_commit[node->index].list) &&
+ client->carveout_commit[node->index].commit != 0);
+
+ client->carveout_commit[node->index].commit += len;
+ /* if this client isn't already on the list of nodes for this heap,
+ add it */
+ if (list_empty(&client->carveout_commit[node->index].list)) {
+ list_add(&client->carveout_commit[node->index].list,
+ &node->clients);
+ }
+ mutex_unlock(&node->clients_mutex);
+}
+
+void nvmap_carveout_commit_subtract(struct nvmap_client *client,
+ struct nvmap_carveout_node *node,
+ size_t len)
+{
+ mutex_lock(&node->clients_mutex);
+ 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);
+}
+
+static struct nvmap_client* get_client_from_carveout_commit(
+ struct nvmap_carveout_node *node, struct nvmap_carveout_commit *commit)
+{
+ struct nvmap_carveout_commit *first_commit = commit - node->index;
+ return (void *)first_commit - offsetof(struct nvmap_client,
+ carveout_commit);
+}
+
+
struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
size_t len, size_t align,
unsigned long usage,
@@ -268,9 +314,11 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
{
struct nvmap_carveout_node *co_heap;
struct nvmap_device *dev = client->dev;
+ int i;
- list_for_each_entry(co_heap, &dev->heaps, heap_list) {
+ for (i = 0; i < dev->nr_carveouts; i++) {
struct nvmap_heap_block *block;
+ co_heap = &dev->heaps[i];
if (!(co_heap->heap_bit & usage))
continue;
@@ -283,8 +331,10 @@ 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
+ } else {
+ nvmap_carveout_commit_add(client, co_heap, len);
return block;
+ }
}
}
@@ -370,11 +420,13 @@ struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
struct nvmap_client *nvmap_create_client(struct nvmap_device *dev)
{
struct nvmap_client *client;
+ int i;
if (WARN_ON(!dev))
return NULL;
- client = kzalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client) + (sizeof(struct nvmap_carveout_commit)
+ * dev->nr_carveouts), GFP_KERNEL);
if (!client)
return NULL;
@@ -388,6 +440,14 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev)
client->iovm_limit = nvmap_mru_vm_size(client->share->iovmm);
+ for (i = 0; i < dev->nr_carveouts; i++) {
+ INIT_LIST_HEAD(&client->carveout_commit[i].list);
+ client->carveout_commit[i].commit = 0;
+ }
+
+ get_task_struct(current);
+ client->task = current;
+
spin_lock_init(&client->ref_lock);
atomic_set(&client->count, 1);
@@ -397,6 +457,7 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev)
static void destroy_client(struct nvmap_client *client)
{
struct rb_node *n;
+ int i;
if (!client)
return;
@@ -421,6 +482,12 @@ static void destroy_client(struct nvmap_client *client)
kfree(ref);
}
+ for (i = 0; i < client->dev->nr_carveouts; i++)
+ list_del(&client->carveout_commit[i].list);
+
+ if (client->task)
+ put_task_struct(client->task);
+
kfree(client);
}
@@ -657,11 +724,35 @@ static ssize_t attr_show_usage(struct device *dev,
return sprintf(buf, "%08x\n", node->heap_bit);
}
+static ssize_t attr_show_clients(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvmap_carveout_node *node = nvmap_heap_device_to_arg(dev);
+ struct nvmap_carveout_commit *commit;
+ char *orig_buf = buf;
+
+ mutex_lock(&node->clients_mutex);
+ list_for_each_entry(commit, &node->clients, list) {
+ struct nvmap_client *client =
+ get_client_from_carveout_commit(node, commit);
+ char task_comm[sizeof(client->task->comm)];
+ get_task_comm(task_comm, client->task);
+ buf += sprintf(buf, "%16s %8u %8u\n", task_comm,
+ client->task->pid, commit->commit);
+ }
+ mutex_unlock(&node->clients_mutex);
+ return buf - orig_buf;
+}
+
static struct device_attribute heap_attr_show_usage =
__ATTR(usage, S_IRUGO, attr_show_usage, NULL);
+static struct device_attribute heap_attr_show_clients =
+ __ATTR(clients, S_IRUGO, attr_show_clients, NULL);
+
static struct attribute *heap_extra_attrs[] = {
&heap_attr_show_usage.attr,
+ &heap_attr_show_clients.attr,
NULL,
};
@@ -729,7 +820,6 @@ static int nvmap_probe(struct platform_device *pdev)
spin_lock_init(&dev->ptelock);
spin_lock_init(&dev->handle_lock);
- INIT_LIST_HEAD(&dev->heaps);
for (i = 0; i < NVMAP_NUM_PTES; i++) {
unsigned long addr;
@@ -773,24 +863,30 @@ static int nvmap_probe(struct platform_device *pdev)
goto fail;
}
+ dev->nr_carveouts = 0;
+ dev->heaps = kzalloc(sizeof(struct nvmap_carveout_node) *
+ plat->nr_carveouts, GFP_KERNEL);
+ if (!dev->heaps) {
+ e = -ENOMEM;
+ dev_err(&pdev->dev, "couldn't allocate carveout memory\n");
+ goto fail;
+ }
+
for (i = 0; i < plat->nr_carveouts; i++) {
- struct nvmap_carveout_node *node;
+ struct nvmap_carveout_node *node = &dev->heaps[i];
const struct nvmap_platform_carveout *co = &plat->carveouts[i];
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node) {
- e = -ENOMEM;
- dev_err(&pdev->dev, "couldn't allocate %s\n", co->name);
- goto fail;
- }
node->carveout = nvmap_heap_create(dev->dev_user.this_device,
co->name, co->base, co->size,
co->buddy_size, node);
if (!node->carveout) {
e = -ENOMEM;
- kfree(node);
dev_err(&pdev->dev, "couldn't create %s\n", co->name);
- goto fail;
+ goto fail_heaps;
}
+ dev->nr_carveouts++;
+ mutex_init(&node->clients_mutex);
+ node->index = i;
+ INIT_LIST_HEAD(&node->clients);
node->heap_bit = co->usage_mask;
if (nvmap_heap_create_group(node->carveout,
&heap_extra_attr_group))
@@ -798,24 +894,18 @@ static int nvmap_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "created carveout %s (%uKiB)\n",
co->name, co->size / 1024);
- list_add_tail(&node->heap_list, &dev->heaps);
}
- /* FIXME: walk platform data and create heaps */
-
platform_set_drvdata(pdev, dev);
nvmap_dev = dev;
return 0;
-fail:
- while (!list_empty(&dev->heaps)) {
- struct nvmap_carveout_node *node;
-
- node = list_first_entry(&dev->heaps,
- struct nvmap_carveout_node, heap_list);
- list_del(&node->heap_list);
+fail_heaps:
+ for (i = 0; i < dev->nr_carveouts; i++) {
+ struct nvmap_carveout_node *node = &dev->heaps[i];
nvmap_heap_remove_group(node->carveout, &heap_extra_attr_group);
nvmap_heap_destroy(node->carveout);
- kfree(node);
}
+fail:
+ kfree(dev->heaps);
nvmap_mru_destroy(&dev->iovmm_master);
if (dev->dev_super.minor != MISC_DYNAMIC_MINOR)
misc_deregister(&dev->dev_super);
@@ -835,6 +925,7 @@ static int nvmap_remove(struct platform_device *pdev)
struct nvmap_device *dev = platform_get_drvdata(pdev);
struct rb_node *n;
struct nvmap_handle *h;
+ int i;
misc_deregister(&dev->dev_super);
misc_deregister(&dev->dev_user);
@@ -850,16 +941,12 @@ static int nvmap_remove(struct platform_device *pdev)
nvmap_mru_destroy(&dev->iovmm_master);
- while (!list_empty(&dev->heaps)) {
- struct nvmap_carveout_node *node;
-
- node = list_first_entry(&dev->heaps,
- struct nvmap_carveout_node, heap_list);
- list_del(&node->heap_list);
+ for (i = 0; i < dev->nr_carveouts; i++) {
+ struct nvmap_carveout_node *node = &dev->heaps[i];
nvmap_heap_remove_group(node->carveout, &heap_extra_attr_group);
nvmap_heap_destroy(node->carveout);
- kfree(node);
}
+ kfree(dev->heaps);
free_vm_area(dev->vm_rgn);
kfree(dev);
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 2f50c0a1b8d3..be130b4be757 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -81,6 +81,9 @@ void _nvmap_handle_free(struct nvmap_handle *h)
goto out;
if (!h->heap_pgalloc) {
+ nvmap_carveout_commit_subtract(client,
+ nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
+ h->size);
nvmap_heap_free(h->carveout);
goto out;
}
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
index 2449b00f7d52..abc72cc99720 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.c
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -734,6 +734,11 @@ void *nvmap_heap_device_to_arg(struct device *dev)
return heap->arg;
}
+void *nvmap_heap_to_arg(struct nvmap_heap *heap)
+{
+ return heap->arg;
+}
+
/* nvmap_heap_destroy: frees all resources in heap */
void nvmap_heap_destroy(struct nvmap_heap *heap)
{
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.h b/drivers/video/tegra/nvmap/nvmap_heap.h
index 66854f26b353..40ee4ba02cb2 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.h
+++ b/drivers/video/tegra/nvmap/nvmap_heap.h
@@ -42,6 +42,8 @@ void nvmap_heap_destroy(struct nvmap_heap *heap);
void *nvmap_heap_device_to_arg(struct device *dev);
+void *nvmap_heap_to_arg(struct nvmap_heap *heap);
+
struct nvmap_heap_block *nvmap_heap_alloc(struct nvmap_heap *heap, size_t len,
size_t align, unsigned int prot);