Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: Improve drm_mm search (and fix topdown allocation) with rbtrees

The drm_mm range manager claimed to support top-down insertion, but it
was neither searching for the top-most hole that could fit the
allocation request nor fitting the request to the hole correctly.

In order to search the range efficiently, we create a secondary index
for the holes using either their size or their address. This index
allows us to find the smallest hole or the hole at the bottom or top of
the range efficiently, whilst keeping the hole stack to rapidly service
evictions.

v2: Search for holes both high and low. Rename flags to mode.
v3: Discover rb_entry_safe() and use it!
v4: Kerneldoc for enum drm_mm_insert_mode.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: "Christian König" <christian.koenig@amd.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Russell King <rmk+kernel@armlinux.org.uk>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Sean Paul <seanpaul@chromium.org>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Christian Gmeiner <christian.gmeiner@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: Eric Anholt <eric@anholt.net>
Cc: Sinclair Yeh <syeh@vmware.com>
Cc: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com> # vmwgfx
Reviewed-by: Lucas Stach <l.stach@pengutronix.de> #etnaviv
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202210438.28702-1-chris@chris-wilson.co.uk

authored by

Chris Wilson and committed by
Daniel Vetter
4e64e553 17aad8a3

+470 -442
+7 -9
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
··· 97 97 { 98 98 struct amdgpu_gtt_mgr *mgr = man->priv; 99 99 struct drm_mm_node *node = mem->mm_node; 100 - enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST; 101 - enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; 100 + enum drm_mm_insert_mode mode; 102 101 unsigned long fpfn, lpfn; 103 102 int r; 104 103 ··· 114 115 else 115 116 lpfn = man->size; 116 117 117 - if (place && place->flags & TTM_PL_FLAG_TOPDOWN) { 118 - sflags = DRM_MM_SEARCH_BELOW; 119 - aflags = DRM_MM_CREATE_TOP; 120 - } 118 + mode = DRM_MM_INSERT_BEST; 119 + if (place && place->flags & TTM_PL_FLAG_TOPDOWN) 120 + mode = DRM_MM_INSERT_HIGH; 121 121 122 122 spin_lock(&mgr->lock); 123 - r = drm_mm_insert_node_in_range_generic(&mgr->mm, node, mem->num_pages, 124 - mem->page_alignment, 0, 125 - fpfn, lpfn, sflags, aflags); 123 + r = drm_mm_insert_node_in_range(&mgr->mm, node, 124 + mem->num_pages, mem->page_alignment, 0, 125 + fpfn, lpfn, mode); 126 126 spin_unlock(&mgr->lock); 127 127 128 128 if (!r) {
+8 -12
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
··· 97 97 struct amdgpu_vram_mgr *mgr = man->priv; 98 98 struct drm_mm *mm = &mgr->mm; 99 99 struct drm_mm_node *nodes; 100 - enum drm_mm_search_flags sflags = DRM_MM_SEARCH_DEFAULT; 101 - enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; 100 + enum drm_mm_insert_mode mode; 102 101 unsigned long lpfn, num_nodes, pages_per_node, pages_left; 103 102 unsigned i; 104 103 int r; ··· 120 121 if (!nodes) 121 122 return -ENOMEM; 122 123 123 - if (place->flags & TTM_PL_FLAG_TOPDOWN) { 124 - sflags = DRM_MM_SEARCH_BELOW; 125 - aflags = DRM_MM_CREATE_TOP; 126 - } 124 + mode = DRM_MM_INSERT_BEST; 125 + if (place->flags & TTM_PL_FLAG_TOPDOWN) 126 + mode = DRM_MM_INSERT_HIGH; 127 127 128 128 pages_left = mem->num_pages; 129 129 ··· 133 135 134 136 if (pages == pages_per_node) 135 137 alignment = pages_per_node; 136 - else 137 - sflags |= DRM_MM_SEARCH_BEST; 138 138 139 - r = drm_mm_insert_node_in_range_generic(mm, &nodes[i], pages, 140 - alignment, 0, 141 - place->fpfn, lpfn, 142 - sflags, aflags); 139 + r = drm_mm_insert_node_in_range(mm, &nodes[i], 140 + pages, alignment, 0, 141 + place->fpfn, lpfn, 142 + mode); 143 143 if (unlikely(r)) 144 144 goto error; 145 145
+2 -2
drivers/gpu/drm/armada/armada_gem.c
··· 148 148 return -ENOSPC; 149 149 150 150 mutex_lock(&priv->linear_lock); 151 - ret = drm_mm_insert_node(&priv->linear, node, size, align, 152 - DRM_MM_SEARCH_DEFAULT); 151 + ret = drm_mm_insert_node_generic(&priv->linear, node, 152 + size, align, 0, 0); 153 153 mutex_unlock(&priv->linear_lock); 154 154 if (ret) { 155 155 kfree(node);
+272 -216
drivers/gpu/drm/drm_mm.c
··· 97 97 * locking would be fully redundant. 98 98 */ 99 99 100 - static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, 101 - u64 size, 102 - u64 alignment, 103 - unsigned long color, 104 - u64 start, 105 - u64 end, 106 - enum drm_mm_search_flags flags); 107 - 108 100 #ifdef CONFIG_DRM_DEBUG_MM 109 101 #include <linux/stackdepot.h> 110 102 ··· 218 226 &drm_mm_interval_tree_augment); 219 227 } 220 228 221 - static void drm_mm_insert_helper(struct drm_mm_node *hole_node, 222 - struct drm_mm_node *node, 223 - u64 size, u64 alignment, 224 - unsigned long color, 225 - u64 range_start, u64 range_end, 226 - enum drm_mm_allocator_flags flags) 229 + #define RB_INSERT(root, member, expr) do { \ 230 + struct rb_node **link = &root.rb_node, *rb = NULL; \ 231 + u64 x = expr(node); \ 232 + while (*link) { \ 233 + rb = *link; \ 234 + if (x < expr(rb_entry(rb, struct drm_mm_node, member))) \ 235 + link = &rb->rb_left; \ 236 + else \ 237 + link = &rb->rb_right; \ 238 + } \ 239 + rb_link_node(&node->member, rb, link); \ 240 + rb_insert_color(&node->member, &root); \ 241 + } while (0) 242 + 243 + #define HOLE_SIZE(NODE) ((NODE)->hole_size) 244 + #define HOLE_ADDR(NODE) (__drm_mm_hole_node_start(NODE)) 245 + 246 + static void add_hole(struct drm_mm_node *node) 227 247 { 228 - struct drm_mm *mm = hole_node->mm; 229 - u64 hole_start = drm_mm_hole_node_start(hole_node); 230 - u64 hole_end = drm_mm_hole_node_end(hole_node); 231 - u64 adj_start = hole_start; 232 - u64 adj_end = hole_end; 248 + struct drm_mm *mm = node->mm; 233 249 234 - DRM_MM_BUG_ON(!drm_mm_hole_follows(hole_node) || node->allocated); 250 + node->hole_size = 251 + __drm_mm_hole_node_end(node) - __drm_mm_hole_node_start(node); 252 + DRM_MM_BUG_ON(!drm_mm_hole_follows(node)); 235 253 236 - if (mm->color_adjust) 237 - mm->color_adjust(hole_node, color, &adj_start, &adj_end); 254 + RB_INSERT(mm->holes_size, rb_hole_size, HOLE_SIZE); 255 + RB_INSERT(mm->holes_addr, rb_hole_addr, HOLE_ADDR); 238 256 239 - adj_start = max(adj_start, range_start); 240 - adj_end = min(adj_end, range_end); 257 + list_add(&node->hole_stack, &mm->hole_stack); 258 + } 241 259 242 - if (flags & DRM_MM_CREATE_TOP) 243 - adj_start = adj_end - size; 260 + static void rm_hole(struct drm_mm_node *node) 261 + { 262 + DRM_MM_BUG_ON(!drm_mm_hole_follows(node)); 244 263 245 - if (alignment) { 246 - u64 rem; 264 + list_del(&node->hole_stack); 265 + rb_erase(&node->rb_hole_size, &node->mm->holes_size); 266 + rb_erase(&node->rb_hole_addr, &node->mm->holes_addr); 267 + node->hole_size = 0; 247 268 248 - div64_u64_rem(adj_start, alignment, &rem); 249 - if (rem) { 250 - if (flags & DRM_MM_CREATE_TOP) 251 - adj_start -= rem; 252 - else 253 - adj_start += alignment - rem; 269 + DRM_MM_BUG_ON(drm_mm_hole_follows(node)); 270 + } 271 + 272 + static inline struct drm_mm_node *rb_hole_size_to_node(struct rb_node *rb) 273 + { 274 + return rb_entry_safe(rb, struct drm_mm_node, rb_hole_size); 275 + } 276 + 277 + static inline struct drm_mm_node *rb_hole_addr_to_node(struct rb_node *rb) 278 + { 279 + return rb_entry_safe(rb, struct drm_mm_node, rb_hole_addr); 280 + } 281 + 282 + static inline u64 rb_hole_size(struct rb_node *rb) 283 + { 284 + return rb_entry(rb, struct drm_mm_node, rb_hole_size)->hole_size; 285 + } 286 + 287 + static struct drm_mm_node *best_hole(struct drm_mm *mm, u64 size) 288 + { 289 + struct rb_node *best = NULL; 290 + struct rb_node **link = &mm->holes_size.rb_node; 291 + 292 + while (*link) { 293 + struct rb_node *rb = *link; 294 + 295 + if (size <= rb_hole_size(rb)) { 296 + link = &rb->rb_left; 297 + best = rb; 298 + } else { 299 + link = &rb->rb_right; 254 300 } 255 301 } 256 302 257 - if (adj_start == hole_start) { 258 - hole_node->hole_follows = 0; 259 - list_del(&hole_node->hole_stack); 303 + return rb_hole_size_to_node(best); 304 + } 305 + 306 + static struct drm_mm_node *find_hole(struct drm_mm *mm, u64 addr) 307 + { 308 + struct drm_mm_node *node = NULL; 309 + struct rb_node **link = &mm->holes_addr.rb_node; 310 + 311 + while (*link) { 312 + u64 hole_start; 313 + 314 + node = rb_hole_addr_to_node(*link); 315 + hole_start = __drm_mm_hole_node_start(node); 316 + 317 + if (addr < hole_start) 318 + link = &node->rb_hole_addr.rb_left; 319 + else if (addr > hole_start + node->hole_size) 320 + link = &node->rb_hole_addr.rb_right; 321 + else 322 + break; 260 323 } 261 324 262 - node->start = adj_start; 263 - node->size = size; 264 - node->mm = mm; 265 - node->color = color; 266 - node->allocated = 1; 325 + return node; 326 + } 267 327 268 - list_add(&node->node_list, &hole_node->node_list); 328 + static struct drm_mm_node * 329 + first_hole(struct drm_mm *mm, 330 + u64 start, u64 end, u64 size, 331 + enum drm_mm_insert_mode mode) 332 + { 333 + if (RB_EMPTY_ROOT(&mm->holes_size)) 334 + return NULL; 269 335 270 - drm_mm_interval_tree_add_node(hole_node, node); 336 + switch (mode) { 337 + default: 338 + case DRM_MM_INSERT_BEST: 339 + return best_hole(mm, size); 271 340 272 - DRM_MM_BUG_ON(node->start < range_start); 273 - DRM_MM_BUG_ON(node->start < adj_start); 274 - DRM_MM_BUG_ON(node->start + node->size > adj_end); 275 - DRM_MM_BUG_ON(node->start + node->size > range_end); 341 + case DRM_MM_INSERT_LOW: 342 + return find_hole(mm, start); 276 343 277 - node->hole_follows = 0; 278 - if (__drm_mm_hole_node_start(node) < hole_end) { 279 - list_add(&node->hole_stack, &mm->hole_stack); 280 - node->hole_follows = 1; 344 + case DRM_MM_INSERT_HIGH: 345 + return find_hole(mm, end); 346 + 347 + case DRM_MM_INSERT_EVICT: 348 + return list_first_entry_or_null(&mm->hole_stack, 349 + struct drm_mm_node, 350 + hole_stack); 281 351 } 352 + } 282 353 283 - save_stack(node); 354 + static struct drm_mm_node * 355 + next_hole(struct drm_mm *mm, 356 + struct drm_mm_node *node, 357 + enum drm_mm_insert_mode mode) 358 + { 359 + switch (mode) { 360 + default: 361 + case DRM_MM_INSERT_BEST: 362 + return rb_hole_size_to_node(rb_next(&node->rb_hole_size)); 363 + 364 + case DRM_MM_INSERT_LOW: 365 + return rb_hole_addr_to_node(rb_next(&node->rb_hole_addr)); 366 + 367 + case DRM_MM_INSERT_HIGH: 368 + return rb_hole_addr_to_node(rb_prev(&node->rb_hole_addr)); 369 + 370 + case DRM_MM_INSERT_EVICT: 371 + node = list_next_entry(node, hole_stack); 372 + return &node->hole_stack == &mm->hole_stack ? NULL : node; 373 + } 284 374 } 285 375 286 376 /** ··· 391 317 return -ENOSPC; 392 318 393 319 /* Find the relevant hole to add our node to */ 394 - hole = drm_mm_interval_tree_iter_first(&mm->interval_tree, 395 - node->start, ~(u64)0); 396 - if (hole) { 397 - if (hole->start < end) 398 - return -ENOSPC; 399 - } else { 400 - hole = list_entry(drm_mm_nodes(mm), typeof(*hole), node_list); 401 - } 402 - 403 - hole = list_last_entry(&hole->node_list, typeof(*hole), node_list); 404 - if (!drm_mm_hole_follows(hole)) 320 + hole = find_hole(mm, node->start); 321 + if (!hole) 405 322 return -ENOSPC; 406 323 407 324 adj_start = hole_start = __drm_mm_hole_node_start(hole); 408 - adj_end = hole_end = __drm_mm_hole_node_end(hole); 325 + adj_end = hole_end = hole_start + hole->hole_size; 409 326 410 327 if (mm->color_adjust) 411 328 mm->color_adjust(hole, node->color, &adj_start, &adj_end); ··· 405 340 return -ENOSPC; 406 341 407 342 node->mm = mm; 408 - node->allocated = 1; 409 343 410 344 list_add(&node->node_list, &hole->node_list); 411 - 412 345 drm_mm_interval_tree_add_node(hole, node); 346 + node->allocated = true; 347 + node->hole_size = 0; 413 348 414 - if (node->start == hole_start) { 415 - hole->hole_follows = 0; 416 - list_del(&hole->hole_stack); 417 - } 418 - 419 - node->hole_follows = 0; 420 - if (end != hole_end) { 421 - list_add(&node->hole_stack, &mm->hole_stack); 422 - node->hole_follows = 1; 423 - } 349 + rm_hole(hole); 350 + if (node->start > hole_start) 351 + add_hole(hole); 352 + if (end < hole_end) 353 + add_hole(node); 424 354 425 355 save_stack(node); 426 - 427 356 return 0; 428 357 } 429 358 EXPORT_SYMBOL(drm_mm_reserve_node); 430 359 431 360 /** 432 - * drm_mm_insert_node_in_range_generic - ranged search for space and insert @node 361 + * drm_mm_insert_node_in_range - ranged search for space and insert @node 433 362 * @mm: drm_mm to allocate from 434 363 * @node: preallocate node to insert 435 364 * @size: size of the allocation 436 365 * @alignment: alignment of the allocation 437 366 * @color: opaque tag value to use for this node 438 - * @start: start of the allowed range for this node 439 - * @end: end of the allowed range for this node 440 - * @sflags: flags to fine-tune the allocation search 441 - * @aflags: flags to fine-tune the allocation behavior 367 + * @range_start: start of the allowed range for this node 368 + * @range_end: end of the allowed range for this node 369 + * @mode: fine-tune the allocation search and placement 442 370 * 443 371 * The preallocated @node must be cleared to 0. 444 372 * 445 373 * Returns: 446 374 * 0 on success, -ENOSPC if there's no suitable hole. 447 375 */ 448 - int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, 449 - u64 size, u64 alignment, 450 - unsigned long color, 451 - u64 start, u64 end, 452 - enum drm_mm_search_flags sflags, 453 - enum drm_mm_allocator_flags aflags) 376 + int drm_mm_insert_node_in_range(struct drm_mm * const mm, 377 + struct drm_mm_node * const node, 378 + u64 size, u64 alignment, 379 + unsigned long color, 380 + u64 range_start, u64 range_end, 381 + enum drm_mm_insert_mode mode) 454 382 { 455 - struct drm_mm_node *hole_node; 383 + struct drm_mm_node *hole; 384 + u64 remainder_mask; 456 385 457 - if (WARN_ON(size == 0)) 458 - return -EINVAL; 386 + DRM_MM_BUG_ON(range_start >= range_end); 459 387 460 - hole_node = drm_mm_search_free_in_range_generic(mm, 461 - size, alignment, color, 462 - start, end, sflags); 463 - if (!hole_node) 388 + if (unlikely(size == 0 || range_end - range_start < size)) 464 389 return -ENOSPC; 465 390 466 - drm_mm_insert_helper(hole_node, node, 467 - size, alignment, color, 468 - start, end, aflags); 469 - return 0; 391 + if (alignment <= 1) 392 + alignment = 0; 393 + 394 + remainder_mask = is_power_of_2(alignment) ? alignment - 1 : 0; 395 + for (hole = first_hole(mm, range_start, range_end, size, mode); hole; 396 + hole = next_hole(mm, hole, mode)) { 397 + u64 hole_start = __drm_mm_hole_node_start(hole); 398 + u64 hole_end = hole_start + hole->hole_size; 399 + u64 adj_start, adj_end; 400 + u64 col_start, col_end; 401 + 402 + if (mode == DRM_MM_INSERT_LOW && hole_start >= range_end) 403 + break; 404 + 405 + if (mode == DRM_MM_INSERT_HIGH && hole_end <= range_start) 406 + break; 407 + 408 + col_start = hole_start; 409 + col_end = hole_end; 410 + if (mm->color_adjust) 411 + mm->color_adjust(hole, color, &col_start, &col_end); 412 + 413 + adj_start = max(col_start, range_start); 414 + adj_end = min(col_end, range_end); 415 + 416 + if (adj_end <= adj_start || adj_end - adj_start < size) 417 + continue; 418 + 419 + if (mode == DRM_MM_INSERT_HIGH) 420 + adj_start = adj_end - size; 421 + 422 + if (alignment) { 423 + u64 rem; 424 + 425 + if (likely(remainder_mask)) 426 + rem = adj_start & remainder_mask; 427 + else 428 + div64_u64_rem(adj_start, alignment, &rem); 429 + if (rem) { 430 + adj_start -= rem; 431 + if (mode != DRM_MM_INSERT_HIGH) 432 + adj_start += alignment; 433 + 434 + if (adj_start < max(col_start, range_start) || 435 + min(col_end, range_end) - adj_start < size) 436 + continue; 437 + 438 + if (adj_end <= adj_start || 439 + adj_end - adj_start < size) 440 + continue; 441 + } 442 + } 443 + 444 + node->mm = mm; 445 + node->size = size; 446 + node->start = adj_start; 447 + node->color = color; 448 + node->hole_size = 0; 449 + 450 + list_add(&node->node_list, &hole->node_list); 451 + drm_mm_interval_tree_add_node(hole, node); 452 + node->allocated = true; 453 + 454 + rm_hole(hole); 455 + if (adj_start > hole_start) 456 + add_hole(hole); 457 + if (adj_start + size < hole_end) 458 + add_hole(node); 459 + 460 + save_stack(node); 461 + return 0; 462 + } 463 + 464 + return -ENOSPC; 470 465 } 471 - EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); 466 + EXPORT_SYMBOL(drm_mm_insert_node_in_range); 472 467 473 468 /** 474 469 * drm_mm_remove_node - Remove a memory node from the allocator. ··· 546 421 DRM_MM_BUG_ON(!node->allocated); 547 422 DRM_MM_BUG_ON(node->scanned_block); 548 423 549 - prev_node = 550 - list_entry(node->node_list.prev, struct drm_mm_node, node_list); 424 + prev_node = list_prev_entry(node, node_list); 551 425 552 - if (drm_mm_hole_follows(node)) { 553 - DRM_MM_BUG_ON(__drm_mm_hole_node_start(node) == 554 - __drm_mm_hole_node_end(node)); 555 - list_del(&node->hole_stack); 556 - } else { 557 - DRM_MM_BUG_ON(__drm_mm_hole_node_start(node) != 558 - __drm_mm_hole_node_end(node)); 559 - } 560 - 561 - if (!drm_mm_hole_follows(prev_node)) { 562 - prev_node->hole_follows = 1; 563 - list_add(&prev_node->hole_stack, &mm->hole_stack); 564 - } else 565 - list_move(&prev_node->hole_stack, &mm->hole_stack); 426 + if (drm_mm_hole_follows(node)) 427 + rm_hole(node); 566 428 567 429 drm_mm_interval_tree_remove(node, &mm->interval_tree); 568 430 list_del(&node->node_list); 569 - node->allocated = 0; 431 + node->allocated = false; 432 + 433 + if (drm_mm_hole_follows(prev_node)) 434 + rm_hole(prev_node); 435 + add_hole(prev_node); 570 436 } 571 437 EXPORT_SYMBOL(drm_mm_remove_node); 572 - 573 - static int check_free_hole(u64 start, u64 end, u64 size, u64 alignment) 574 - { 575 - if (end - start < size) 576 - return 0; 577 - 578 - if (alignment) { 579 - u64 rem; 580 - 581 - div64_u64_rem(start, alignment, &rem); 582 - if (rem) 583 - start += alignment - rem; 584 - } 585 - 586 - return end >= start + size; 587 - } 588 - 589 - static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, 590 - u64 size, 591 - u64 alignment, 592 - unsigned long color, 593 - u64 start, 594 - u64 end, 595 - enum drm_mm_search_flags flags) 596 - { 597 - struct drm_mm_node *entry; 598 - struct drm_mm_node *best; 599 - u64 adj_start; 600 - u64 adj_end; 601 - u64 best_size; 602 - 603 - DRM_MM_BUG_ON(mm->scan_active); 604 - 605 - best = NULL; 606 - best_size = ~0UL; 607 - 608 - __drm_mm_for_each_hole(entry, mm, adj_start, adj_end, 609 - flags & DRM_MM_SEARCH_BELOW) { 610 - u64 hole_size = adj_end - adj_start; 611 - 612 - if (mm->color_adjust) { 613 - mm->color_adjust(entry, color, &adj_start, &adj_end); 614 - if (adj_end <= adj_start) 615 - continue; 616 - } 617 - 618 - adj_start = max(adj_start, start); 619 - adj_end = min(adj_end, end); 620 - 621 - if (!check_free_hole(adj_start, adj_end, size, alignment)) 622 - continue; 623 - 624 - if (!(flags & DRM_MM_SEARCH_BEST)) 625 - return entry; 626 - 627 - if (hole_size < best_size) { 628 - best = entry; 629 - best_size = hole_size; 630 - } 631 - } 632 - 633 - return best; 634 - } 635 438 636 439 /** 637 440 * drm_mm_replace_node - move an allocation from @old to @new ··· 574 521 { 575 522 DRM_MM_BUG_ON(!old->allocated); 576 523 577 - list_replace(&old->node_list, &new->node_list); 578 - list_replace(&old->hole_stack, &new->hole_stack); 579 - rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree); 580 - new->hole_follows = old->hole_follows; 581 - new->mm = old->mm; 582 - new->start = old->start; 583 - new->size = old->size; 584 - new->color = old->color; 585 - new->__subtree_last = old->__subtree_last; 524 + *new = *old; 586 525 587 - old->allocated = 0; 588 - new->allocated = 1; 526 + list_replace(&old->node_list, &new->node_list); 527 + rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree); 528 + 529 + if (drm_mm_hole_follows(old)) { 530 + list_replace(&old->hole_stack, &new->hole_stack); 531 + rb_replace_node(&old->rb_hole_size, 532 + &new->rb_hole_size, 533 + &old->mm->holes_size); 534 + rb_replace_node(&old->rb_hole_addr, 535 + &new->rb_hole_addr, 536 + &old->mm->holes_addr); 537 + } 538 + 539 + old->allocated = false; 540 + new->allocated = true; 589 541 } 590 542 EXPORT_SYMBOL(drm_mm_replace_node); 591 543 ··· 635 577 * @color: opaque tag value to use for the allocation 636 578 * @start: start of the allowed range for the allocation 637 579 * @end: end of the allowed range for the allocation 638 - * @flags: flags to specify how the allocation will be performed afterwards 580 + * @mode: fine-tune the allocation search and placement 639 581 * 640 582 * This simply sets up the scanning routines with the parameters for the desired 641 583 * hole. ··· 651 593 unsigned long color, 652 594 u64 start, 653 595 u64 end, 654 - unsigned int flags) 596 + enum drm_mm_insert_mode mode) 655 597 { 656 598 DRM_MM_BUG_ON(start >= end); 657 599 DRM_MM_BUG_ON(!size || size > end - start); ··· 666 608 scan->alignment = alignment; 667 609 scan->remainder_mask = is_power_of_2(alignment) ? alignment - 1 : 0; 668 610 scan->size = size; 669 - scan->flags = flags; 611 + scan->mode = mode; 670 612 671 613 DRM_MM_BUG_ON(end <= start); 672 614 scan->range_start = start; ··· 725 667 if (adj_end <= adj_start || adj_end - adj_start < scan->size) 726 668 return false; 727 669 728 - if (scan->flags == DRM_MM_CREATE_TOP) 670 + if (scan->mode == DRM_MM_INSERT_HIGH) 729 671 adj_start = adj_end - scan->size; 730 672 731 673 if (scan->alignment) { ··· 737 679 div64_u64_rem(adj_start, scan->alignment, &rem); 738 680 if (rem) { 739 681 adj_start -= rem; 740 - if (scan->flags != DRM_MM_CREATE_TOP) 682 + if (scan->mode != DRM_MM_INSERT_HIGH) 741 683 adj_start += scan->alignment; 742 684 if (adj_start < max(col_start, scan->range_start) || 743 685 min(col_end, scan->range_end) - adj_start < scan->size) ··· 833 775 834 776 hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack); 835 777 hole_start = __drm_mm_hole_node_start(hole); 836 - hole_end = __drm_mm_hole_node_end(hole); 778 + hole_end = hole_start + hole->hole_size; 837 779 838 780 DRM_MM_BUG_ON(hole_start > scan->hit_start); 839 781 DRM_MM_BUG_ON(hole_end < scan->hit_end); ··· 860 802 { 861 803 DRM_MM_BUG_ON(start + size <= start); 862 804 805 + mm->color_adjust = NULL; 806 + 863 807 INIT_LIST_HEAD(&mm->hole_stack); 864 - mm->scan_active = 0; 808 + mm->interval_tree = RB_ROOT; 809 + mm->holes_size = RB_ROOT; 810 + mm->holes_addr = RB_ROOT; 865 811 866 812 /* Clever trick to avoid a special case in the free hole tracking. */ 867 813 INIT_LIST_HEAD(&mm->head_node.node_list); 868 - mm->head_node.allocated = 0; 869 - mm->head_node.hole_follows = 1; 814 + mm->head_node.allocated = false; 870 815 mm->head_node.mm = mm; 871 816 mm->head_node.start = start + size; 872 - mm->head_node.size = start - mm->head_node.start; 873 - list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack); 817 + mm->head_node.size = -size; 818 + add_hole(&mm->head_node); 874 819 875 - mm->interval_tree = RB_ROOT; 876 - 877 - mm->color_adjust = NULL; 820 + mm->scan_active = 0; 878 821 } 879 822 EXPORT_SYMBOL(drm_mm_init); 880 823 ··· 896 837 897 838 static u64 drm_mm_dump_hole(struct drm_printer *p, const struct drm_mm_node *entry) 898 839 { 899 - u64 hole_start, hole_end, hole_size; 840 + u64 start, size; 900 841 901 - if (entry->hole_follows) { 902 - hole_start = drm_mm_hole_node_start(entry); 903 - hole_end = drm_mm_hole_node_end(entry); 904 - hole_size = hole_end - hole_start; 905 - drm_printf(p, "%#018llx-%#018llx: %llu: free\n", hole_start, 906 - hole_end, hole_size); 907 - return hole_size; 842 + size = entry->hole_size; 843 + if (size) { 844 + start = drm_mm_hole_node_start(entry); 845 + drm_printf(p, "%#018llx-%#018llx: %llu: free\n", 846 + start, start + size, size); 908 847 } 909 848 910 - return 0; 849 + return size; 911 850 } 912 - 913 851 /** 914 852 * drm_mm_print - print allocator state 915 853 * @mm: drm_mm allocator to print
+1 -2
drivers/gpu/drm/drm_vma_manager.c
··· 212 212 goto out_unlock; 213 213 } 214 214 215 - ret = drm_mm_insert_node(&mgr->vm_addr_space_mm, &node->vm_node, 216 - pages, 0, DRM_MM_SEARCH_DEFAULT); 215 + ret = drm_mm_insert_node(&mgr->vm_addr_space_mm, &node->vm_node, pages); 217 216 if (ret) 218 217 goto out_unlock; 219 218
+7 -4
drivers/gpu/drm/etnaviv/etnaviv_mmu.c
··· 108 108 struct drm_mm_node *node, size_t size) 109 109 { 110 110 struct etnaviv_vram_mapping *free = NULL; 111 + enum drm_mm_insert_mode mode = DRM_MM_INSERT_LOW; 111 112 int ret; 112 113 113 114 lockdep_assert_held(&mmu->lock); ··· 120 119 bool found; 121 120 122 121 ret = drm_mm_insert_node_in_range(&mmu->mm, node, 123 - size, 0, mmu->last_iova, ~0UL, 124 - DRM_MM_SEARCH_DEFAULT); 125 - 122 + size, 0, 0, 123 + mmu->last_iova, U64_MAX, 124 + mode); 126 125 if (ret != -ENOSPC) 127 126 break; 128 127 ··· 137 136 } 138 137 139 138 /* Try to retire some entries */ 140 - drm_mm_scan_init(&scan, &mmu->mm, size, 0, 0, 0); 139 + drm_mm_scan_init(&scan, &mmu->mm, size, 0, 0, mode); 141 140 142 141 found = 0; 143 142 INIT_LIST_HEAD(&list); ··· 188 187 list_del_init(&m->mmu_node); 189 188 list_del_init(&m->scan_node); 190 189 } 190 + 191 + mode = DRM_MM_INSERT_EVICT; 191 192 192 193 /* 193 194 * We removed enough mappings so that the new allocation will
+4 -6
drivers/gpu/drm/i915/i915_gem.c
··· 69 69 struct drm_mm_node *node, u32 size) 70 70 { 71 71 memset(node, 0, sizeof(*node)); 72 - return drm_mm_insert_node_in_range_generic(&ggtt->base.mm, node, 73 - size, 0, 74 - I915_COLOR_UNEVICTABLE, 75 - 0, ggtt->mappable_end, 76 - DRM_MM_SEARCH_DEFAULT, 77 - DRM_MM_CREATE_DEFAULT); 72 + return drm_mm_insert_node_in_range(&ggtt->base.mm, node, 73 + size, 0, I915_COLOR_UNEVICTABLE, 74 + 0, ggtt->mappable_end, 75 + DRM_MM_INSERT_LOW); 78 76 } 79 77 80 78 static void
+7 -2
drivers/gpu/drm/i915/i915_gem_evict.c
··· 109 109 }, **phase; 110 110 struct i915_vma *vma, *next; 111 111 struct drm_mm_node *node; 112 + enum drm_mm_insert_mode mode; 112 113 int ret; 113 114 114 115 lockdep_assert_held(&vm->i915->drm.struct_mutex); ··· 128 127 * On each list, the oldest objects lie at the HEAD with the freshest 129 128 * object on the TAIL. 130 129 */ 130 + mode = DRM_MM_INSERT_BEST; 131 + if (flags & PIN_HIGH) 132 + mode = DRM_MM_INSERT_HIGH; 133 + if (flags & PIN_MAPPABLE) 134 + mode = DRM_MM_INSERT_LOW; 131 135 drm_mm_scan_init_with_range(&scan, &vm->mm, 132 136 min_size, alignment, cache_level, 133 - start, end, 134 - flags & PIN_HIGH ? DRM_MM_CREATE_TOP : 0); 137 + start, end, mode); 135 138 136 139 /* Retire before we search the active list. Although we have 137 140 * reasonable accuracy in our retirement lists, we may have
+2 -3
drivers/gpu/drm/i915/i915_gem_execbuffer.c
··· 436 436 PIN_MAPPABLE | PIN_NONBLOCK); 437 437 if (IS_ERR(vma)) { 438 438 memset(&cache->node, 0, sizeof(cache->node)); 439 - ret = drm_mm_insert_node_in_range_generic 439 + ret = drm_mm_insert_node_in_range 440 440 (&ggtt->base.mm, &cache->node, 441 441 PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 442 442 0, ggtt->mappable_end, 443 - DRM_MM_SEARCH_DEFAULT, 444 - DRM_MM_CREATE_DEFAULT); 443 + DRM_MM_INSERT_LOW); 445 444 if (ret) /* no inactive aperture space, use cpu reloc */ 446 445 return NULL; 447 446 } else {
+16 -23
drivers/gpu/drm/i915/i915_gem_gtt.c
··· 2748 2748 return ret; 2749 2749 2750 2750 /* Reserve a mappable slot for our lockless error capture */ 2751 - ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm, 2752 - &ggtt->error_capture, 2753 - PAGE_SIZE, 0, 2754 - I915_COLOR_UNEVICTABLE, 2755 - 0, ggtt->mappable_end, 2756 - 0, 0); 2751 + ret = drm_mm_insert_node_in_range(&ggtt->base.mm, &ggtt->error_capture, 2752 + PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 2753 + 0, ggtt->mappable_end, 2754 + DRM_MM_INSERT_LOW); 2757 2755 if (ret) 2758 2756 return ret; 2759 2757 ··· 3661 3663 u64 size, u64 alignment, unsigned long color, 3662 3664 u64 start, u64 end, unsigned int flags) 3663 3665 { 3664 - u32 search_flag, alloc_flag; 3666 + enum drm_mm_insert_mode mode; 3665 3667 u64 offset; 3666 3668 int err; 3667 3669 ··· 3682 3684 if (unlikely(round_up(start, alignment) > round_down(end - size, alignment))) 3683 3685 return -ENOSPC; 3684 3686 3685 - if (flags & PIN_HIGH) { 3686 - search_flag = DRM_MM_SEARCH_BELOW; 3687 - alloc_flag = DRM_MM_CREATE_TOP; 3688 - } else { 3689 - search_flag = DRM_MM_SEARCH_DEFAULT; 3690 - alloc_flag = DRM_MM_CREATE_DEFAULT; 3691 - } 3687 + mode = DRM_MM_INSERT_BEST; 3688 + if (flags & PIN_HIGH) 3689 + mode = DRM_MM_INSERT_HIGH; 3690 + if (flags & PIN_MAPPABLE) 3691 + mode = DRM_MM_INSERT_LOW; 3692 3692 3693 3693 /* We only allocate in PAGE_SIZE/GTT_PAGE_SIZE (4096) chunks, 3694 3694 * so we know that we always have a minimum alignment of 4096. ··· 3698 3702 if (alignment <= I915_GTT_MIN_ALIGNMENT) 3699 3703 alignment = 0; 3700 3704 3701 - err = drm_mm_insert_node_in_range_generic(&vm->mm, node, 3702 - size, alignment, color, 3703 - start, end, 3704 - search_flag, alloc_flag); 3705 + err = drm_mm_insert_node_in_range(&vm->mm, node, 3706 + size, alignment, color, 3707 + start, end, mode); 3705 3708 if (err != -ENOSPC) 3706 3709 return err; 3707 3710 ··· 3738 3743 if (err) 3739 3744 return err; 3740 3745 3741 - search_flag = DRM_MM_SEARCH_DEFAULT; 3742 - return drm_mm_insert_node_in_range_generic(&vm->mm, node, 3743 - size, alignment, color, 3744 - start, end, 3745 - search_flag, alloc_flag); 3746 + return drm_mm_insert_node_in_range(&vm->mm, node, 3747 + size, alignment, color, 3748 + start, end, DRM_MM_INSERT_EVICT); 3746 3749 }
+3 -3
drivers/gpu/drm/i915/i915_gem_stolen.c
··· 55 55 return -ENODEV; 56 56 57 57 mutex_lock(&dev_priv->mm.stolen_lock); 58 - ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size, 59 - alignment, start, end, 60 - DRM_MM_SEARCH_DEFAULT); 58 + ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, 59 + size, alignment, 0, 60 + start, end, DRM_MM_INSERT_BEST); 61 61 mutex_unlock(&dev_priv->mm.stolen_lock); 62 62 63 63 return ret;
+1 -2
drivers/gpu/drm/msm/msm_gem.c
··· 54 54 if (!p) 55 55 return ERR_PTR(-ENOMEM); 56 56 57 - ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, 58 - npages, 0, DRM_MM_SEARCH_DEFAULT); 57 + ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, npages); 59 58 if (ret) { 60 59 drm_free_large(p); 61 60 return ERR_PTR(ret);
+1 -2
drivers/gpu/drm/msm/msm_gem_vma.c
··· 45 45 if (WARN_ON(drm_mm_node_allocated(&vma->node))) 46 46 return 0; 47 47 48 - ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages, 49 - 0, DRM_MM_SEARCH_DEFAULT); 48 + ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); 50 49 if (ret) 51 50 return ret; 52 51
+26 -32
drivers/gpu/drm/selftests/test-drm_mm.c
··· 22 22 static unsigned int max_prime = 128; 23 23 24 24 enum { 25 - DEFAULT, 26 - TOPDOWN, 27 25 BEST, 26 + BOTTOMUP, 27 + TOPDOWN, 28 + EVICT, 28 29 }; 29 30 30 31 static const struct insert_mode { 31 32 const char *name; 32 - unsigned int search_flags; 33 - unsigned int create_flags; 33 + enum drm_mm_insert_mode mode; 34 34 } insert_modes[] = { 35 - [DEFAULT] = { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT }, 36 - [TOPDOWN] = { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP }, 37 - [BEST] = { "best", DRM_MM_SEARCH_BEST, DRM_MM_CREATE_DEFAULT }, 35 + [BEST] = { "best", DRM_MM_INSERT_BEST }, 36 + [BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW }, 37 + [TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH }, 38 + [EVICT] = { "evict", DRM_MM_INSERT_EVICT }, 38 39 {} 39 40 }, evict_modes[] = { 40 - { "default", DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT }, 41 - { "top-down", DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP }, 41 + { "bottom-up", DRM_MM_INSERT_LOW }, 42 + { "top-down", DRM_MM_INSERT_HIGH }, 42 43 {} 43 44 }; 44 45 ··· 527 526 528 527 err = drm_mm_insert_node_generic(mm, node, 529 528 size, alignment, color, 530 - mode->search_flags, 531 - mode->create_flags); 529 + mode->mode); 532 530 if (err) { 533 531 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", 534 532 size, alignment, color, mode->name, err); ··· 547 547 struct drm_mm_node tmp = {}; 548 548 int err; 549 549 550 - err = drm_mm_insert_node(mm, &tmp, size, 0, DRM_MM_SEARCH_DEFAULT); 550 + err = drm_mm_insert_node(mm, &tmp, size); 551 551 if (likely(err == -ENOSPC)) 552 552 return true; 553 553 ··· 753 753 { 754 754 int err; 755 755 756 - err = drm_mm_insert_node_in_range_generic(mm, node, 757 - size, alignment, color, 758 - range_start, range_end, 759 - mode->search_flags, 760 - mode->create_flags); 756 + err = drm_mm_insert_node_in_range(mm, node, 757 + size, alignment, color, 758 + range_start, range_end, 759 + mode->mode); 761 760 if (err) { 762 761 pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", 763 762 size, alignment, color, mode->name, ··· 780 781 struct drm_mm_node tmp = {}; 781 782 int err; 782 783 783 - err = drm_mm_insert_node_in_range_generic(mm, &tmp, 784 - size, 0, 0, 785 - range_start, range_end, 786 - DRM_MM_SEARCH_DEFAULT, 787 - DRM_MM_CREATE_DEFAULT); 784 + err = drm_mm_insert_node_in_range(mm, &tmp, 785 + size, 0, 0, 786 + range_start, range_end, 787 + 0); 788 788 if (likely(err == -ENOSPC)) 789 789 return true; 790 790 ··· 1322 1324 drm_mm_scan_init_with_range(&scan, mm, 1323 1325 size, alignment, 0, 1324 1326 range_start, range_end, 1325 - mode->create_flags); 1327 + mode->mode); 1326 1328 if (!evict_nodes(&scan, 1327 1329 nodes, order, count, false, 1328 1330 &evict_list)) ··· 1330 1332 1331 1333 memset(&tmp, 0, sizeof(tmp)); 1332 1334 err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, 1333 - mode->search_flags, 1334 - mode->create_flags); 1335 + DRM_MM_INSERT_EVICT); 1335 1336 if (err) { 1336 1337 pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", 1337 1338 size, alignment); ··· 1405 1408 ret = -EINVAL; 1406 1409 drm_mm_init(&mm, 0, size); 1407 1410 for (n = 0; n < size; n++) { 1408 - err = drm_mm_insert_node(&mm, &nodes[n].node, 1, 0, 1409 - DRM_MM_SEARCH_DEFAULT); 1411 + err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1410 1412 if (err) { 1411 1413 pr_err("insert failed, step %d\n", n); 1412 1414 ret = err; ··· 1513 1517 ret = -EINVAL; 1514 1518 drm_mm_init(&mm, 0, size); 1515 1519 for (n = 0; n < size; n++) { 1516 - err = drm_mm_insert_node(&mm, &nodes[n].node, 1, 0, 1517 - DRM_MM_SEARCH_DEFAULT); 1520 + err = drm_mm_insert_node(&mm, &nodes[n].node, 1); 1518 1521 if (err) { 1519 1522 pr_err("insert failed, step %d\n", n); 1520 1523 ret = err; ··· 1899 1904 drm_mm_scan_init_with_range(&scan, mm, 1900 1905 size, alignment, color, 1901 1906 range_start, range_end, 1902 - mode->create_flags); 1907 + mode->mode); 1903 1908 if (!evict_nodes(&scan, 1904 1909 nodes, order, count, true, 1905 1910 &evict_list)) ··· 1907 1912 1908 1913 memset(&tmp, 0, sizeof(tmp)); 1909 1914 err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, 1910 - mode->search_flags, 1911 - mode->create_flags); 1915 + DRM_MM_INSERT_EVICT); 1912 1916 if (err) { 1913 1917 pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", 1914 1918 size, alignment, color, err);
+2 -4
drivers/gpu/drm/sis/sis_mm.c
··· 109 109 if (pool == AGP_TYPE) { 110 110 retval = drm_mm_insert_node(&dev_priv->agp_mm, 111 111 &item->mm_node, 112 - mem->size, 0, 113 - DRM_MM_SEARCH_DEFAULT); 112 + mem->size); 114 113 offset = item->mm_node.start; 115 114 } else { 116 115 #if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE) ··· 121 122 #else 122 123 retval = drm_mm_insert_node(&dev_priv->vram_mm, 123 124 &item->mm_node, 124 - mem->size, 0, 125 - DRM_MM_SEARCH_DEFAULT); 125 + mem->size); 126 126 offset = item->mm_node.start; 127 127 #endif 128 128 }
+2 -2
drivers/gpu/drm/tegra/gem.c
··· 128 128 if (!bo->mm) 129 129 return -ENOMEM; 130 130 131 - err = drm_mm_insert_node_generic(&tegra->mm, bo->mm, bo->gem.size, 132 - PAGE_SIZE, 0, 0, 0); 131 + err = drm_mm_insert_node_generic(&tegra->mm, 132 + bo->mm, bo->gem.size, PAGE_SIZE, 0, 0); 133 133 if (err < 0) { 134 134 dev_err(tegra->drm->dev, "out of I/O virtual memory: %zd\n", 135 135 err);
+8 -10
drivers/gpu/drm/ttm/ttm_bo_manager.c
··· 54 54 { 55 55 struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; 56 56 struct drm_mm *mm = &rman->mm; 57 - struct drm_mm_node *node = NULL; 58 - enum drm_mm_search_flags sflags = DRM_MM_SEARCH_BEST; 59 - enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; 57 + struct drm_mm_node *node; 58 + enum drm_mm_insert_mode mode; 60 59 unsigned long lpfn; 61 60 int ret; 62 61 ··· 67 68 if (!node) 68 69 return -ENOMEM; 69 70 70 - if (place->flags & TTM_PL_FLAG_TOPDOWN) { 71 - sflags = DRM_MM_SEARCH_BELOW; 72 - aflags = DRM_MM_CREATE_TOP; 73 - } 71 + mode = DRM_MM_INSERT_BEST; 72 + if (place->flags & TTM_PL_FLAG_TOPDOWN) 73 + mode = DRM_MM_INSERT_HIGH; 74 74 75 75 spin_lock(&rman->lock); 76 - ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages, 76 + ret = drm_mm_insert_node_in_range(mm, node, 77 + mem->num_pages, 77 78 mem->page_alignment, 0, 78 - place->fpfn, lpfn, 79 - sflags, aflags); 79 + place->fpfn, lpfn, mode); 80 80 spin_unlock(&rman->lock); 81 81 82 82 if (unlikely(ret)) {
+1 -1
drivers/gpu/drm/vc4/vc4_crtc.c
··· 593 593 594 594 spin_lock_irqsave(&vc4->hvs->mm_lock, flags); 595 595 ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm, 596 - dlist_count, 1, 0); 596 + dlist_count); 597 597 spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags); 598 598 if (ret) 599 599 return ret;
+1 -2
drivers/gpu/drm/vc4/vc4_hvs.c
··· 141 141 int ret, i; 142 142 u32 __iomem *dst_kernel; 143 143 144 - ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS, 1, 145 - 0); 144 + ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS); 146 145 if (ret) { 147 146 DRM_ERROR("Failed to allocate space for filter kernel: %d\n", 148 147 ret);
+3 -3
drivers/gpu/drm/vc4/vc4_plane.c
··· 514 514 if (lbm_size) { 515 515 if (!vc4_state->lbm.allocated) { 516 516 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 517 - ret = drm_mm_insert_node(&vc4->hvs->lbm_mm, 518 - &vc4_state->lbm, 519 - lbm_size, 32, 0); 517 + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 518 + &vc4_state->lbm, 519 + lbm_size, 32, 0, 0); 520 520 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 521 521 } else { 522 522 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
+2 -2
drivers/gpu/drm/via/via_mm.c
··· 140 140 if (mem->type == VIA_MEM_AGP) 141 141 retval = drm_mm_insert_node(&dev_priv->agp_mm, 142 142 &item->mm_node, 143 - tmpSize, 0, DRM_MM_SEARCH_DEFAULT); 143 + tmpSize); 144 144 else 145 145 retval = drm_mm_insert_node(&dev_priv->vram_mm, 146 146 &item->mm_node, 147 - tmpSize, 0, DRM_MM_SEARCH_DEFAULT); 147 + tmpSize); 148 148 if (retval) 149 149 goto fail_alloc; 150 150
+2 -8
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
··· 673 673 674 674 memset(info->node, 0, sizeof(*info->node)); 675 675 spin_lock_bh(&man->lock); 676 - ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, 677 - 0, 0, 678 - DRM_MM_SEARCH_DEFAULT, 679 - DRM_MM_CREATE_DEFAULT); 676 + ret = drm_mm_insert_node(&man->mm, info->node, info->page_size); 680 677 if (ret) { 681 678 vmw_cmdbuf_man_process(man); 682 - ret = drm_mm_insert_node_generic(&man->mm, info->node, 683 - info->page_size, 0, 0, 684 - DRM_MM_SEARCH_DEFAULT, 685 - DRM_MM_CREATE_DEFAULT); 679 + ret = drm_mm_insert_node(&man->mm, info->node, info->page_size); 686 680 } 687 681 688 682 spin_unlock_bh(&man->lock);
+92 -92
include/drm/drm_mm.h
··· 53 53 #define DRM_MM_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 54 54 #endif 55 55 56 - enum drm_mm_search_flags { 57 - DRM_MM_SEARCH_DEFAULT = 0, 58 - DRM_MM_SEARCH_BEST = 1 << 0, 59 - DRM_MM_SEARCH_BELOW = 1 << 1, 60 - }; 56 + /** 57 + * enum drm_mm_insert_mode - control search and allocation behaviour 58 + * 59 + * The &struct drm_mm range manager supports finding a suitable modes using 60 + * a number of search trees. These trees are oranised by size, by address and 61 + * in most recent eviction order. This allows the user to find either the 62 + * smallest hole to reuse, the lowest or highest address to reuse, or simply 63 + * reuse the most recent eviction that fits. When allocating the &drm_mm_node 64 + * from within the hole, the &drm_mm_insert_mode also dictate whether to 65 + * allocate the lowest matching address or the highest. 66 + */ 67 + enum drm_mm_insert_mode { 68 + /** 69 + * @DRM_MM_INSERT_BEST: 70 + * 71 + * Search for the smallest hole (within the search range) that fits 72 + * the desired node. 73 + * 74 + * Allocates the node from the bottom of the found hole. 75 + */ 76 + DRM_MM_INSERT_BEST = 0, 61 77 62 - enum drm_mm_allocator_flags { 63 - DRM_MM_CREATE_DEFAULT = 0, 64 - DRM_MM_CREATE_TOP = 1 << 0, 65 - }; 78 + /** 79 + * @DRM_MM_INSERT_LOW: 80 + * 81 + * Search for the lowest hole (address closest to 0, within the search 82 + * range) that fits the desired node. 83 + * 84 + * Allocates the node from the bottom of the found hole. 85 + */ 86 + DRM_MM_INSERT_LOW, 66 87 67 - #define DRM_MM_BOTTOMUP DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT 68 - #define DRM_MM_TOPDOWN DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP 88 + /** 89 + * @DRM_MM_INSERT_HIGH: 90 + * 91 + * Search for the highest hole (address closest to U64_MAX, within the 92 + * search range) that fits the desired node. 93 + * 94 + * Allocates the node from the *top* of the found hole. The specified 95 + * alignment for the node is applied to the base of the node 96 + * (&drm_mm_node.start). 97 + */ 98 + DRM_MM_INSERT_HIGH, 99 + 100 + /** 101 + * @DRM_MM_INSERT_EVICT: 102 + * 103 + * Search for the most recently evicted hole (within the search range) 104 + * that fits the desired node. This is appropriate for use immediately 105 + * after performing an eviction scan (see drm_mm_scan_init()) and 106 + * removing the selected nodes to form a hole. 107 + * 108 + * Allocates the node from the bottom of the found hole. 109 + */ 110 + DRM_MM_INSERT_EVICT, 111 + }; 69 112 70 113 /** 71 114 * struct drm_mm_node - allocated block in the DRM allocator ··· 127 84 /** @size: Size of the allocated block. */ 128 85 u64 size; 129 86 /* private: */ 87 + struct drm_mm *mm; 130 88 struct list_head node_list; 131 89 struct list_head hole_stack; 132 90 struct rb_node rb; 133 - unsigned hole_follows : 1; 134 - unsigned allocated : 1; 135 - bool scanned_block : 1; 91 + struct rb_node rb_hole_size; 92 + struct rb_node rb_hole_addr; 136 93 u64 __subtree_last; 137 - struct drm_mm *mm; 94 + u64 hole_size; 95 + bool allocated : 1; 96 + bool scanned_block : 1; 138 97 #ifdef CONFIG_DRM_DEBUG_MM 139 98 depot_stack_handle_t stack; 140 99 #endif ··· 172 127 struct drm_mm_node head_node; 173 128 /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */ 174 129 struct rb_root interval_tree; 130 + struct rb_root holes_size; 131 + struct rb_root holes_addr; 175 132 176 133 unsigned long scan_active; 177 134 }; ··· 202 155 u64 hit_end; 203 156 204 157 unsigned long color; 205 - unsigned int flags; 158 + enum drm_mm_insert_mode mode; 206 159 }; 207 160 208 161 /** ··· 255 208 */ 256 209 static inline bool drm_mm_hole_follows(const struct drm_mm_node *node) 257 210 { 258 - return node->hole_follows; 211 + return node->hole_size; 259 212 } 260 213 261 214 static inline u64 __drm_mm_hole_node_start(const struct drm_mm_node *hole_node) ··· 338 291 #define drm_mm_for_each_node_safe(entry, next, mm) \ 339 292 list_for_each_entry_safe(entry, next, drm_mm_nodes(mm), node_list) 340 293 341 - #define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \ 342 - for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ 343 - &entry->hole_stack != &(mm)->hole_stack ? \ 344 - hole_start = drm_mm_hole_node_start(entry), \ 345 - hole_end = drm_mm_hole_node_end(entry), \ 346 - 1 : 0; \ 347 - entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack)) 348 - 349 294 /** 350 295 * drm_mm_for_each_hole - iterator to walk over all holes 351 - * @entry: &drm_mm_node used internally to track progress 296 + * @pos: &drm_mm_node used internally to track progress 352 297 * @mm: &drm_mm allocator to walk 353 298 * @hole_start: ulong variable to assign the hole start to on each iteration 354 299 * @hole_end: ulong variable to assign the hole end to on each iteration ··· 353 314 * Implementation Note: 354 315 * We need to inline list_for_each_entry in order to be able to set hole_start 355 316 * and hole_end on each iteration while keeping the macro sane. 356 - * 357 - * The __drm_mm_for_each_hole version is similar, but with added support for 358 - * going backwards. 359 317 */ 360 - #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \ 361 - __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, 0) 318 + #define drm_mm_for_each_hole(pos, mm, hole_start, hole_end) \ 319 + for (pos = list_first_entry(&(mm)->hole_stack, \ 320 + typeof(*pos), hole_stack); \ 321 + &pos->hole_stack != &(mm)->hole_stack ? \ 322 + hole_start = drm_mm_hole_node_start(pos), \ 323 + hole_end = hole_start + pos->hole_size, \ 324 + 1 : 0; \ 325 + pos = list_next_entry(pos, hole_stack)) 362 326 363 327 /* 364 328 * Basic range manager support (drm_mm.c) 365 329 */ 366 330 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node); 367 - int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, 368 - struct drm_mm_node *node, 369 - u64 size, 370 - u64 alignment, 371 - unsigned long color, 372 - u64 start, 373 - u64 end, 374 - enum drm_mm_search_flags sflags, 375 - enum drm_mm_allocator_flags aflags); 376 - 377 - /** 378 - * drm_mm_insert_node_in_range - ranged search for space and insert @node 379 - * @mm: drm_mm to allocate from 380 - * @node: preallocate node to insert 381 - * @size: size of the allocation 382 - * @alignment: alignment of the allocation 383 - * @start: start of the allowed range for this node 384 - * @end: end of the allowed range for this node 385 - * @flags: flags to fine-tune the allocation 386 - * 387 - * This is a simplified version of drm_mm_insert_node_in_range_generic() with 388 - * @color set to 0. 389 - * 390 - * The preallocated node must be cleared to 0. 391 - * 392 - * Returns: 393 - * 0 on success, -ENOSPC if there's no suitable hole. 394 - */ 395 - static inline int drm_mm_insert_node_in_range(struct drm_mm *mm, 396 - struct drm_mm_node *node, 397 - u64 size, 398 - u64 alignment, 399 - u64 start, 400 - u64 end, 401 - enum drm_mm_search_flags flags) 402 - { 403 - return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 404 - 0, start, end, flags, 405 - DRM_MM_CREATE_DEFAULT); 406 - } 331 + int drm_mm_insert_node_in_range(struct drm_mm *mm, 332 + struct drm_mm_node *node, 333 + u64 size, 334 + u64 alignment, 335 + unsigned long color, 336 + u64 start, 337 + u64 end, 338 + enum drm_mm_insert_mode mode); 407 339 408 340 /** 409 341 * drm_mm_insert_node_generic - search for space and insert @node ··· 383 373 * @size: size of the allocation 384 374 * @alignment: alignment of the allocation 385 375 * @color: opaque tag value to use for this node 386 - * @sflags: flags to fine-tune the allocation search 387 - * @aflags: flags to fine-tune the allocation behavior 376 + * @mode: fine-tune the allocation search and placement 388 377 * 389 378 * This is a simplified version of drm_mm_insert_node_in_range_generic() with no 390 379 * range restrictions applied. ··· 397 388 drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, 398 389 u64 size, u64 alignment, 399 390 unsigned long color, 400 - enum drm_mm_search_flags sflags, 401 - enum drm_mm_allocator_flags aflags) 391 + enum drm_mm_insert_mode mode) 402 392 { 403 - return drm_mm_insert_node_in_range_generic(mm, node, 404 - size, alignment, 0, 405 - 0, U64_MAX, 406 - sflags, aflags); 393 + return drm_mm_insert_node_in_range(mm, node, 394 + size, alignment, color, 395 + 0, U64_MAX, mode); 407 396 } 408 397 409 398 /** ··· 409 402 * @mm: drm_mm to allocate from 410 403 * @node: preallocate node to insert 411 404 * @size: size of the allocation 412 - * @alignment: alignment of the allocation 413 - * @flags: flags to fine-tune the allocation 414 405 * 415 406 * This is a simplified version of drm_mm_insert_node_generic() with @color set 416 407 * to 0. ··· 420 415 */ 421 416 static inline int drm_mm_insert_node(struct drm_mm *mm, 422 417 struct drm_mm_node *node, 423 - u64 size, 424 - u64 alignment, 425 - enum drm_mm_search_flags flags) 418 + u64 size) 426 419 { 427 - return drm_mm_insert_node_generic(mm, node, 428 - size, alignment, 0, 429 - flags, DRM_MM_CREATE_DEFAULT); 420 + return drm_mm_insert_node_generic(mm, node, size, 0, 0, 0); 430 421 } 431 422 432 423 void drm_mm_remove_node(struct drm_mm_node *node); ··· 469 468 struct drm_mm *mm, 470 469 u64 size, u64 alignment, unsigned long color, 471 470 u64 start, u64 end, 472 - unsigned int flags); 471 + enum drm_mm_insert_mode mode); 473 472 474 473 /** 475 474 * drm_mm_scan_init - initialize lru scanning ··· 478 477 * @size: size of the allocation 479 478 * @alignment: alignment of the allocation 480 479 * @color: opaque tag value to use for the allocation 481 - * @flags: flags to specify how the allocation will be performed afterwards 480 + * @mode: fine-tune the allocation search and placement 482 481 * 483 482 * This is a simplified version of drm_mm_scan_init_with_range() with no range 484 483 * restrictions applied. ··· 495 494 u64 size, 496 495 u64 alignment, 497 496 unsigned long color, 498 - unsigned int flags) 497 + enum drm_mm_insert_mode mode) 499 498 { 500 499 drm_mm_scan_init_with_range(scan, mm, 501 500 size, alignment, color, 502 - 0, U64_MAX, 503 - flags); 501 + 0, U64_MAX, mode); 504 502 } 505 503 506 504 bool drm_mm_scan_add_block(struct drm_mm_scan *scan,