diff options
Diffstat (limited to 'drivers/gpu/drm/drm_mm.c')
-rw-r--r-- | drivers/gpu/drm/drm_mm.c | 76 |
1 files changed, 73 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 11d44a1e0ab3..632473beb40c 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -104,6 +104,68 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ | |||
104 | u64 end, | 104 | u64 end, |
105 | enum drm_mm_search_flags flags); | 105 | enum drm_mm_search_flags flags); |
106 | 106 | ||
107 | #ifdef CONFIG_DRM_DEBUG_MM | ||
108 | #include <linux/stackdepot.h> | ||
109 | |||
110 | #define STACKDEPTH 32 | ||
111 | #define BUFSZ 4096 | ||
112 | |||
113 | static noinline void save_stack(struct drm_mm_node *node) | ||
114 | { | ||
115 | unsigned long entries[STACKDEPTH]; | ||
116 | struct stack_trace trace = { | ||
117 | .entries = entries, | ||
118 | .max_entries = STACKDEPTH, | ||
119 | .skip = 1 | ||
120 | }; | ||
121 | |||
122 | save_stack_trace(&trace); | ||
123 | if (trace.nr_entries != 0 && | ||
124 | trace.entries[trace.nr_entries-1] == ULONG_MAX) | ||
125 | trace.nr_entries--; | ||
126 | |||
127 | /* May be called under spinlock, so avoid sleeping */ | ||
128 | node->stack = depot_save_stack(&trace, GFP_NOWAIT); | ||
129 | } | ||
130 | |||
131 | static void show_leaks(struct drm_mm *mm) | ||
132 | { | ||
133 | struct drm_mm_node *node; | ||
134 | unsigned long entries[STACKDEPTH]; | ||
135 | char *buf; | ||
136 | |||
137 | buf = kmalloc(BUFSZ, GFP_KERNEL); | ||
138 | if (!buf) | ||
139 | return; | ||
140 | |||
141 | list_for_each_entry(node, &mm->head_node.node_list, node_list) { | ||
142 | struct stack_trace trace = { | ||
143 | .entries = entries, | ||
144 | .max_entries = STACKDEPTH | ||
145 | }; | ||
146 | |||
147 | if (!node->stack) { | ||
148 | DRM_ERROR("node [%08llx + %08llx]: unknown owner\n", | ||
149 | node->start, node->size); | ||
150 | continue; | ||
151 | } | ||
152 | |||
153 | depot_fetch_stack(node->stack, &trace); | ||
154 | snprint_stack_trace(buf, BUFSZ, &trace, 0); | ||
155 | DRM_ERROR("node [%08llx + %08llx]: inserted at\n%s", | ||
156 | node->start, node->size, buf); | ||
157 | } | ||
158 | |||
159 | kfree(buf); | ||
160 | } | ||
161 | |||
162 | #undef STACKDEPTH | ||
163 | #undef BUFSZ | ||
164 | #else | ||
165 | static void save_stack(struct drm_mm_node *node) { } | ||
166 | static void show_leaks(struct drm_mm *mm) { } | ||
167 | #endif | ||
168 | |||
107 | #define START(node) ((node)->start) | 169 | #define START(node) ((node)->start) |
108 | #define LAST(node) ((node)->start + (node)->size - 1) | 170 | #define LAST(node) ((node)->start + (node)->size - 1) |
109 | 171 | ||
@@ -228,6 +290,8 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, | |||
228 | list_add(&node->hole_stack, &mm->hole_stack); | 290 | list_add(&node->hole_stack, &mm->hole_stack); |
229 | node->hole_follows = 1; | 291 | node->hole_follows = 1; |
230 | } | 292 | } |
293 | |||
294 | save_stack(node); | ||
231 | } | 295 | } |
232 | 296 | ||
233 | /** | 297 | /** |
@@ -293,6 +357,8 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) | |||
293 | node->hole_follows = 1; | 357 | node->hole_follows = 1; |
294 | } | 358 | } |
295 | 359 | ||
360 | save_stack(node); | ||
361 | |||
296 | return 0; | 362 | return 0; |
297 | } | 363 | } |
298 | EXPORT_SYMBOL(drm_mm_reserve_node); | 364 | EXPORT_SYMBOL(drm_mm_reserve_node); |
@@ -397,6 +463,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, | |||
397 | list_add(&node->hole_stack, &mm->hole_stack); | 463 | list_add(&node->hole_stack, &mm->hole_stack); |
398 | node->hole_follows = 1; | 464 | node->hole_follows = 1; |
399 | } | 465 | } |
466 | |||
467 | save_stack(node); | ||
400 | } | 468 | } |
401 | 469 | ||
402 | /** | 470 | /** |
@@ -861,10 +929,12 @@ EXPORT_SYMBOL(drm_mm_init); | |||
861 | * Note that it is a bug to call this function on an allocator which is not | 929 | * Note that it is a bug to call this function on an allocator which is not |
862 | * clean. | 930 | * clean. |
863 | */ | 931 | */ |
864 | void drm_mm_takedown(struct drm_mm * mm) | 932 | void drm_mm_takedown(struct drm_mm *mm) |
865 | { | 933 | { |
866 | WARN(!list_empty(&mm->head_node.node_list), | 934 | if (WARN(!list_empty(&mm->head_node.node_list), |
867 | "Memory manager not clean during takedown.\n"); | 935 | "Memory manager not clean during takedown.\n")) |
936 | show_leaks(mm); | ||
937 | |||
868 | } | 938 | } |
869 | EXPORT_SYMBOL(drm_mm_takedown); | 939 | EXPORT_SYMBOL(drm_mm_takedown); |
870 | 940 | ||