| 1 | /* SPDX-License-Identifier: MIT */ |
| 2 | /* |
| 3 | * Copyright © 2021 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #ifndef __I915_VMA_RESOURCE_H__ |
| 7 | #define __I915_VMA_RESOURCE_H__ |
| 8 | |
| 9 | #include <linux/dma-fence.h> |
| 10 | #include <linux/refcount.h> |
| 11 | |
| 12 | #include "i915_gem.h" |
| 13 | #include "i915_scatterlist.h" |
| 14 | #include "i915_sw_fence.h" |
| 15 | #include "intel_runtime_pm.h" |
| 16 | |
| 17 | struct intel_memory_region; |
| 18 | |
| 19 | struct i915_page_sizes { |
| 20 | /** |
| 21 | * The sg mask of the pages sg_table. i.e the mask of |
| 22 | * the lengths for each sg entry. |
| 23 | */ |
| 24 | unsigned int phys; |
| 25 | |
| 26 | /** |
| 27 | * The gtt page sizes we are allowed to use given the |
| 28 | * sg mask and the supported page sizes. This will |
| 29 | * express the smallest unit we can use for the whole |
| 30 | * object, as well as the larger sizes we may be able |
| 31 | * to use opportunistically. |
| 32 | */ |
| 33 | unsigned int sg; |
| 34 | }; |
| 35 | |
| 36 | /** |
| 37 | * struct i915_vma_bindinfo - Information needed for async bind |
| 38 | * only but that can be dropped after the bind has taken place. |
| 39 | * Consider making this a separate argument to the bind_vma |
| 40 | * op, coalescing with other arguments like vm, stash, cache_level |
| 41 | * and flags |
| 42 | * @pages: The pages sg-table. |
| 43 | * @page_sizes: Page sizes of the pages. |
| 44 | * @pages_rsgt: Refcounted sg-table when delayed object destruction |
| 45 | * is supported. May be NULL. |
| 46 | * @readonly: Whether the vma should be bound read-only. |
| 47 | * @lmem: Whether the vma points to lmem. |
| 48 | */ |
| 49 | struct i915_vma_bindinfo { |
| 50 | struct sg_table *pages; |
| 51 | struct i915_page_sizes page_sizes; |
| 52 | struct i915_refct_sgt *pages_rsgt; |
| 53 | bool readonly:1; |
| 54 | bool lmem:1; |
| 55 | }; |
| 56 | |
| 57 | /** |
| 58 | * struct i915_vma_resource - Snapshotted unbind information. |
| 59 | * @unbind_fence: Fence to mark unbinding complete. Note that this fence |
| 60 | * is not considered published until unbind is scheduled, and as such it |
| 61 | * is illegal to access this fence before scheduled unbind other than |
| 62 | * for refcounting. |
| 63 | * @lock: The @unbind_fence lock. |
| 64 | * @hold_count: Number of holders blocking the fence from finishing. |
| 65 | * The vma itself is keeping a hold, which is released when unbind |
| 66 | * is scheduled. |
| 67 | * @work: Work struct for deferred unbind work. |
| 68 | * @chain: Pointer to struct i915_sw_fence used to await dependencies. |
| 69 | * @rb: Rb node for the vm's pending unbind interval tree. |
| 70 | * @__subtree_last: Interval tree private member. |
| 71 | * @wakeref: wakeref. |
| 72 | * @vm: non-refcounted pointer to the vm. This is for internal use only and |
| 73 | * this member is cleared after vm_resource unbind. |
| 74 | * @mr: The memory region of the object pointed to by the vma. |
| 75 | * @ops: Pointer to the backend i915_vma_ops. |
| 76 | * @private: Bind backend private info. |
| 77 | * @start: Offset into the address space of bind range start. Note that |
| 78 | * this is after any padding that might have been allocated. |
| 79 | * @node_size: Size of the allocated range manager node with padding |
| 80 | * subtracted. |
| 81 | * @vma_size: Bind size. |
| 82 | * @guard: The size of guard area preceding and trailing the bind. |
| 83 | * @page_sizes_gtt: Resulting page sizes from the bind operation. |
| 84 | * @bound_flags: Flags indicating binding status. |
| 85 | * @allocated: Backend private data. TODO: Should move into @private. |
| 86 | * @immediate_unbind: Unbind can be done immediately and doesn't need to be |
| 87 | * deferred to a work item awaiting unsignaled fences. This is a hack. |
| 88 | * (dma_fence_work uses a fence flag for this, but this seems slightly |
| 89 | * cleaner). |
| 90 | * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't |
| 91 | * take a wakeref in the dma-fence signalling critical path, it needs to be |
| 92 | * taken when the unbind is scheduled. |
| 93 | * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting |
| 94 | * needs to be skipped for unbind. |
| 95 | * @tlb: pointer for obj->mm.tlb, if async unbind. Otherwise, NULL |
| 96 | * |
| 97 | * The lifetime of a struct i915_vma_resource is from a binding request to |
| 98 | * the actual possible asynchronous unbind has completed. |
| 99 | */ |
| 100 | struct i915_vma_resource { |
| 101 | struct dma_fence unbind_fence; |
| 102 | /* See above for description of the lock. */ |
| 103 | spinlock_t lock; |
| 104 | refcount_t hold_count; |
| 105 | struct work_struct work; |
| 106 | struct i915_sw_fence chain; |
| 107 | struct rb_node rb; |
| 108 | u64 __subtree_last; |
| 109 | struct i915_address_space *vm; |
| 110 | intel_wakeref_t wakeref; |
| 111 | |
| 112 | /** |
| 113 | * @bi: Information needed for async bind only but that can be dropped |
| 114 | * after the bind has taken place. |
| 115 | * |
| 116 | * Consider making this a separate argument to the bind_vma op, |
| 117 | * coalescing with other arguments like vm, stash, cache_level and flags |
| 118 | */ |
| 119 | struct i915_vma_bindinfo bi; |
| 120 | |
| 121 | #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| 122 | struct intel_memory_region *mr; |
| 123 | #endif |
| 124 | const struct i915_vma_ops *ops; |
| 125 | void *private; |
| 126 | u64 start; |
| 127 | u64 node_size; |
| 128 | u64 vma_size; |
| 129 | u32 guard; |
| 130 | u32 page_sizes_gtt; |
| 131 | |
| 132 | u32 bound_flags; |
| 133 | bool allocated:1; |
| 134 | bool immediate_unbind:1; |
| 135 | bool needs_wakeref:1; |
| 136 | bool skip_pte_rewrite:1; |
| 137 | |
| 138 | u32 *tlb; |
| 139 | }; |
| 140 | |
| 141 | bool i915_vma_resource_hold(struct i915_vma_resource *vma_res, |
| 142 | bool *lockdep_cookie); |
| 143 | |
| 144 | void i915_vma_resource_unhold(struct i915_vma_resource *vma_res, |
| 145 | bool lockdep_cookie); |
| 146 | |
| 147 | struct i915_vma_resource *i915_vma_resource_alloc(void); |
| 148 | |
| 149 | void i915_vma_resource_free(struct i915_vma_resource *vma_res); |
| 150 | |
| 151 | struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res, |
| 152 | u32 *tlb); |
| 153 | |
| 154 | void __i915_vma_resource_init(struct i915_vma_resource *vma_res); |
| 155 | |
| 156 | /** |
| 157 | * i915_vma_resource_get - Take a reference on a vma resource |
| 158 | * @vma_res: The vma resource on which to take a reference. |
| 159 | * |
| 160 | * Return: The @vma_res pointer |
| 161 | */ |
| 162 | static inline struct i915_vma_resource |
| 163 | *i915_vma_resource_get(struct i915_vma_resource *vma_res) |
| 164 | { |
| 165 | dma_fence_get(fence: &vma_res->unbind_fence); |
| 166 | return vma_res; |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * i915_vma_resource_put - Release a reference to a struct i915_vma_resource |
| 171 | * @vma_res: The resource |
| 172 | */ |
| 173 | static inline void i915_vma_resource_put(struct i915_vma_resource *vma_res) |
| 174 | { |
| 175 | dma_fence_put(fence: &vma_res->unbind_fence); |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | * i915_vma_resource_init - Initialize a vma resource. |
| 180 | * @vma_res: The vma resource to initialize |
| 181 | * @vm: Pointer to the vm. |
| 182 | * @pages: The pages sg-table. |
| 183 | * @page_sizes: Page sizes of the pages. |
| 184 | * @pages_rsgt: Pointer to a struct i915_refct_sgt of an object with |
| 185 | * delayed destruction. |
| 186 | * @readonly: Whether the vma should be bound read-only. |
| 187 | * @lmem: Whether the vma points to lmem. |
| 188 | * @mr: The memory region of the object the vma points to. |
| 189 | * @ops: The backend ops. |
| 190 | * @private: Bind backend private info. |
| 191 | * @start: Offset into the address space of bind range start after padding. |
| 192 | * @node_size: Size of the allocated range manager node minus padding. |
| 193 | * @size: Bind size. |
| 194 | * @guard: The size of the guard area preceding and trailing the bind. |
| 195 | * |
| 196 | * Initializes a vma resource allocated using i915_vma_resource_alloc(). |
| 197 | * The reason for having separate allocate and initialize function is that |
| 198 | * initialization may need to be performed from under a lock where |
| 199 | * allocation is not allowed. |
| 200 | */ |
| 201 | static inline void i915_vma_resource_init(struct i915_vma_resource *vma_res, |
| 202 | struct i915_address_space *vm, |
| 203 | struct sg_table *pages, |
| 204 | const struct i915_page_sizes *page_sizes, |
| 205 | struct i915_refct_sgt *pages_rsgt, |
| 206 | bool readonly, |
| 207 | bool lmem, |
| 208 | struct intel_memory_region *mr, |
| 209 | const struct i915_vma_ops *ops, |
| 210 | void *private, |
| 211 | u64 start, |
| 212 | u64 node_size, |
| 213 | u64 size, |
| 214 | u32 guard) |
| 215 | { |
| 216 | __i915_vma_resource_init(vma_res); |
| 217 | vma_res->vm = vm; |
| 218 | vma_res->bi.pages = pages; |
| 219 | vma_res->bi.page_sizes = *page_sizes; |
| 220 | if (pages_rsgt) |
| 221 | vma_res->bi.pages_rsgt = i915_refct_sgt_get(rsgt: pages_rsgt); |
| 222 | vma_res->bi.readonly = readonly; |
| 223 | vma_res->bi.lmem = lmem; |
| 224 | #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| 225 | vma_res->mr = mr; |
| 226 | #endif |
| 227 | vma_res->ops = ops; |
| 228 | vma_res->private = private; |
| 229 | vma_res->start = start; |
| 230 | vma_res->node_size = node_size; |
| 231 | vma_res->vma_size = size; |
| 232 | vma_res->guard = guard; |
| 233 | } |
| 234 | |
| 235 | static inline void i915_vma_resource_fini(struct i915_vma_resource *vma_res) |
| 236 | { |
| 237 | GEM_BUG_ON(refcount_read(&vma_res->hold_count) != 1); |
| 238 | if (vma_res->bi.pages_rsgt) |
| 239 | i915_refct_sgt_put(rsgt: vma_res->bi.pages_rsgt); |
| 240 | i915_sw_fence_fini(fence: &vma_res->chain); |
| 241 | } |
| 242 | |
| 243 | int i915_vma_resource_bind_dep_sync(struct i915_address_space *vm, |
| 244 | u64 first, |
| 245 | u64 last, |
| 246 | bool intr); |
| 247 | |
| 248 | int i915_vma_resource_bind_dep_await(struct i915_address_space *vm, |
| 249 | struct i915_sw_fence *sw_fence, |
| 250 | u64 first, |
| 251 | u64 last, |
| 252 | bool intr, |
| 253 | gfp_t gfp); |
| 254 | |
| 255 | void i915_vma_resource_bind_dep_sync_all(struct i915_address_space *vm); |
| 256 | |
| 257 | void i915_vma_resource_module_exit(void); |
| 258 | |
| 259 | int i915_vma_resource_module_init(void); |
| 260 | |
| 261 | #endif |
| 262 | |