Commit 901593f2bf221659a605bdc1dcb11376ea934163

Authored by Chris Wilson
Committed by Daniel Vetter
1 parent 3490ea5de6

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>

Showing 2 changed files with 18 additions and 29 deletions Side-by-side Diff

drivers/gpu/drm/drm_mm.c
... ... @@ -221,12 +221,14 @@
221 221  
222 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 224 if (adj_start < start)
228 225 adj_start = start;
  226 + if (adj_end > end)
  227 + adj_end = end;
229 228  
  229 + if (mm->color_adjust)
  230 + mm->color_adjust(hole_node, color, &adj_start, &adj_end);
  231 +
230 232 if (alignment) {
231 233 unsigned tmp = adj_start % alignment;
232 234 if (tmp)
... ... @@ -506,7 +508,7 @@
506 508 mm->scan_size = size;
507 509 mm->scanned_blocks = 0;
508 510 mm->scan_hit_start = 0;
509   - mm->scan_hit_size = 0;
  511 + mm->scan_hit_end = 0;
510 512 mm->scan_check_range = 0;
511 513 mm->prev_scanned_node = NULL;
512 514 }
... ... @@ -533,7 +535,7 @@
533 535 mm->scan_size = size;
534 536 mm->scanned_blocks = 0;
535 537 mm->scan_hit_start = 0;
536   - mm->scan_hit_size = 0;
  538 + mm->scan_hit_end = 0;
537 539 mm->scan_start = start;
538 540 mm->scan_end = end;
539 541 mm->scan_check_range = 1;
... ... @@ -552,8 +554,7 @@
552 554 struct drm_mm *mm = node->mm;
553 555 struct drm_mm_node *prev_node;
554 556 unsigned long hole_start, hole_end;
555   - unsigned long adj_start;
556   - unsigned long adj_end;
  557 + unsigned long adj_start, adj_end;
557 558  
558 559 mm->scanned_blocks++;
559 560  
560 561  
... ... @@ -570,15 +571,9 @@
570 571 node->node_list.next = &mm->prev_scanned_node->node_list;
571 572 mm->prev_scanned_node = node;
572 573  
573   - hole_start = drm_mm_hole_node_start(prev_node);
574   - hole_end = drm_mm_hole_node_end(prev_node);
  574 + adj_start = hole_start = drm_mm_hole_node_start(prev_node);
  575 + adj_end = hole_end = drm_mm_hole_node_end(prev_node);
575 576  
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   -
582 577 if (mm->scan_check_range) {
583 578 if (adj_start < mm->scan_start)
584 579 adj_start = mm->scan_start;
585 580  
... ... @@ -586,11 +581,14 @@
586 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 588 if (check_free_hole(adj_start, adj_end,
590 589 mm->scan_size, mm->scan_alignment)) {
591 590 mm->scan_hit_start = hole_start;
592   - mm->scan_hit_size = hole_end;
593   -
  591 + mm->scan_hit_end = hole_end;
594 592 return 1;
595 593 }
596 594  
597 595  
... ... @@ -626,19 +624,10 @@
626 624 node_list);
627 625  
628 626 prev_node->hole_follows = node->scanned_preceeds_hole;
629   - INIT_LIST_HEAD(&node->node_list);
630 627 list_add(&node->node_list, &prev_node->node_list);
631 628  
632   - /* Only need to check for containement because start&size for the
633   - * complete resulting free block (not just the desired part) is
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;
  629 + return (drm_mm_hole_node_end(node) > mm->scan_hit_start &&
  630 + node->start < mm->scan_hit_end);
642 631 }
643 632 EXPORT_SYMBOL(drm_mm_scan_remove_block);
644 633  
include/drm/drm_mm.h
... ... @@ -70,7 +70,7 @@
70 70 unsigned long scan_color;
71 71 unsigned long scan_size;
72 72 unsigned long scan_hit_start;
73   - unsigned scan_hit_size;
  73 + unsigned long scan_hit_end;
74 74 unsigned scanned_blocks;
75 75 unsigned long scan_start;
76 76 unsigned long scan_end;