aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_mm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_mm.c')
-rw-r--r--drivers/gpu/drm/drm_mm.c76
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
113static 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
131static 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
165static void save_stack(struct drm_mm_node *node) { }
166static 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}
298EXPORT_SYMBOL(drm_mm_reserve_node); 364EXPORT_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 */
864void drm_mm_takedown(struct drm_mm * mm) 932void 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}
869EXPORT_SYMBOL(drm_mm_takedown); 939EXPORT_SYMBOL(drm_mm_takedown);
870 940