diff options
author | Lajos Molnar <molnar@ti.com> | 2011-07-13 22:13:54 -0400 |
---|---|---|
committer | Paolo Pisati <paolo.pisati@canonical.com> | 2012-08-17 04:19:06 -0400 |
commit | 0200964daf35597a1b44165eb3ff4236e75ee318 (patch) | |
tree | 8e3b4f8afdcafee0021f4b99224ae493d7b5417b | |
parent | 9eae825bfa7dcc2f6015b6d091c254e36f280244 (diff) |
OMAP:TILER: Add debugfs interfaces for Tiler
Added <debugfs>/tiler/map/2x1 file which contains the TILER container map
subsampled 2x1. Reading this file will perform a dump of the tiler container.
Added <debugfs/tiler/alloc_debug debugfs parameter. Setting this parameter
to a non-zero value will cause debug prints for each area allocation and
deallocation.
Signed-off-by: Lajos Molnar <molnar@ti.com>
Signed-off-by: Andy Gross<andy.gross@ti.com>
-rw-r--r-- | drivers/media/video/tiler/tiler-main.c | 218 |
1 files changed, 217 insertions, 1 deletions
diff --git a/drivers/media/video/tiler/tiler-main.c b/drivers/media/video/tiler/tiler-main.c index 92aac12dc3a..5feb83507a2 100644 --- a/drivers/media/video/tiler/tiler-main.c +++ b/drivers/media/video/tiler/tiler-main.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/pagemap.h> /* page_cache_release() */ | 31 | #include <linux/pagemap.h> /* page_cache_release() */ |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/debugfs.h> | ||
35 | #include <linux/seq_file.h> | ||
34 | 36 | ||
35 | #include <mach/dmm.h> | 37 | #include <mach/dmm.h> |
36 | #include "tmm.h" | 38 | #include "tmm.h" |
@@ -40,6 +42,7 @@ | |||
40 | static bool ssptr_id = CONFIG_TILER_SSPTR_ID; | 42 | static bool ssptr_id = CONFIG_TILER_SSPTR_ID; |
41 | static uint default_align = CONFIG_TILER_ALIGNMENT; | 43 | static uint default_align = CONFIG_TILER_ALIGNMENT; |
42 | static uint granularity = CONFIG_TILER_GRANULARITY; | 44 | static uint granularity = CONFIG_TILER_GRANULARITY; |
45 | static u32 tiler_alloc_debug; | ||
43 | 46 | ||
44 | /* | 47 | /* |
45 | * We can only change ssptr_id if there are no blocks allocated, so that | 48 | * We can only change ssptr_id if there are no blocks allocated, so that |
@@ -52,10 +55,14 @@ module_param_named(align, default_align, uint, 0644); | |||
52 | MODULE_PARM_DESC(align, "Default block ssptr alignment"); | 55 | MODULE_PARM_DESC(align, "Default block ssptr alignment"); |
53 | module_param_named(grain, granularity, uint, 0644); | 56 | module_param_named(grain, granularity, uint, 0644); |
54 | MODULE_PARM_DESC(grain, "Granularity (bytes)"); | 57 | MODULE_PARM_DESC(grain, "Granularity (bytes)"); |
58 | module_param_named(alloc_debug, tiler_alloc_debug, uint, 0644); | ||
59 | MODULE_PARM_DESC(alloc_debug, "Allocation debug flag"); | ||
55 | 60 | ||
56 | struct tiler_dev { | 61 | struct tiler_dev { |
57 | struct cdev cdev; | 62 | struct cdev cdev; |
58 | }; | 63 | }; |
64 | static struct dentry *dbgfs; | ||
65 | static struct dentry *dbg_map; | ||
59 | 66 | ||
60 | struct platform_driver tiler_driver_ldm = { | 67 | struct platform_driver tiler_driver_ldm = { |
61 | .driver = { | 68 | .driver = { |
@@ -163,6 +170,152 @@ static u32 _m_get_id(void) | |||
163 | return id; | 170 | return id; |
164 | } | 171 | } |
165 | 172 | ||
173 | #define TILER_WIDTH 256 | ||
174 | #define TILER_HEIGHT 128 | ||
175 | |||
176 | static void fill_map(char **map, int div, struct tcm_area *a, char c, bool ovw) | ||
177 | { | ||
178 | int x, y; | ||
179 | for (y = a->p0.y; y <= a->p1.y; y++) | ||
180 | for (x = a->p0.x / div; x <= a->p1.x / div; x++) | ||
181 | if (map[y][x] == ' ' || ovw) | ||
182 | map[y][x] = c; | ||
183 | } | ||
184 | |||
185 | static void fill_map_pt(char **map, int div, struct tcm_pt *p, char c) | ||
186 | { | ||
187 | map[p->y][p->x / div] = c; | ||
188 | } | ||
189 | |||
190 | static char read_map_pt(char **map, int div, struct tcm_pt *p) | ||
191 | { | ||
192 | return map[p->y][p->x / div]; | ||
193 | } | ||
194 | |||
195 | static int map_width(int div, int x0, int x1) | ||
196 | { | ||
197 | return (x1 / div) - (x0 / div) + 1; | ||
198 | } | ||
199 | |||
200 | static void text_map(char **map, int div, char *nice, int y, int x0, int x1) | ||
201 | { | ||
202 | char *p = map[y] + (x0 / div); | ||
203 | int w = (map_width(div, x0, x1) - strlen(nice)) / 2; | ||
204 | if (w >= 0) { | ||
205 | p += w; | ||
206 | while (*nice) | ||
207 | *p++ = *nice++; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static void map_1d_info(char **map, int div, char *nice, struct tcm_area *a) | ||
212 | { | ||
213 | sprintf(nice, "%dK", tcm_sizeof(*a) * 4); | ||
214 | if (a->p0.y + 1 < a->p1.y) { | ||
215 | text_map(map, div, nice, (a->p0.y + a->p1.y) / 2, 0, | ||
216 | TILER_WIDTH - 1); | ||
217 | } else if (a->p0.y < a->p1.y) { | ||
218 | if (strlen(nice) < map_width(div, a->p0.x, TILER_WIDTH - 1)) | ||
219 | text_map(map, div, nice, a->p0.y, a->p0.x + div, | ||
220 | TILER_WIDTH - 1); | ||
221 | else if (strlen(nice) < map_width(div, 0, a->p1.x)) | ||
222 | text_map(map, div, nice, a->p1.y, 0, a->p1.y - div); | ||
223 | } else if (strlen(nice) + 1 < map_width(div, a->p0.x, a->p1.x)) { | ||
224 | text_map(map, div, nice, a->p0.y, a->p0.x, a->p1.x); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void map_2d_info(char **map, int div, char *nice, struct tcm_area *a) | ||
229 | { | ||
230 | sprintf(nice, "(%d*%d)", tcm_awidth(*a), tcm_aheight(*a)); | ||
231 | if (strlen(nice) + 1 < map_width(div, a->p0.x, a->p1.x)) | ||
232 | text_map(map, div, nice, (a->p0.y + a->p1.y) / 2, a->p0.x, | ||
233 | a->p1.x); | ||
234 | } | ||
235 | |||
236 | static void debug_allocation_map(struct seq_file *s) | ||
237 | { | ||
238 | int div = 2; | ||
239 | int i; | ||
240 | char **map, *global_map; | ||
241 | struct area_info *ai; | ||
242 | struct mem_info *mi; | ||
243 | struct tcm_area a, p; | ||
244 | static char *m2d = "abcdefghijklmnopqrstuvwxyz" | ||
245 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
246 | static char *a2d = ".,:;'\"`~!^-+"; | ||
247 | char *m2dp = m2d, *a2dp = a2d; | ||
248 | char nice[128]; | ||
249 | |||
250 | /* allocate map */ | ||
251 | map = kzalloc(TILER_HEIGHT * sizeof(*map), GFP_KERNEL); | ||
252 | global_map = kzalloc((TILER_WIDTH / div + 1) * TILER_HEIGHT, | ||
253 | GFP_KERNEL); | ||
254 | if (!map || !global_map) { | ||
255 | printk(KERN_ERR "could not allocate map for debug print\n"); | ||
256 | goto error; | ||
257 | } | ||
258 | memset(global_map, ' ', (TILER_WIDTH / div + 1) * TILER_HEIGHT); | ||
259 | for (i = 0; i < TILER_HEIGHT; i++) { | ||
260 | map[i] = global_map + i * (TILER_WIDTH / div + 1); | ||
261 | map[i][TILER_WIDTH / div] = 0; | ||
262 | } | ||
263 | |||
264 | /* get all allocations */ | ||
265 | mutex_lock(&mtx); | ||
266 | |||
267 | list_for_each_entry(mi, &blocks, global) { | ||
268 | if (mi->area.is2d) { | ||
269 | ai = mi->parent; | ||
270 | fill_map(map, div, &ai->area, *a2dp, false); | ||
271 | fill_map(map, div, &mi->area, *m2dp, true); | ||
272 | if (!*++a2dp) | ||
273 | a2dp = a2d; | ||
274 | if (!*++m2dp) | ||
275 | m2dp = m2d; | ||
276 | map_2d_info(map, div, nice, &mi->area); | ||
277 | } else { | ||
278 | bool start = read_map_pt(map, div, &mi->area.p0) == ' '; | ||
279 | bool end = read_map_pt(map, div, &mi->area.p1) == ' '; | ||
280 | tcm_for_each_slice(a, mi->area, p) | ||
281 | fill_map(map, div, &a, '=', true); | ||
282 | fill_map_pt(map, div, &mi->area.p0, start ? '<' : 'X'); | ||
283 | fill_map_pt(map, div, &mi->area.p1, end ? '>' : 'X'); | ||
284 | map_1d_info(map, div, nice, &mi->area); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | seq_printf(s, "BEGIN TILER MAP\n"); | ||
289 | for (i = 0; i < TILER_HEIGHT; i++) | ||
290 | seq_printf(s, "%03d:%s\n", i, map[i]); | ||
291 | seq_printf(s, "END TILER MAP\n"); | ||
292 | |||
293 | mutex_unlock(&mtx); | ||
294 | |||
295 | error: | ||
296 | kfree(map); | ||
297 | kfree(global_map); | ||
298 | } | ||
299 | |||
300 | static int tiler_debug_show(struct seq_file *s, void *unused) | ||
301 | { | ||
302 | void (*func)(struct seq_file *) = s->private; | ||
303 | func(s); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int tiler_debug_open(struct inode *inode, struct file *file) | ||
308 | { | ||
309 | return single_open(file, tiler_debug_show, inode->i_private); | ||
310 | } | ||
311 | |||
312 | static const struct file_operations tiler_debug_fops = { | ||
313 | .open = tiler_debug_open, | ||
314 | .read = seq_read, | ||
315 | .llseek = seq_lseek, | ||
316 | .release = single_release, | ||
317 | }; | ||
318 | |||
166 | /* | 319 | /* |
167 | * gid_info handling methods | 320 | * gid_info handling methods |
168 | * ========================================================================== | 321 | * ========================================================================== |
@@ -434,6 +587,16 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 offs, u16 band, | |||
434 | 587 | ||
435 | /* remove from reserved list */ | 588 | /* remove from reserved list */ |
436 | list_del(&mi->global); | 589 | list_del(&mi->global); |
590 | if (tiler_alloc_debug & 1) | ||
591 | printk(KERN_ERR "(=2d (%d-%d,%d-%d) in (%d-%d,%d-%d) prereserved)\n", | ||
592 | mi->area.p0.x, mi->area.p1.x, | ||
593 | mi->area.p0.y, mi->area.p1.y, | ||
594 | ((struct area_info *) mi->parent)->area.p0.x, | ||
595 | ((struct area_info *) mi->parent)->area.p1.x, | ||
596 | ((struct area_info *) mi->parent)->area.p0.y, | ||
597 | ((struct area_info *) mi->parent)->area.p1.y); | ||
598 | |||
599 | |||
437 | goto done; | 600 | goto done; |
438 | } | 601 | } |
439 | } | 602 | } |
@@ -454,6 +617,16 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 offs, u16 band, | |||
454 | x = _m_blk_find_fit(w, align, offs, ai, &before); | 617 | x = _m_blk_find_fit(w, align, offs, ai, &before); |
455 | if (x) { | 618 | if (x) { |
456 | _m_add2area(mi, ai, x - w, w, before); | 619 | _m_add2area(mi, ai, x - w, w, before); |
620 | |||
621 | if (tiler_alloc_debug & 1) | ||
622 | printk(KERN_ERR "(+2d (%d-%d,%d-%d) in (%d-%d,%d-%d) existing)\n", | ||
623 | mi->area.p0.x, mi->area.p1.x, | ||
624 | mi->area.p0.y, mi->area.p1.y, | ||
625 | ((struct area_info *) mi->parent)->area.p0.x, | ||
626 | ((struct area_info *) mi->parent)->area.p1.x, | ||
627 | ((struct area_info *) mi->parent)->area.p0.y, | ||
628 | ((struct area_info *) mi->parent)->area.p1.y); | ||
629 | |||
457 | goto done; | 630 | goto done; |
458 | } | 631 | } |
459 | } | 632 | } |
@@ -465,6 +638,13 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 offs, u16 band, | |||
465 | max(band, align), tcm, gi); | 638 | max(band, align), tcm, gi); |
466 | if (ai) { | 639 | if (ai) { |
467 | _m_add2area(mi, ai, ai->area.p0.x + offs, w, &ai->blocks); | 640 | _m_add2area(mi, ai, ai->area.p0.x + offs, w, &ai->blocks); |
641 | if (tiler_alloc_debug & 1) | ||
642 | printk(KERN_ERR "(+2d (%d-%d,%d-%d) in (%d-%d,%d-%d) new)\n", | ||
643 | mi->area.p0.x, mi->area.p1.x, | ||
644 | mi->area.p0.y, mi->area.p1.y, | ||
645 | ai->area.p0.x, ai->area.p1.x, | ||
646 | ai->area.p0.y, ai->area.p1.y); | ||
647 | |||
468 | } else { | 648 | } else { |
469 | /* clean up */ | 649 | /* clean up */ |
470 | kfree(mi); | 650 | kfree(mi); |
@@ -608,14 +788,31 @@ static s32 _m_free(struct mem_info *mi) | |||
608 | 788 | ||
609 | /* check to see if area needs removing also */ | 789 | /* check to see if area needs removing also */ |
610 | if (ai && !--ai->nblocks) { | 790 | if (ai && !--ai->nblocks) { |
791 | if (tiler_alloc_debug & 1) | ||
792 | printk(KERN_ERR "(-2d (%d-%d,%d-%d) in (%d-%d,%d-%d) last)\n", | ||
793 | mi->area.p0.x, mi->area.p1.x, | ||
794 | mi->area.p0.y, mi->area.p1.y, | ||
795 | ai->area.p0.x, ai->area.p1.x, | ||
796 | ai->area.p0.y, ai->area.p1.y); | ||
797 | |||
611 | res = tcm_free(&ai->area); | 798 | res = tcm_free(&ai->area); |
612 | list_del(&ai->by_gid); | 799 | list_del(&ai->by_gid); |
613 | /* try to remove parent if it became empty */ | 800 | /* try to remove parent if it became empty */ |
614 | _m_try_free_group(ai->gi); | 801 | _m_try_free_group(ai->gi); |
615 | kfree(ai); | 802 | kfree(ai); |
616 | ai = NULL; | 803 | ai = NULL; |
617 | } | 804 | } else if (tiler_alloc_debug & 1) |
805 | printk(KERN_ERR "(-2d (%d-%d,%d-%d) in (%d-%d,%d-%d) remaining)\n", | ||
806 | mi->area.p0.x, mi->area.p1.x, | ||
807 | mi->area.p0.y, mi->area.p1.y, | ||
808 | ai->area.p0.x, ai->area.p1.x, | ||
809 | ai->area.p0.y, ai->area.p1.y); | ||
618 | } else { | 810 | } else { |
811 | if (tiler_alloc_debug & 1) | ||
812 | printk(KERN_ERR "(-1d: %d,%d..%d,%d)\n", | ||
813 | mi->area.p0.x, mi->area.p0.y, | ||
814 | mi->area.p1.x, mi->area.p1.y); | ||
815 | |||
619 | /* remove 1D area */ | 816 | /* remove 1D area */ |
620 | res = tcm_free(&mi->area); | 817 | res = tcm_free(&mi->area); |
621 | /* try to remove parent if it became empty */ | 818 | /* try to remove parent if it became empty */ |
@@ -892,6 +1089,11 @@ static struct mem_info *alloc_area(enum tiler_fmt fmt, u32 width, u32 height, | |||
892 | return NULL; | 1089 | return NULL; |
893 | } | 1090 | } |
894 | 1091 | ||
1092 | if (tiler_alloc_debug & 1) | ||
1093 | printk(KERN_ERR "(+1d: %d,%d..%d,%d)\n", | ||
1094 | mi->area.p0.x, mi->area.p0.y, | ||
1095 | mi->area.p1.x, mi->area.p1.y); | ||
1096 | |||
895 | mutex_lock(&mtx); | 1097 | mutex_lock(&mtx); |
896 | mi->parent = gi; | 1098 | mi->parent = gi; |
897 | list_add(&mi->by_area, &gi->onedim); | 1099 | list_add(&mi->by_area, &gi->onedim); |
@@ -1329,6 +1531,18 @@ static s32 __init tiler_init(void) | |||
1329 | INIT_LIST_HEAD(&orphan_areas); | 1531 | INIT_LIST_HEAD(&orphan_areas); |
1330 | INIT_LIST_HEAD(&orphan_onedim); | 1532 | INIT_LIST_HEAD(&orphan_onedim); |
1331 | 1533 | ||
1534 | dbgfs = debugfs_create_dir("tiler", NULL); | ||
1535 | if (IS_ERR_OR_NULL(dbgfs)) | ||
1536 | dev_warn(device, "failed to create debug files.\n"); | ||
1537 | else | ||
1538 | dbg_map = debugfs_create_dir("map", dbgfs); | ||
1539 | if (!IS_ERR_OR_NULL(dbg_map)) | ||
1540 | debugfs_create_file("2x1", S_IRUGO, dbg_map, | ||
1541 | &debug_allocation_map, &tiler_debug_fops); | ||
1542 | if (!IS_ERR_OR_NULL(dbgfs)) | ||
1543 | debugfs_create_bool("alloc_debug", S_IRUGO | S_IWUSR, dbgfs, | ||
1544 | (u32*)&tiler_alloc_debug); | ||
1545 | |||
1332 | error: | 1546 | error: |
1333 | /* TODO: error handling for device registration */ | 1547 | /* TODO: error handling for device registration */ |
1334 | if (r) { | 1548 | if (r) { |
@@ -1348,6 +1562,8 @@ static void __exit tiler_exit(void) | |||
1348 | 1562 | ||
1349 | mutex_lock(&mtx); | 1563 | mutex_lock(&mtx); |
1350 | 1564 | ||
1565 | debugfs_remove_recursive(dbgfs); | ||
1566 | |||
1351 | /* free all process data */ | 1567 | /* free all process data */ |
1352 | tiler.cleanup(); | 1568 | tiler.cleanup(); |
1353 | 1569 | ||