gpu: ion: Add dump of memory map

Add dump of physical memory map, showing allocated and
free areas, to debugfs interface for heaps with carveout memory.

Change-Id: I9bda9f3e555e55570c95e652616ca1fcc25eb0ab
Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
This commit is contained in:
Olav Haugan
2012-05-25 11:58:56 -07:00
committed by Stephen Boyd
parent 4f3cadaf47
commit eeab21e633
5 changed files with 255 additions and 8 deletions

View File

@@ -1551,6 +1551,144 @@ static size_t ion_debug_heap_total(struct ion_client *client,
return size; return size;
} }
/**
* Searches through a clients handles to find if the buffer is owned
* by this client. Used for debug output.
* @param client pointer to candidate owner of buffer
* @param buf pointer to buffer that we are trying to find the owner of
* @return 1 if found, 0 otherwise
*/
static int ion_debug_find_buffer_owner(const struct ion_client *client,
const struct ion_buffer *buf)
{
struct rb_node *n;
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
const struct ion_handle *handle = rb_entry(n,
const struct ion_handle,
node);
if (handle->buffer == buf)
return 1;
}
return 0;
}
/**
* Adds mem_map_data pointer to the tree of mem_map
* Used for debug output.
* @param mem_map The mem_map tree
* @param data The new data to add to the tree
*/
static void ion_debug_mem_map_add(struct rb_root *mem_map,
struct mem_map_data *data)
{
struct rb_node **p = &mem_map->rb_node;
struct rb_node *parent = NULL;
struct mem_map_data *entry;
while (*p) {
parent = *p;
entry = rb_entry(parent, struct mem_map_data, node);
if (data->addr < entry->addr) {
p = &(*p)->rb_left;
} else if (data->addr > entry->addr) {
p = &(*p)->rb_right;
} else {
pr_err("%s: mem_map_data already found.", __func__);
BUG();
}
}
rb_link_node(&data->node, parent, p);
rb_insert_color(&data->node, mem_map);
}
/**
* Search for an owner of a buffer by iterating over all ION clients.
* @param dev ion device containing pointers to all the clients.
* @param buffer pointer to buffer we are trying to find the owner of.
* @return name of owner.
*/
const char *ion_debug_locate_owner(const struct ion_device *dev,
const struct ion_buffer *buffer)
{
struct rb_node *j;
const char *client_name = NULL;
for (j = rb_first(&dev->clients); j && !client_name;
j = rb_next(j)) {
struct ion_client *client = rb_entry(j, struct ion_client,
node);
if (ion_debug_find_buffer_owner(client, buffer))
client_name = client->name;
}
return client_name;
}
/**
* Create a mem_map of the heap.
* @param s seq_file to log error message to.
* @param heap The heap to create mem_map for.
* @param mem_map The mem map to be created.
*/
void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
struct rb_root *mem_map)
{
struct ion_device *dev = heap->dev;
struct rb_node *n;
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer =
rb_entry(n, struct ion_buffer, node);
if (buffer->heap->id == heap->id) {
struct mem_map_data *data =
kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
seq_printf(s, "ERROR: out of memory. "
"Part of memory map will not be logged\n");
break;
}
data->addr = buffer->priv_phys;
data->addr_end = buffer->priv_phys + buffer->size-1;
data->size = buffer->size;
data->client_name = ion_debug_locate_owner(dev, buffer);
ion_debug_mem_map_add(mem_map, data);
}
}
}
/**
* Free the memory allocated by ion_debug_mem_map_create
* @param mem_map The mem map to free.
*/
static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
{
if (mem_map) {
struct rb_node *n;
while ((n = rb_first(mem_map)) != 0) {
struct mem_map_data *data =
rb_entry(n, struct mem_map_data, node);
rb_erase(&data->node, mem_map);
kfree(data);
}
}
}
/**
* Print heap debug information.
* @param s seq_file to log message to.
* @param heap pointer to heap that we will print debug information for.
*/
static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
{
if (heap->ops->print_debug) {
struct rb_root mem_map = RB_ROOT;
ion_debug_mem_map_create(s, heap, &mem_map);
heap->ops->print_debug(heap, s, &mem_map);
ion_debug_mem_map_destroy(&mem_map);
}
}
static int ion_debug_heap_show(struct seq_file *s, void *unused) static int ion_debug_heap_show(struct seq_file *s, void *unused)
{ {
struct ion_heap *heap = s->private; struct ion_heap *heap = s->private;
@@ -1577,8 +1715,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
client->pid, size); client->pid, size);
} }
} }
if (heap->ops->print_debug) ion_heap_print_debug(s, heap);
heap->ops->print_debug(heap, s);
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return 0; return 0;
} }

View File

@@ -260,7 +260,8 @@ int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
return 0; return 0;
} }
static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s) static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *mem_map)
{ {
struct ion_carveout_heap *carveout_heap = struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap); container_of(heap, struct ion_carveout_heap, heap);
@@ -269,6 +270,44 @@ static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s)
carveout_heap->allocated_bytes); carveout_heap->allocated_bytes);
seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size); seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size);
if (mem_map) {
unsigned long base = carveout_heap->base;
unsigned long size = carveout_heap->total_size;
unsigned long end = base+size;
unsigned long last_end = base;
struct rb_node *n;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
for (n = rb_first(mem_map); n; n = rb_next(n)) {
struct mem_map_data *data =
rb_entry(n, struct mem_map_data, node);
const char *client_name = "(null)";
if (last_end < data->addr) {
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
"FREE", last_end, data->addr-1,
data->addr-last_end,
data->addr-last_end);
}
if (data->client_name)
client_name = data->client_name;
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
client_name, data->addr,
data->addr_end,
data->size, data->size);
last_end = data->addr_end+1;
}
if (last_end < end) {
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
last_end, end-1, end-last_end, end-last_end);
}
}
return 0; return 0;
} }

View File

@@ -572,7 +572,8 @@ int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
return 0; return 0;
} }
static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s) static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *mem_map)
{ {
unsigned long total_alloc; unsigned long total_alloc;
unsigned long total_size; unsigned long total_size;
@@ -597,6 +598,45 @@ static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s)
seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No"); seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No");
seq_printf(s, "reusable: %s\n", cp_heap->reusable ? "Yes" : "No"); seq_printf(s, "reusable: %s\n", cp_heap->reusable ? "Yes" : "No");
if (mem_map) {
unsigned long base = cp_heap->base;
unsigned long size = cp_heap->total_size;
unsigned long end = base+size;
unsigned long last_end = base;
struct rb_node *n;
seq_printf(s, "\nMemory Map\n");
seq_printf(s, "%16.s %14.s %14.s %14.s\n",
"client", "start address", "end address",
"size (hex)");
for (n = rb_first(mem_map); n; n = rb_next(n)) {
struct mem_map_data *data =
rb_entry(n, struct mem_map_data, node);
const char *client_name = "(null)";
if (last_end < data->addr) {
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
"FREE", last_end, data->addr-1,
data->addr-last_end,
data->addr-last_end);
}
if (data->client_name)
client_name = data->client_name;
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
client_name, data->addr,
data->addr_end,
data->size, data->size);
last_end = data->addr_end+1;
}
if (last_end < end) {
seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
last_end, end-1, end-last_end, end-last_end);
}
}
return 0; return 0;
} }
@@ -917,6 +957,14 @@ void ion_cp_heap_destroy(struct ion_heap *heap)
cp_heap = NULL; cp_heap = NULL;
} }
void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
unsigned long *size) \
{
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
*base = cp_heap->base;
*size = cp_heap->total_size;
}
/* SCM related code for locking down memory for content protection */ /* SCM related code for locking down memory for content protection */

View File

@@ -143,7 +143,8 @@ struct ion_heap_ops {
unsigned long iova_length, unsigned long iova_length,
unsigned long flags); unsigned long flags);
void (*unmap_iommu)(struct ion_iommu_map *data); void (*unmap_iommu)(struct ion_iommu_map *data);
int (*print_debug)(struct ion_heap *heap, struct seq_file *s); int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *mem_map);
int (*secure_heap)(struct ion_heap *heap); int (*secure_heap)(struct ion_heap *heap);
int (*unsecure_heap)(struct ion_heap *heap); int (*unsecure_heap)(struct ion_heap *heap);
}; };
@@ -173,7 +174,22 @@ struct ion_heap {
const char *name; const char *name;
}; };
/**
* struct mem_map_data - represents information about the memory map for a heap
* @node: rb node used to store in the tree of mem_map_data
* @addr: start address of memory region.
* @addr: end address of memory region.
* @size: size of memory region
* @client_name: name of the client who owns this buffer.
*
*/
struct mem_map_data {
struct rb_node node;
unsigned long addr;
unsigned long addr_end;
unsigned long size;
const char *client_name;
};
#define iommu_map_domain(__m) ((__m)->domain_info[1]) #define iommu_map_domain(__m) ((__m)->domain_info[1])
#define iommu_map_partition(__m) ((__m)->domain_info[0]) #define iommu_map_partition(__m) ((__m)->domain_info[0])
@@ -286,4 +302,9 @@ int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
void *uaddr, unsigned long offset, unsigned long len, void *uaddr, unsigned long offset, unsigned long len,
unsigned int cmd); unsigned int cmd);
void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
unsigned long *size);
void ion_mem_map_show(struct ion_heap *heap);
#endif /* _ION_PRIV_H */ #endif /* _ION_PRIV_H */

View File

@@ -214,7 +214,8 @@ int ion_system_heap_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
return 0; return 0;
} }
static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s) static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *unused)
{ {
seq_printf(s, "total bytes currently allocated: %lx\n", seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_heap_allocated)); (unsigned long) atomic_read(&system_heap_allocated));
@@ -417,7 +418,8 @@ int ion_system_contig_heap_cache_ops(struct ion_heap *heap,
} }
static int ion_system_contig_print_debug(struct ion_heap *heap, static int ion_system_contig_print_debug(struct ion_heap *heap,
struct seq_file *s) struct seq_file *s,
const struct rb_root *unused)
{ {
seq_printf(s, "total bytes currently allocated: %lx\n", seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_contig_heap_allocated)); (unsigned long) atomic_read(&system_contig_heap_allocated));