1 1.1 riastrad /* $NetBSD: i915_buddy.h,v 1.2 2021/12/18 23:45:28 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* SPDX-License-Identifier: MIT */ 4 1.1 riastrad /* 5 1.1 riastrad * Copyright 2019 Intel Corporation 6 1.1 riastrad */ 7 1.1 riastrad 8 1.1 riastrad #ifndef __I915_BUDDY_H__ 9 1.1 riastrad #define __I915_BUDDY_H__ 10 1.1 riastrad 11 1.1 riastrad #include <linux/bitops.h> 12 1.1 riastrad #include <linux/list.h> 13 1.1 riastrad 14 1.1 riastrad struct i915_buddy_block { 15 1.1 riastrad #define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) 16 1.1 riastrad #define I915_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) 17 1.1 riastrad #define I915_BUDDY_ALLOCATED (1 << 10) 18 1.1 riastrad #define I915_BUDDY_FREE (2 << 10) 19 1.1 riastrad #define I915_BUDDY_SPLIT (3 << 10) 20 1.1 riastrad #define I915_BUDDY_HEADER_ORDER GENMASK_ULL(9, 0) 21 1.1 riastrad u64 header; 22 1.1 riastrad 23 1.1 riastrad struct i915_buddy_block *left; 24 1.1 riastrad struct i915_buddy_block *right; 25 1.1 riastrad struct i915_buddy_block *parent; 26 1.1 riastrad 27 1.1 riastrad void *private; /* owned by creator */ 28 1.1 riastrad 29 1.1 riastrad /* 30 1.1 riastrad * While the block is allocated by the user through i915_buddy_alloc*, 31 1.1 riastrad * the user has ownership of the link, for example to maintain within 32 1.1 riastrad * a list, if so desired. As soon as the block is freed with 33 1.1 riastrad * i915_buddy_free* ownership is given back to the mm. 34 1.1 riastrad */ 35 1.1 riastrad struct list_head link; 36 1.1 riastrad struct list_head tmp_link; 37 1.1 riastrad }; 38 1.1 riastrad 39 1.1 riastrad #define I915_BUDDY_MAX_ORDER I915_BUDDY_HEADER_ORDER 40 1.1 riastrad 41 1.1 riastrad /* 42 1.1 riastrad * Binary Buddy System. 43 1.1 riastrad * 44 1.1 riastrad * Locking should be handled by the user, a simple mutex around 45 1.1 riastrad * i915_buddy_alloc* and i915_buddy_free* should suffice. 46 1.1 riastrad */ 47 1.1 riastrad struct i915_buddy_mm { 48 1.1 riastrad /* Maintain a free list for each order. */ 49 1.1 riastrad struct list_head *free_list; 50 1.1 riastrad 51 1.1 riastrad /* 52 1.1 riastrad * Maintain explicit binary tree(s) to track the allocation of the 53 1.1 riastrad * address space. This gives us a simple way of finding a buddy block 54 1.1 riastrad * and performing the potentially recursive merge step when freeing a 55 1.1 riastrad * block. Nodes are either allocated or free, in which case they will 56 1.1 riastrad * also exist on the respective free list. 57 1.1 riastrad */ 58 1.1 riastrad struct i915_buddy_block **roots; 59 1.1 riastrad 60 1.1 riastrad /* 61 1.1 riastrad * Anything from here is public, and remains static for the lifetime of 62 1.1 riastrad * the mm. Everything above is considered do-not-touch. 63 1.1 riastrad */ 64 1.1 riastrad unsigned int n_roots; 65 1.1 riastrad unsigned int max_order; 66 1.1 riastrad 67 1.1 riastrad /* Must be at least PAGE_SIZE */ 68 1.1 riastrad u64 chunk_size; 69 1.1 riastrad u64 size; 70 1.1 riastrad }; 71 1.1 riastrad 72 1.1 riastrad static inline u64 73 1.1 riastrad i915_buddy_block_offset(struct i915_buddy_block *block) 74 1.1 riastrad { 75 1.1 riastrad return block->header & I915_BUDDY_HEADER_OFFSET; 76 1.1 riastrad } 77 1.1 riastrad 78 1.1 riastrad static inline unsigned int 79 1.1 riastrad i915_buddy_block_order(struct i915_buddy_block *block) 80 1.1 riastrad { 81 1.1 riastrad return block->header & I915_BUDDY_HEADER_ORDER; 82 1.1 riastrad } 83 1.1 riastrad 84 1.1 riastrad static inline unsigned int 85 1.1 riastrad i915_buddy_block_state(struct i915_buddy_block *block) 86 1.1 riastrad { 87 1.1 riastrad return block->header & I915_BUDDY_HEADER_STATE; 88 1.1 riastrad } 89 1.1 riastrad 90 1.1 riastrad static inline bool 91 1.1 riastrad i915_buddy_block_is_allocated(struct i915_buddy_block *block) 92 1.1 riastrad { 93 1.1 riastrad return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED; 94 1.1 riastrad } 95 1.1 riastrad 96 1.1 riastrad static inline bool 97 1.1 riastrad i915_buddy_block_is_free(struct i915_buddy_block *block) 98 1.1 riastrad { 99 1.1 riastrad return i915_buddy_block_state(block) == I915_BUDDY_FREE; 100 1.1 riastrad } 101 1.1 riastrad 102 1.1 riastrad static inline bool 103 1.1 riastrad i915_buddy_block_is_split(struct i915_buddy_block *block) 104 1.1 riastrad { 105 1.1 riastrad return i915_buddy_block_state(block) == I915_BUDDY_SPLIT; 106 1.1 riastrad } 107 1.1 riastrad 108 1.1 riastrad static inline u64 109 1.1 riastrad i915_buddy_block_size(struct i915_buddy_mm *mm, 110 1.1 riastrad struct i915_buddy_block *block) 111 1.1 riastrad { 112 1.1 riastrad return mm->chunk_size << i915_buddy_block_order(block); 113 1.1 riastrad } 114 1.1 riastrad 115 1.1 riastrad int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size); 116 1.1 riastrad 117 1.1 riastrad void i915_buddy_fini(struct i915_buddy_mm *mm); 118 1.1 riastrad 119 1.1 riastrad struct i915_buddy_block * 120 1.1 riastrad i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order); 121 1.1 riastrad 122 1.1 riastrad int i915_buddy_alloc_range(struct i915_buddy_mm *mm, 123 1.1 riastrad struct list_head *blocks, 124 1.1 riastrad u64 start, u64 size); 125 1.1 riastrad 126 1.1 riastrad void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block); 127 1.1 riastrad 128 1.1 riastrad void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects); 129 1.1 riastrad 130 1.1 riastrad #endif 131