| /* SPDX-License-Identifier: MIT */ |
| /* |
| * Copyright © 2021 Intel Corporation |
| */ |
| |
| #ifndef __I915_VMA_RESOURCE_H__ |
| #define __I915_VMA_RESOURCE_H__ |
| |
| #include <linux/dma-fence.h> |
| #include <linux/refcount.h> |
| |
| #include "i915_gem.h" |
| #include "i915_scatterlist.h" |
| #include "i915_sw_fence.h" |
| #include "intel_runtime_pm.h" |
| |
| struct intel_memory_region; |
| |
| struct i915_page_sizes { |
| /** |
| * The sg mask of the pages sg_table. i.e the mask of |
| * the lengths for each sg entry. |
| */ |
| unsigned int phys; |
| |
| /** |
| * The gtt page sizes we are allowed to use given the |
| * sg mask and the supported page sizes. This will |
| * express the smallest unit we can use for the whole |
| * object, as well as the larger sizes we may be able |
| * to use opportunistically. |
| */ |
| unsigned int sg; |
| }; |
| |
| /** |
| * struct i915_vma_bindinfo - Information needed for async bind |
| * only but that can be dropped after the bind has taken place. |
| * Consider making this a separate argument to the bind_vma |
| * op, coalescing with other arguments like vm, stash, cache_level |
| * and flags |
| * @pages: The pages sg-table. |
| * @page_sizes: Page sizes of the pages. |
| * @pages_rsgt: Refcounted sg-table when delayed object destruction |
| * is supported. May be NULL. |
| * @readonly: Whether the vma should be bound read-only. |
| * @lmem: Whether the vma points to lmem. |
| */ |
| struct i915_vma_bindinfo { |
| struct sg_table *pages; |
| struct i915_page_sizes page_sizes; |
| struct i915_refct_sgt *pages_rsgt; |
| bool readonly:1; |
| bool lmem:1; |
| }; |
| |
| /** |
| * struct i915_vma_resource - Snapshotted unbind information. |
| * @unbind_fence: Fence to mark unbinding complete. Note that this fence |
| * is not considered published until unbind is scheduled, and as such it |
| * is illegal to access this fence before scheduled unbind other than |
| * for refcounting. |
| * @lock: The @unbind_fence lock. |
| * @hold_count: Number of holders blocking the fence from finishing. |
| * The vma itself is keeping a hold, which is released when unbind |
| * is scheduled. |
| * @work: Work struct for deferred unbind work. |
| * @chain: Pointer to struct i915_sw_fence used to await dependencies. |
| * @rb: Rb node for the vm's pending unbind interval tree. |
| * @__subtree_last: Interval tree private member. |
| * @wakeref: wakeref. |
| * @vm: non-refcounted pointer to the vm. This is for internal use only and |
| * this member is cleared after vm_resource unbind. |
| * @mr: The memory region of the object pointed to by the vma. |
| * @ops: Pointer to the backend i915_vma_ops. |
| * @private: Bind backend private info. |
| * @start: Offset into the address space of bind range start. Note that |
| * this is after any padding that might have been allocated. |
| * @node_size: Size of the allocated range manager node with padding |
| * subtracted. |
| * @vma_size: Bind size. |
| * @guard: The size of guard area preceding and trailing the bind. |
| * @page_sizes_gtt: Resulting page sizes from the bind operation. |
| * @bound_flags: Flags indicating binding status. |
| * @allocated: Backend private data. TODO: Should move into @private. |
| * @immediate_unbind: Unbind can be done immediately and doesn't need to be |
| * deferred to a work item awaiting unsignaled fences. This is a hack. |
| * (dma_fence_work uses a fence flag for this, but this seems slightly |
| * cleaner). |
| * @needs_wakeref: Whether a wakeref is needed during unbind. Since we can't |
| * take a wakeref in the dma-fence signalling critical path, it needs to be |
| * taken when the unbind is scheduled. |
| * @skip_pte_rewrite: During ggtt suspend and vm takedown pte rewriting |
| * needs to be skipped for unbind. |
| * @tlb: pointer for obj->mm.tlb, if async unbind. Otherwise, NULL |
| * |
| * The lifetime of a struct i915_vma_resource is from a binding request to |
| * the actual possible asynchronous unbind has completed. |
| */ |
| struct i915_vma_resource { |
| struct dma_fence unbind_fence; |
| /* See above for description of the lock. */ |
| spinlock_t lock; |
| refcount_t hold_count; |
| struct work_struct work; |
| struct i915_sw_fence chain; |
| struct rb_node rb; |
| u64 __subtree_last; |
| struct i915_address_space *vm; |
| intel_wakeref_t wakeref; |
| |
| /** |
| * @bi: Information needed for async bind only but that can be dropped |
| * after the bind has taken place. |
| * |
| * Consider making this a separate argument to the bind_vma op, |
| * coalescing with other arguments like vm, stash, cache_level and flags |
| */ |
| struct i915_vma_bindinfo bi; |
| |
| #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| struct intel_memory_region *mr; |
| #endif |
| const struct i915_vma_ops *ops; |
| void *private; |
| u64 start; |
| u64 node_size; |
| u64 vma_size; |
| u32 guard; |
| u32 page_sizes_gtt; |
| |
| u32 bound_flags; |
| bool allocated:1; |
| bool immediate_unbind:1; |
| bool needs_wakeref:1; |
| bool skip_pte_rewrite:1; |
| |
| u32 *tlb; |
| }; |
| |
| bool i915_vma_resource_hold(struct i915_vma_resource *vma_res, |
| bool *lockdep_cookie); |
| |
| void i915_vma_resource_unhold(struct i915_vma_resource *vma_res, |
| bool lockdep_cookie); |
| |
| struct i915_vma_resource *i915_vma_resource_alloc(void); |
| |
| void i915_vma_resource_free(struct i915_vma_resource *vma_res); |
| |
| struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res, |
| u32 *tlb); |
| |
| void __i915_vma_resource_init(struct i915_vma_resource *vma_res); |
| |
| /** |
| * i915_vma_resource_get - Take a reference on a vma resource |
| * @vma_res: The vma resource on which to take a reference. |
| * |
| * Return: The @vma_res pointer |
| */ |
| static inline struct i915_vma_resource |
| *i915_vma_resource_get(struct i915_vma_resource *vma_res) |
| { |
| dma_fence_get(&vma_res->unbind_fence); |
| return vma_res; |
| } |
| |
| /** |
| * i915_vma_resource_put - Release a reference to a struct i915_vma_resource |
| * @vma_res: The resource |
| */ |
| static inline void i915_vma_resource_put(struct i915_vma_resource *vma_res) |
| { |
| dma_fence_put(&vma_res->unbind_fence); |
| } |
| |
| /** |
| * i915_vma_resource_init - Initialize a vma resource. |
| * @vma_res: The vma resource to initialize |
| * @vm: Pointer to the vm. |
| * @pages: The pages sg-table. |
| * @page_sizes: Page sizes of the pages. |
| * @pages_rsgt: Pointer to a struct i915_refct_sgt of an object with |
| * delayed destruction. |
| * @readonly: Whether the vma should be bound read-only. |
| * @lmem: Whether the vma points to lmem. |
| * @mr: The memory region of the object the vma points to. |
| * @ops: The backend ops. |
| * @private: Bind backend private info. |
| * @start: Offset into the address space of bind range start after padding. |
| * @node_size: Size of the allocated range manager node minus padding. |
| * @size: Bind size. |
| * @guard: The size of the guard area preceding and trailing the bind. |
| * |
| * Initializes a vma resource allocated using i915_vma_resource_alloc(). |
| * The reason for having separate allocate and initialize function is that |
| * initialization may need to be performed from under a lock where |
| * allocation is not allowed. |
| */ |
| static inline void i915_vma_resource_init(struct i915_vma_resource *vma_res, |
| struct i915_address_space *vm, |
| struct sg_table *pages, |
| const struct i915_page_sizes *page_sizes, |
| struct i915_refct_sgt *pages_rsgt, |
| bool readonly, |
| bool lmem, |
| struct intel_memory_region *mr, |
| const struct i915_vma_ops *ops, |
| void *private, |
| u64 start, |
| u64 node_size, |
| u64 size, |
| u32 guard) |
| { |
| __i915_vma_resource_init(vma_res); |
| vma_res->vm = vm; |
| vma_res->bi.pages = pages; |
| vma_res->bi.page_sizes = *page_sizes; |
| if (pages_rsgt) |
| vma_res->bi.pages_rsgt = i915_refct_sgt_get(pages_rsgt); |
| vma_res->bi.readonly = readonly; |
| vma_res->bi.lmem = lmem; |
| #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| vma_res->mr = mr; |
| #endif |
| vma_res->ops = ops; |
| vma_res->private = private; |
| vma_res->start = start; |
| vma_res->node_size = node_size; |
| vma_res->vma_size = size; |
| vma_res->guard = guard; |
| } |
| |
| static inline void i915_vma_resource_fini(struct i915_vma_resource *vma_res) |
| { |
| GEM_BUG_ON(refcount_read(&vma_res->hold_count) != 1); |
| if (vma_res->bi.pages_rsgt) |
| i915_refct_sgt_put(vma_res->bi.pages_rsgt); |
| i915_sw_fence_fini(&vma_res->chain); |
| } |
| |
| int i915_vma_resource_bind_dep_sync(struct i915_address_space *vm, |
| u64 first, |
| u64 last, |
| bool intr); |
| |
| int i915_vma_resource_bind_dep_await(struct i915_address_space *vm, |
| struct i915_sw_fence *sw_fence, |
| u64 first, |
| u64 last, |
| bool intr, |
| gfp_t gfp); |
| |
| void i915_vma_resource_bind_dep_sync_all(struct i915_address_space *vm); |
| |
| void i915_vma_resource_module_exit(void); |
| |
| int i915_vma_resource_module_init(void); |
| |
| #endif |