![]() |
|
|||
0001 /************************************************************************** 0002 * 0003 * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA. 0004 * Copyright 2016 Intel Corporation 0005 * All Rights Reserved. 0006 * 0007 * Permission is hereby granted, free of charge, to any person obtaining a 0008 * copy of this software and associated documentation files (the 0009 * "Software"), to deal in the Software without restriction, including 0010 * without limitation the rights to use, copy, modify, merge, publish, 0011 * distribute, sub license, and/or sell copies of the Software, and to 0012 * permit persons to whom the Software is furnished to do so, subject to 0013 * the following conditions: 0014 * 0015 * The above copyright notice and this permission notice (including the 0016 * next paragraph) shall be included in all copies or substantial portions 0017 * of the Software. 0018 * 0019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0021 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 0022 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 0023 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 0024 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 0025 * USE OR OTHER DEALINGS IN THE SOFTWARE. 0026 * 0027 * 0028 **************************************************************************/ 0029 /* 0030 * Authors: 0031 * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> 0032 */ 0033 0034 #ifndef _DRM_MM_H_ 0035 #define _DRM_MM_H_ 0036 0037 /* 0038 * Generic range manager structs 0039 */ 0040 #include <linux/bug.h> 0041 #include <linux/rbtree.h> 0042 #include <linux/limits.h> 0043 #include <linux/mm_types.h> 0044 #include <linux/list.h> 0045 #include <linux/spinlock.h> 0046 #ifdef CONFIG_DRM_DEBUG_MM 0047 #include <linux/stackdepot.h> 0048 #endif 0049 #include <linux/types.h> 0050 0051 #include <drm/drm_print.h> 0052 0053 #ifdef CONFIG_DRM_DEBUG_MM 0054 #define DRM_MM_BUG_ON(expr) BUG_ON(expr) 0055 #else 0056 #define DRM_MM_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr) 0057 #endif 0058 0059 /** 0060 * enum drm_mm_insert_mode - control search and allocation behaviour 0061 * 0062 * The &struct drm_mm range manager supports finding a suitable modes using 0063 * a number of search trees. These trees are oranised by size, by address and 0064 * in most recent eviction order. This allows the user to find either the 0065 * smallest hole to reuse, the lowest or highest address to reuse, or simply 0066 * reuse the most recent eviction that fits. When allocating the &drm_mm_node 0067 * from within the hole, the &drm_mm_insert_mode also dictate whether to 0068 * allocate the lowest matching address or the highest. 0069 */ 0070 enum drm_mm_insert_mode { 0071 /** 0072 * @DRM_MM_INSERT_BEST: 0073 * 0074 * Search for the smallest hole (within the search range) that fits 0075 * the desired node. 0076 * 0077 * Allocates the node from the bottom of the found hole. 0078 */ 0079 DRM_MM_INSERT_BEST = 0, 0080 0081 /** 0082 * @DRM_MM_INSERT_LOW: 0083 * 0084 * Search for the lowest hole (address closest to 0, within the search 0085 * range) that fits the desired node. 0086 * 0087 * Allocates the node from the bottom of the found hole. 0088 */ 0089 DRM_MM_INSERT_LOW, 0090 0091 /** 0092 * @DRM_MM_INSERT_HIGH: 0093 * 0094 * Search for the highest hole (address closest to U64_MAX, within the 0095 * search range) that fits the desired node. 0096 * 0097 * Allocates the node from the *top* of the found hole. The specified 0098 * alignment for the node is applied to the base of the node 0099 * (&drm_mm_node.start). 0100 */ 0101 DRM_MM_INSERT_HIGH, 0102 0103 /** 0104 * @DRM_MM_INSERT_EVICT: 0105 * 0106 * Search for the most recently evicted hole (within the search range) 0107 * that fits the desired node. This is appropriate for use immediately 0108 * after performing an eviction scan (see drm_mm_scan_init()) and 0109 * removing the selected nodes to form a hole. 0110 * 0111 * Allocates the node from the bottom of the found hole. 0112 */ 0113 DRM_MM_INSERT_EVICT, 0114 0115 /** 0116 * @DRM_MM_INSERT_ONCE: 0117 * 0118 * Only check the first hole for suitablity and report -ENOSPC 0119 * immediately otherwise, rather than check every hole until a 0120 * suitable one is found. Can only be used in conjunction with another 0121 * search method such as DRM_MM_INSERT_HIGH or DRM_MM_INSERT_LOW. 0122 */ 0123 DRM_MM_INSERT_ONCE = BIT(31), 0124 0125 /** 0126 * @DRM_MM_INSERT_HIGHEST: 0127 * 0128 * Only check the highest hole (the hole with the largest address) and 0129 * insert the node at the top of the hole or report -ENOSPC if 0130 * unsuitable. 0131 * 0132 * Does not search all holes. 0133 */ 0134 DRM_MM_INSERT_HIGHEST = DRM_MM_INSERT_HIGH | DRM_MM_INSERT_ONCE, 0135 0136 /** 0137 * @DRM_MM_INSERT_LOWEST: 0138 * 0139 * Only check the lowest hole (the hole with the smallest address) and 0140 * insert the node at the bottom of the hole or report -ENOSPC if 0141 * unsuitable. 0142 * 0143 * Does not search all holes. 0144 */ 0145 DRM_MM_INSERT_LOWEST = DRM_MM_INSERT_LOW | DRM_MM_INSERT_ONCE, 0146 }; 0147 0148 /** 0149 * struct drm_mm_node - allocated block in the DRM allocator 0150 * 0151 * This represents an allocated block in a &drm_mm allocator. Except for 0152 * pre-reserved nodes inserted using drm_mm_reserve_node() the structure is 0153 * entirely opaque and should only be accessed through the provided funcions. 0154 * Since allocation of these nodes is entirely handled by the driver they can be 0155 * embedded. 0156 */ 0157 struct drm_mm_node { 0158 /** @color: Opaque driver-private tag. */ 0159 unsigned long color; 0160 /** @start: Start address of the allocated block. */ 0161 u64 start; 0162 /** @size: Size of the allocated block. */ 0163 u64 size; 0164 /* private: */ 0165 struct drm_mm *mm; 0166 struct list_head node_list; 0167 struct list_head hole_stack; 0168 struct rb_node rb; 0169 struct rb_node rb_hole_size; 0170 struct rb_node rb_hole_addr; 0171 u64 __subtree_last; 0172 u64 hole_size; 0173 u64 subtree_max_hole; 0174 unsigned long flags; 0175 #define DRM_MM_NODE_ALLOCATED_BIT 0 0176 #define DRM_MM_NODE_SCANNED_BIT 1 0177 #ifdef CONFIG_DRM_DEBUG_MM 0178 depot_stack_handle_t stack; 0179 #endif 0180 }; 0181 0182 /** 0183 * struct drm_mm - DRM allocator 0184 * 0185 * DRM range allocator with a few special functions and features geared towards 0186 * managing GPU memory. Except for the @color_adjust callback the structure is 0187 * entirely opaque and should only be accessed through the provided functions 0188 * and macros. This structure can be embedded into larger driver structures. 0189 */ 0190 struct drm_mm { 0191 /** 0192 * @color_adjust: 0193 * 0194 * Optional driver callback to further apply restrictions on a hole. The 0195 * node argument points at the node containing the hole from which the 0196 * block would be allocated (see drm_mm_hole_follows() and friends). The 0197 * other arguments are the size of the block to be allocated. The driver 0198 * can adjust the start and end as needed to e.g. insert guard pages. 0199 */ 0200 void (*color_adjust)(const struct drm_mm_node *node, 0201 unsigned long color, 0202 u64 *start, u64 *end); 0203 0204 /* private: */ 0205 /* List of all memory nodes that immediately precede a free hole. */ 0206 struct list_head hole_stack; 0207 /* head_node.node_list is the list of all memory nodes, ordered 0208 * according to the (increasing) start address of the memory node. */ 0209 struct drm_mm_node head_node; 0210 /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */ 0211 struct rb_root_cached interval_tree; 0212 struct rb_root_cached holes_size; 0213 struct rb_root holes_addr; 0214 0215 unsigned long scan_active; 0216 }; 0217 0218 /** 0219 * struct drm_mm_scan - DRM allocator eviction roaster data 0220 * 0221 * This structure tracks data needed for the eviction roaster set up using 0222 * drm_mm_scan_init(), and used with drm_mm_scan_add_block() and 0223 * drm_mm_scan_remove_block(). The structure is entirely opaque and should only 0224 * be accessed through the provided functions and macros. It is meant to be 0225 * allocated temporarily by the driver on the stack. 0226 */ 0227 struct drm_mm_scan { 0228 /* private: */ 0229 struct drm_mm *mm; 0230 0231 u64 size; 0232 u64 alignment; 0233 u64 remainder_mask; 0234 0235 u64 range_start; 0236 u64 range_end; 0237 0238 u64 hit_start; 0239 u64 hit_end; 0240 0241 unsigned long color; 0242 enum drm_mm_insert_mode mode; 0243 }; 0244 0245 /** 0246 * drm_mm_node_allocated - checks whether a node is allocated 0247 * @node: drm_mm_node to check 0248 * 0249 * Drivers are required to clear a node prior to using it with the 0250 * drm_mm range manager. 0251 * 0252 * Drivers should use this helper for proper encapsulation of drm_mm 0253 * internals. 0254 * 0255 * Returns: 0256 * True if the @node is allocated. 0257 */ 0258 static inline bool drm_mm_node_allocated(const struct drm_mm_node *node) 0259 { 0260 return test_bit(DRM_MM_NODE_ALLOCATED_BIT, &node->flags); 0261 } 0262 0263 /** 0264 * drm_mm_initialized - checks whether an allocator is initialized 0265 * @mm: drm_mm to check 0266 * 0267 * Drivers should clear the struct drm_mm prior to initialisation if they 0268 * want to use this function. 0269 * 0270 * Drivers should use this helper for proper encapsulation of drm_mm 0271 * internals. 0272 * 0273 * Returns: 0274 * True if the @mm is initialized. 0275 */ 0276 static inline bool drm_mm_initialized(const struct drm_mm *mm) 0277 { 0278 return READ_ONCE(mm->hole_stack.next); 0279 } 0280 0281 /** 0282 * drm_mm_hole_follows - checks whether a hole follows this node 0283 * @node: drm_mm_node to check 0284 * 0285 * Holes are embedded into the drm_mm using the tail of a drm_mm_node. 0286 * If you wish to know whether a hole follows this particular node, 0287 * query this function. See also drm_mm_hole_node_start() and 0288 * drm_mm_hole_node_end(). 0289 * 0290 * Returns: 0291 * True if a hole follows the @node. 0292 */ 0293 static inline bool drm_mm_hole_follows(const struct drm_mm_node *node) 0294 { 0295 return node->hole_size; 0296 } 0297 0298 static inline u64 __drm_mm_hole_node_start(const struct drm_mm_node *hole_node) 0299 { 0300 return hole_node->start + hole_node->size; 0301 } 0302 0303 /** 0304 * drm_mm_hole_node_start - computes the start of the hole following @node 0305 * @hole_node: drm_mm_node which implicitly tracks the following hole 0306 * 0307 * This is useful for driver-specific debug dumpers. Otherwise drivers should 0308 * not inspect holes themselves. Drivers must check first whether a hole indeed 0309 * follows by looking at drm_mm_hole_follows() 0310 * 0311 * Returns: 0312 * Start of the subsequent hole. 0313 */ 0314 static inline u64 drm_mm_hole_node_start(const struct drm_mm_node *hole_node) 0315 { 0316 DRM_MM_BUG_ON(!drm_mm_hole_follows(hole_node)); 0317 return __drm_mm_hole_node_start(hole_node); 0318 } 0319 0320 static inline u64 __drm_mm_hole_node_end(const struct drm_mm_node *hole_node) 0321 { 0322 return list_next_entry(hole_node, node_list)->start; 0323 } 0324 0325 /** 0326 * drm_mm_hole_node_end - computes the end of the hole following @node 0327 * @hole_node: drm_mm_node which implicitly tracks the following hole 0328 * 0329 * This is useful for driver-specific debug dumpers. Otherwise drivers should 0330 * not inspect holes themselves. Drivers must check first whether a hole indeed 0331 * follows by looking at drm_mm_hole_follows(). 0332 * 0333 * Returns: 0334 * End of the subsequent hole. 0335 */ 0336 static inline u64 drm_mm_hole_node_end(const struct drm_mm_node *hole_node) 0337 { 0338 return __drm_mm_hole_node_end(hole_node); 0339 } 0340 0341 /** 0342 * drm_mm_nodes - list of nodes under the drm_mm range manager 0343 * @mm: the struct drm_mm range manager 0344 * 0345 * As the drm_mm range manager hides its node_list deep with its 0346 * structure, extracting it looks painful and repetitive. This is 0347 * not expected to be used outside of the drm_mm_for_each_node() 0348 * macros and similar internal functions. 0349 * 0350 * Returns: 0351 * The node list, may be empty. 0352 */ 0353 #define drm_mm_nodes(mm) (&(mm)->head_node.node_list) 0354 0355 /** 0356 * drm_mm_for_each_node - iterator to walk over all allocated nodes 0357 * @entry: &struct drm_mm_node to assign to in each iteration step 0358 * @mm: &drm_mm allocator to walk 0359 * 0360 * This iterator walks over all nodes in the range allocator. It is implemented 0361 * with list_for_each(), so not save against removal of elements. 0362 */ 0363 #define drm_mm_for_each_node(entry, mm) \ 0364 list_for_each_entry(entry, drm_mm_nodes(mm), node_list) 0365 0366 /** 0367 * drm_mm_for_each_node_safe - iterator to walk over all allocated nodes 0368 * @entry: &struct drm_mm_node to assign to in each iteration step 0369 * @next: &struct drm_mm_node to store the next step 0370 * @mm: &drm_mm allocator to walk 0371 * 0372 * This iterator walks over all nodes in the range allocator. It is implemented 0373 * with list_for_each_safe(), so save against removal of elements. 0374 */ 0375 #define drm_mm_for_each_node_safe(entry, next, mm) \ 0376 list_for_each_entry_safe(entry, next, drm_mm_nodes(mm), node_list) 0377 0378 /** 0379 * drm_mm_for_each_hole - iterator to walk over all holes 0380 * @pos: &drm_mm_node used internally to track progress 0381 * @mm: &drm_mm allocator to walk 0382 * @hole_start: ulong variable to assign the hole start to on each iteration 0383 * @hole_end: ulong variable to assign the hole end to on each iteration 0384 * 0385 * This iterator walks over all holes in the range allocator. It is implemented 0386 * with list_for_each(), so not save against removal of elements. @entry is used 0387 * internally and will not reflect a real drm_mm_node for the very first hole. 0388 * Hence users of this iterator may not access it. 0389 * 0390 * Implementation Note: 0391 * We need to inline list_for_each_entry in order to be able to set hole_start 0392 * and hole_end on each iteration while keeping the macro sane. 0393 */ 0394 #define drm_mm_for_each_hole(pos, mm, hole_start, hole_end) \ 0395 for (pos = list_first_entry(&(mm)->hole_stack, \ 0396 typeof(*pos), hole_stack); \ 0397 &pos->hole_stack != &(mm)->hole_stack ? \ 0398 hole_start = drm_mm_hole_node_start(pos), \ 0399 hole_end = hole_start + pos->hole_size, \ 0400 1 : 0; \ 0401 pos = list_next_entry(pos, hole_stack)) 0402 0403 /* 0404 * Basic range manager support (drm_mm.c) 0405 */ 0406 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node); 0407 int drm_mm_insert_node_in_range(struct drm_mm *mm, 0408 struct drm_mm_node *node, 0409 u64 size, 0410 u64 alignment, 0411 unsigned long color, 0412 u64 start, 0413 u64 end, 0414 enum drm_mm_insert_mode mode); 0415 0416 /** 0417 * drm_mm_insert_node_generic - search for space and insert @node 0418 * @mm: drm_mm to allocate from 0419 * @node: preallocate node to insert 0420 * @size: size of the allocation 0421 * @alignment: alignment of the allocation 0422 * @color: opaque tag value to use for this node 0423 * @mode: fine-tune the allocation search and placement 0424 * 0425 * This is a simplified version of drm_mm_insert_node_in_range() with no 0426 * range restrictions applied. 0427 * 0428 * The preallocated node must be cleared to 0. 0429 * 0430 * Returns: 0431 * 0 on success, -ENOSPC if there's no suitable hole. 0432 */ 0433 static inline int 0434 drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, 0435 u64 size, u64 alignment, 0436 unsigned long color, 0437 enum drm_mm_insert_mode mode) 0438 { 0439 return drm_mm_insert_node_in_range(mm, node, 0440 size, alignment, color, 0441 0, U64_MAX, mode); 0442 } 0443 0444 /** 0445 * drm_mm_insert_node - search for space and insert @node 0446 * @mm: drm_mm to allocate from 0447 * @node: preallocate node to insert 0448 * @size: size of the allocation 0449 * 0450 * This is a simplified version of drm_mm_insert_node_generic() with @color set 0451 * to 0. 0452 * 0453 * The preallocated node must be cleared to 0. 0454 * 0455 * Returns: 0456 * 0 on success, -ENOSPC if there's no suitable hole. 0457 */ 0458 static inline int drm_mm_insert_node(struct drm_mm *mm, 0459 struct drm_mm_node *node, 0460 u64 size) 0461 { 0462 return drm_mm_insert_node_generic(mm, node, size, 0, 0, 0); 0463 } 0464 0465 void drm_mm_remove_node(struct drm_mm_node *node); 0466 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); 0467 void drm_mm_init(struct drm_mm *mm, u64 start, u64 size); 0468 void drm_mm_takedown(struct drm_mm *mm); 0469 0470 /** 0471 * drm_mm_clean - checks whether an allocator is clean 0472 * @mm: drm_mm allocator to check 0473 * 0474 * Returns: 0475 * True if the allocator is completely free, false if there's still a node 0476 * allocated in it. 0477 */ 0478 static inline bool drm_mm_clean(const struct drm_mm *mm) 0479 { 0480 return list_empty(drm_mm_nodes(mm)); 0481 } 0482 0483 struct drm_mm_node * 0484 __drm_mm_interval_first(const struct drm_mm *mm, u64 start, u64 last); 0485 0486 /** 0487 * drm_mm_for_each_node_in_range - iterator to walk over a range of 0488 * allocated nodes 0489 * @node__: drm_mm_node structure to assign to in each iteration step 0490 * @mm__: drm_mm allocator to walk 0491 * @start__: starting offset, the first node will overlap this 0492 * @end__: ending offset, the last node will start before this (but may overlap) 0493 * 0494 * This iterator walks over all nodes in the range allocator that lie 0495 * between @start and @end. It is implemented similarly to list_for_each(), 0496 * but using the internal interval tree to accelerate the search for the 0497 * starting node, and so not safe against removal of elements. It assumes 0498 * that @end is within (or is the upper limit of) the drm_mm allocator. 0499 * If [@start, @end] are beyond the range of the drm_mm, the iterator may walk 0500 * over the special _unallocated_ &drm_mm.head_node, and may even continue 0501 * indefinitely. 0502 */ 0503 #define drm_mm_for_each_node_in_range(node__, mm__, start__, end__) \ 0504 for (node__ = __drm_mm_interval_first((mm__), (start__), (end__)-1); \ 0505 node__->start < (end__); \ 0506 node__ = list_next_entry(node__, node_list)) 0507 0508 void drm_mm_scan_init_with_range(struct drm_mm_scan *scan, 0509 struct drm_mm *mm, 0510 u64 size, u64 alignment, unsigned long color, 0511 u64 start, u64 end, 0512 enum drm_mm_insert_mode mode); 0513 0514 /** 0515 * drm_mm_scan_init - initialize lru scanning 0516 * @scan: scan state 0517 * @mm: drm_mm to scan 0518 * @size: size of the allocation 0519 * @alignment: alignment of the allocation 0520 * @color: opaque tag value to use for the allocation 0521 * @mode: fine-tune the allocation search and placement 0522 * 0523 * This is a simplified version of drm_mm_scan_init_with_range() with no range 0524 * restrictions applied. 0525 * 0526 * This simply sets up the scanning routines with the parameters for the desired 0527 * hole. 0528 * 0529 * Warning: 0530 * As long as the scan list is non-empty, no other operations than 0531 * adding/removing nodes to/from the scan list are allowed. 0532 */ 0533 static inline void drm_mm_scan_init(struct drm_mm_scan *scan, 0534 struct drm_mm *mm, 0535 u64 size, 0536 u64 alignment, 0537 unsigned long color, 0538 enum drm_mm_insert_mode mode) 0539 { 0540 drm_mm_scan_init_with_range(scan, mm, 0541 size, alignment, color, 0542 0, U64_MAX, mode); 0543 } 0544 0545 bool drm_mm_scan_add_block(struct drm_mm_scan *scan, 0546 struct drm_mm_node *node); 0547 bool drm_mm_scan_remove_block(struct drm_mm_scan *scan, 0548 struct drm_mm_node *node); 0549 struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan); 0550 0551 void drm_mm_print(const struct drm_mm *mm, struct drm_printer *p); 0552 0553 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |