BUG: drm_mm head_node gets broken?
Russell King - ARM Linux
linux at arm.linux.org.uk
Sun May 19 10:22:01 PDT 2013
So, while tinkering with my Dove DRM driver, I tripped over a BUG_ON()
in drm_mm_hole_node_start(), which was called from drm_mm_dump_table():
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
{
struct drm_mm_node *entry;
unsigned long total_used = 0, total_free = 0, total = 0;
unsigned long hole_start, hole_end, hole_size;
hole_start = drm_mm_hole_node_start(&mm->head_node);
hole_end = drm_mm_hole_node_end(&mm->head_node);
drm_mm_hole_node_start() does this:
static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
{
BUG_ON(!hole_node->hole_follows);
return __drm_mm_hole_node_start(hole_node);
}
This appears to indicate that it is required that the head node should
always have a "hole" following it.
As this used to work, I dug in the git history, and found commit 6b9d89b4
(drm: Add colouring to the range allocator), in particular this change:
static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
struct drm_mm_node *node,
- unsigned long size, unsigned alignment)
+ unsigned long size, unsigned alignment,
+ unsigned long color)
{
...
- if (!tmp) {
+ if (alignment) {
+ unsigned tmp = adj_start % alignment;
+ if (tmp)
+ adj_start += alignment - tmp;
+ }
+
+ if (adj_start == hole_start) {
hole_node->hole_follows = 0;
- list_del_init(&hole_node->hole_stack);
- } else
- wasted = alignment - tmp;
+ list_del(&hole_node->hole_stack);
+ }
Now, when we do an allocation, it is typically done as follows:
free = drm_mm_search_free(mm, size, align, 0);
if (free)
linear = drm_mm_get_block(free, size, align);
If nothing has been allocated in the mm, 'free' will be &mm->head_node.
The result is that drm_mm_get_block calls down into drm_mm_insert_helper
with hole_node == &mm->head_node. This I confirmed via:
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index db1e2d6..7241be8 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -125,6 +125,7 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
}
if (adj_start == hole_start) {
+ BUG_ON(hole_node == &mm->head_node);
hole_node->hole_follows = 0;
list_del(&hole_node->hole_stack);
}
which triggers during booting. Hence, we end up setting the head_node
to indicate no hole following - which violates the conditions of other
parts of the code in drm_mm.c.
It looks like this change was made quite a while ago - back in July
2012, so I assume that while the rest of the allocator is fine with this,
it's just the debugging code which is now broken. However, I suspect
that DRM people may wish to either back out the coloring change or
carefully review the change for correctness throughout the drm_mm
code.
More information about the dri-devel
mailing list