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

drm/i915/gem: Implement a function to process all gem objects of a region

An upcoming common pattern is to traverse the region object list and
perform certain actions on all objects in a region. It's a little tricky
to get the list locking right, in particular since a gem object may
change region unless it's pinned or the object lock is held.

Define a function that does this for us and that takes an argument that
defines the action to be performed on each object.

v3:
- Improve structure documentation a bit (Matthew Auld)

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-3-thomas.hellstrom@linux.intel.com

+107
+70
drivers/gpu/drm/i915/gem/i915_gem_region.c
··· 80 80 i915_gem_object_free(obj); 81 81 return ERR_PTR(err); 82 82 } 83 + 84 + /** 85 + * i915_gem_process_region - Iterate over all objects of a region using ops 86 + * to process and optionally skip objects 87 + * @mr: The memory region 88 + * @apply: ops and private data 89 + * 90 + * This function can be used to iterate over the regions object list, 91 + * checking whether to skip objects, and, if not, lock the objects and 92 + * process them using the supplied ops. Note that this function temporarily 93 + * removes objects from the region list while iterating, so that if run 94 + * concurrently with itself may not iterate over all objects. 95 + * 96 + * Return: 0 if successful, negative error code on failure. 97 + */ 98 + int i915_gem_process_region(struct intel_memory_region *mr, 99 + struct i915_gem_apply_to_region *apply) 100 + { 101 + const struct i915_gem_apply_to_region_ops *ops = apply->ops; 102 + struct drm_i915_gem_object *obj; 103 + struct list_head still_in_list; 104 + int ret = 0; 105 + 106 + /* 107 + * In the future, a non-NULL apply->ww could mean the caller is 108 + * already in a locking transaction and provides its own context. 109 + */ 110 + GEM_WARN_ON(apply->ww); 111 + 112 + INIT_LIST_HEAD(&still_in_list); 113 + mutex_lock(&mr->objects.lock); 114 + for (;;) { 115 + struct i915_gem_ww_ctx ww; 116 + 117 + obj = list_first_entry_or_null(&mr->objects.list, typeof(*obj), 118 + mm.region_link); 119 + if (!obj) 120 + break; 121 + 122 + list_move_tail(&obj->mm.region_link, &still_in_list); 123 + if (!kref_get_unless_zero(&obj->base.refcount)) 124 + continue; 125 + 126 + /* 127 + * Note: Someone else might be migrating the object at this 128 + * point. The object's region is not stable until we lock 129 + * the object. 130 + */ 131 + mutex_unlock(&mr->objects.lock); 132 + apply->ww = &ww; 133 + for_i915_gem_ww(&ww, ret, apply->interruptible) { 134 + ret = i915_gem_object_lock(obj, apply->ww); 135 + if (ret) 136 + continue; 137 + 138 + if (obj->mm.region == mr) 139 + ret = ops->process_obj(apply, obj); 140 + /* Implicit object unlock */ 141 + } 142 + 143 + i915_gem_object_put(obj); 144 + mutex_lock(&mr->objects.lock); 145 + if (ret) 146 + break; 147 + } 148 + list_splice_tail(&still_in_list, &mr->objects.list); 149 + mutex_unlock(&mr->objects.lock); 150 + 151 + return ret; 152 + }
+37
drivers/gpu/drm/i915/gem/i915_gem_region.h
··· 12 12 struct drm_i915_gem_object; 13 13 struct sg_table; 14 14 15 + struct i915_gem_apply_to_region; 16 + 17 + /** 18 + * struct i915_gem_apply_to_region_ops - ops to use when iterating over all 19 + * region objects. 20 + */ 21 + struct i915_gem_apply_to_region_ops { 22 + /** 23 + * process_obj - Process the current object 24 + * @apply: Embed this for private data. 25 + * @obj: The current object. 26 + * 27 + * Note that if this function is part of a ww transaction, and 28 + * if returns -EDEADLK for one of the objects, it may be 29 + * rerun for that same object in the same pass. 30 + */ 31 + int (*process_obj)(struct i915_gem_apply_to_region *apply, 32 + struct drm_i915_gem_object *obj); 33 + }; 34 + 35 + /** 36 + * struct i915_gem_apply_to_region - Argument to the struct 37 + * i915_gem_apply_to_region_ops functions. 38 + * @ops: The ops for the operation. 39 + * @ww: Locking context used for the transaction. 40 + * @interruptible: Whether to perform object locking interruptible. 41 + * 42 + * This structure is intended to be embedded in a private struct if needed 43 + */ 44 + struct i915_gem_apply_to_region { 45 + const struct i915_gem_apply_to_region_ops *ops; 46 + struct i915_gem_ww_ctx *ww; 47 + u32 interruptible:1; 48 + }; 49 + 15 50 void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj, 16 51 struct intel_memory_region *mem); 17 52 void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj); ··· 57 22 resource_size_t page_size, 58 23 unsigned int flags); 59 24 25 + int i915_gem_process_region(struct intel_memory_region *mr, 26 + struct i915_gem_apply_to_region *apply); 60 27 #endif