aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_mm.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-12-19 11:51:06 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-01-08 05:52:02 -0500
commit901593f2bf221659a605bdc1dcb11376ea934163 (patch)
tree4cee7420d2045c53974af51288372e2fe7e35ab0 /drivers/gpu/drm/drm_mm.c
parent3490ea5de6ac4af309c3df8a26a5cca61306334c (diff)
drm: Only evict the blocks required to create the requested hole
Avoid clobbering adjacent blocks if they happen to expire earlier and amalgamate together to form the requested hole. In passing this fixes a regression from commit ea7b1dd44867e9cd6bac67e7c9fc3f128b5b255c Author: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Fri Feb 18 17:59:12 2011 +0100 drm: mm: track free areas implicitly which swaps the end address for size (with a potential overflow) and effectively causes the eviction code to clobber almost all earlier buffers above the evictee. v2: Check the original hole not the adjusted as the coloring may confuse us when later searching for the overlapping nodes. Also make sure that we do apply the range restriction and color adjustment in the same order for both scanning, searching and insertion. v3: Send the version that was actually tested. Note that this seems to be ducttape of decent quality ot paper over some of our unbind related gpu hangs reported since 3.7. It is not fully effective though, and certainly doesn't fix the underlying bug. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> [danvet: Added note plus bugzilla link and tested-by.] Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55984 Tested-by: Norbert Preining <preining@logic.at> Acked-by: Dave Airlie <airlied@gmail.com Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_mm.c')
-rw-r--r--drivers/gpu/drm/drm_mm.c45
1 files changed, 17 insertions, 28 deletions
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 2bf9670ba29b..2aa331499f81 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -221,11 +221,13 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
221 221
222 BUG_ON(!hole_node->hole_follows || node->allocated); 222 BUG_ON(!hole_node->hole_follows || node->allocated);
223 223
224 if (mm->color_adjust)
225 mm->color_adjust(hole_node, color, &adj_start, &adj_end);
226
227 if (adj_start < start) 224 if (adj_start < start)
228 adj_start = start; 225 adj_start = start;
226 if (adj_end > end)
227 adj_end = end;
228
229 if (mm->color_adjust)
230 mm->color_adjust(hole_node, color, &adj_start, &adj_end);
229 231
230 if (alignment) { 232 if (alignment) {
231 unsigned tmp = adj_start % alignment; 233 unsigned tmp = adj_start % alignment;
@@ -506,7 +508,7 @@ void drm_mm_init_scan(struct drm_mm *mm,
506 mm->scan_size = size; 508 mm->scan_size = size;
507 mm->scanned_blocks = 0; 509 mm->scanned_blocks = 0;
508 mm->scan_hit_start = 0; 510 mm->scan_hit_start = 0;
509 mm->scan_hit_size = 0; 511 mm->scan_hit_end = 0;
510 mm->scan_check_range = 0; 512 mm->scan_check_range = 0;
511 mm->prev_scanned_node = NULL; 513 mm->prev_scanned_node = NULL;
512} 514}
@@ -533,7 +535,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm,
533 mm->scan_size = size; 535 mm->scan_size = size;
534 mm->scanned_blocks = 0; 536 mm->scanned_blocks = 0;
535 mm->scan_hit_start = 0; 537 mm->scan_hit_start = 0;
536 mm->scan_hit_size = 0; 538 mm->scan_hit_end = 0;
537 mm->scan_start = start; 539 mm->scan_start = start;
538 mm->scan_end = end; 540 mm->scan_end = end;
539 mm->scan_check_range = 1; 541 mm->scan_check_range = 1;
@@ -552,8 +554,7 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
552 struct drm_mm *mm = node->mm; 554 struct drm_mm *mm = node->mm;
553 struct drm_mm_node *prev_node; 555 struct drm_mm_node *prev_node;
554 unsigned long hole_start, hole_end; 556 unsigned long hole_start, hole_end;
555 unsigned long adj_start; 557 unsigned long adj_start, adj_end;
556 unsigned long adj_end;
557 558
558 mm->scanned_blocks++; 559 mm->scanned_blocks++;
559 560
@@ -570,14 +571,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
570 node->node_list.next = &mm->prev_scanned_node->node_list; 571 node->node_list.next = &mm->prev_scanned_node->node_list;
571 mm->prev_scanned_node = node; 572 mm->prev_scanned_node = node;
572 573
573 hole_start = drm_mm_hole_node_start(prev_node); 574 adj_start = hole_start = drm_mm_hole_node_start(prev_node);
574 hole_end = drm_mm_hole_node_end(prev_node); 575 adj_end = hole_end = drm_mm_hole_node_end(prev_node);
575
576 adj_start = hole_start;
577 adj_end = hole_end;
578
579 if (mm->color_adjust)
580 mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end);
581 576
582 if (mm->scan_check_range) { 577 if (mm->scan_check_range) {
583 if (adj_start < mm->scan_start) 578 if (adj_start < mm->scan_start)
@@ -586,11 +581,14 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
586 adj_end = mm->scan_end; 581 adj_end = mm->scan_end;
587 } 582 }
588 583
584 if (mm->color_adjust)
585 mm->color_adjust(prev_node, mm->scan_color,
586 &adj_start, &adj_end);
587
589 if (check_free_hole(adj_start, adj_end, 588 if (check_free_hole(adj_start, adj_end,
590 mm->scan_size, mm->scan_alignment)) { 589 mm->scan_size, mm->scan_alignment)) {
591 mm->scan_hit_start = hole_start; 590 mm->scan_hit_start = hole_start;
592 mm->scan_hit_size = hole_end; 591 mm->scan_hit_end = hole_end;
593
594 return 1; 592 return 1;
595 } 593 }
596 594
@@ -626,19 +624,10 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node)
626 node_list); 624 node_list);
627 625
628 prev_node->hole_follows = node->scanned_preceeds_hole; 626 prev_node->hole_follows = node->scanned_preceeds_hole;
629 INIT_LIST_HEAD(&node->node_list);
630 list_add(&node->node_list, &prev_node->node_list); 627 list_add(&node->node_list, &prev_node->node_list);
631 628
632 /* Only need to check for containement because start&size for the 629 return (drm_mm_hole_node_end(node) > mm->scan_hit_start &&
633 * complete resulting free block (not just the desired part) is 630 node->start < mm->scan_hit_end);
634 * stored. */
635 if (node->start >= mm->scan_hit_start &&
636 node->start + node->size
637 <= mm->scan_hit_start + mm->scan_hit_size) {
638 return 1;
639 }
640
641 return 0;
642} 631}
643EXPORT_SYMBOL(drm_mm_scan_remove_block); 632EXPORT_SYMBOL(drm_mm_scan_remove_block);
644 633