video: tegra: host: Tegra12 updates to host
[linux-3.10.git] / drivers / video / tegra / host / nvhost_allocator.h
1 /*
2  * drivers/video/tegra/host/nvhost_allocator.h
3  *
4  * nvhost allocator
5  *
6  * Copyright (c) 2011, NVIDIA CORPORATION.  All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 #ifndef __NVHOST_ALLOCATOR_H__
22 #define __NVHOST_ALLOCATOR_H__
23
24 #include <linux/rbtree.h>
25 #include <linux/rwsem.h>
26 #include <linux/slab.h>
27
28 /* #define ALLOCATOR_DEBUG */
29
30 struct allocator_block;
31
32 /* main struct */
33 struct nvhost_allocator {
34
35         char name[32];                  /* name for allocator */
36         struct rb_root rb_root;         /* rb tree root for blocks */
37
38         u32 base;                       /* min value of this linear space */
39         u32 limit;                      /* max value = limit - 1 */
40         u32 align;                      /* alignment size, power of 2 */
41
42         struct nvhost_alloc_block *block_first; /* first block in list */
43         struct nvhost_alloc_block *block_recent; /* last visited block */
44
45         u32 first_free_addr;            /* first free addr,
46                                            non-contigous allocation preferred start,
47                                            in order to pick up small holes */
48         u32 last_free_addr;             /* last free addr,
49                                            contiguous allocation preferred start */
50         u32 cached_hole_size;           /* max free hole size up to last_free_addr */
51         u32 block_count;                /* number of blocks */
52
53         struct rw_semaphore rw_sema;    /* lock */
54         struct kmem_cache *block_cache; /* slab cache */
55
56         int (*alloc)(struct nvhost_allocator *allocator,
57                 u32 *addr, u32 len);
58         int (*alloc_nc)(struct nvhost_allocator *allocator,
59                 u32 *addr, u32 len,
60                 struct nvhost_alloc_block **pblock);
61         int (*free)(struct nvhost_allocator *allocator,
62                 u32 addr, u32 len);
63         void (*free_nc)(struct nvhost_allocator *allocator,
64                 struct nvhost_alloc_block *block);
65 };
66
67 /* a block of linear space range [start, end) */
68 struct nvhost_alloc_block {
69         struct nvhost_allocator *allocator;     /* parent allocator */
70         struct rb_node rb;                      /* rb tree node */
71
72         u32 start;                              /* linear space range [start, end) */
73         u32 end;
74
75         void *priv;                             /* backing structure for this linear space block
76                                                    page table, comp tag, etc */
77
78         struct nvhost_alloc_block *prev;        /* prev block with lower address */
79         struct nvhost_alloc_block *next;        /* next block with higher address */
80
81         bool nc_block;
82         struct nvhost_alloc_block *nc_prev;     /* prev block for non-contiguous allocation */
83         struct nvhost_alloc_block *nc_next;     /* next block for non-contiguous allocation */
84 };
85
86 int nvhost_allocator_init(struct nvhost_allocator *allocator,
87                         const char *name, u32 base, u32 size, u32 align);
88 void nvhost_allocator_destroy(struct nvhost_allocator *allocator);
89
90 int nvhost_block_alloc(struct nvhost_allocator *allocator,
91                         u32 *addr, u32 len);
92 int nvhost_block_alloc_nc(struct nvhost_allocator *allocator,
93                         u32 *addr, u32 len,
94                         struct nvhost_alloc_block **pblock);
95
96 int nvhost_block_free(struct nvhost_allocator *allocator,
97                         u32 addr, u32 len);
98 void nvhost_block_free_nc(struct nvhost_allocator *allocator,
99                         struct nvhost_alloc_block *block);
100
101 #if defined(ALLOCATOR_DEBUG)
102
103 #define allocator_dbg(alloctor, format, arg...)                         \
104 do {                                                            \
105         if (1)                                                  \
106                 printk(KERN_DEBUG "nvhost_allocator (%s) %s: " format "\n", alloctor->name, __func__, ##arg);\
107 } while (0)
108
109 static inline void
110 nvhost_allocator_dump(struct nvhost_allocator *allocator) {
111         struct nvhost_alloc_block *block;
112         u32 count = 0;
113
114         down_read(&allocator->rw_sema);
115         for (block = allocator->block_first; block; block = block->next) {
116                 allocator_dbg(allocator, "block %d - %d:%d, nc %d",
117                         count++, block->start, block->end, block->nc_block);
118
119                 if (block->prev)
120                         BUG_ON(block->prev->end > block->start);
121                 if (block->next)
122                         BUG_ON(block->next->start < block->end);
123         }
124         allocator_dbg(allocator, "tracked count %d, actual count %d",
125                 allocator->block_count, count);
126         allocator_dbg(allocator, "first block %d:%d",
127                 allocator->block_first ? allocator->block_first->start : -1,
128                 allocator->block_first ? allocator->block_first->end : -1);
129         allocator_dbg(allocator, "first free addr %d", allocator->first_free_addr);
130         allocator_dbg(allocator, "last free addr %d", allocator->last_free_addr);
131         allocator_dbg(allocator, "cached hole size %d", allocator->cached_hole_size);
132         up_read(&allocator->rw_sema);
133
134         BUG_ON(count != allocator->block_count);
135 }
136
137 static inline void
138 nvhost_allocator_dump_nc_list(
139                 struct nvhost_allocator *allocator,
140                 struct nvhost_alloc_block *block)
141 {
142         down_read(&allocator->rw_sema);
143         while (block) {
144                 printk(KERN_DEBUG "non-contiguous block %d:%d\n",
145                         block->start, block->end);
146                 block = block->nc_next;
147         }
148         up_read(&allocator->rw_sema);
149 }
150
151 void nvhost_allocator_test(void);
152
153 #else /* ALLOCATOR_DEBUG */
154
155 #define allocator_dbg(format, arg...)
156
157 #endif /* ALLOCATOR_DEBUG */
158
159 #endif /*__NVHOST_ALLOCATOR_H__ */