Commit d80ee88e authored by Thomas Hellström's avatar Thomas Hellström
Browse files

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: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: default avatarMatthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-3-thomas.hellstrom@linux.intel.com
parent 0d938863
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -80,3 +80,73 @@ i915_gem_object_create_region(struct intel_memory_region *mem,
	i915_gem_object_free(obj);
	return ERR_PTR(err);
}

/**
 * i915_gem_process_region - Iterate over all objects of a region using ops
 * to process and optionally skip objects
 * @mr: The memory region
 * @apply: ops and private data
 *
 * This function can be used to iterate over the regions object list,
 * checking whether to skip objects, and, if not, lock the objects and
 * process them using the supplied ops. Note that this function temporarily
 * removes objects from the region list while iterating, so that if run
 * concurrently with itself may not iterate over all objects.
 *
 * Return: 0 if successful, negative error code on failure.
 */
int i915_gem_process_region(struct intel_memory_region *mr,
			    struct i915_gem_apply_to_region *apply)
{
	const struct i915_gem_apply_to_region_ops *ops = apply->ops;
	struct drm_i915_gem_object *obj;
	struct list_head still_in_list;
	int ret = 0;

	/*
	 * In the future, a non-NULL apply->ww could mean the caller is
	 * already in a locking transaction and provides its own context.
	 */
	GEM_WARN_ON(apply->ww);

	INIT_LIST_HEAD(&still_in_list);
	mutex_lock(&mr->objects.lock);
	for (;;) {
		struct i915_gem_ww_ctx ww;

		obj = list_first_entry_or_null(&mr->objects.list, typeof(*obj),
					       mm.region_link);
		if (!obj)
			break;

		list_move_tail(&obj->mm.region_link, &still_in_list);
		if (!kref_get_unless_zero(&obj->base.refcount))
			continue;

		/*
		 * Note: Someone else might be migrating the object at this
		 * point. The object's region is not stable until we lock
		 * the object.
		 */
		mutex_unlock(&mr->objects.lock);
		apply->ww = &ww;
		for_i915_gem_ww(&ww, ret, apply->interruptible) {
			ret = i915_gem_object_lock(obj, apply->ww);
			if (ret)
				continue;

			if (obj->mm.region == mr)
				ret = ops->process_obj(apply, obj);
			/* Implicit object unlock */
		}

		i915_gem_object_put(obj);
		mutex_lock(&mr->objects.lock);
		if (ret)
			break;
	}
	list_splice_tail(&still_in_list, &mr->objects.list);
	mutex_unlock(&mr->objects.lock);

	return ret;
}
+37 −0
Original line number Diff line number Diff line
@@ -12,6 +12,41 @@ struct intel_memory_region;
struct drm_i915_gem_object;
struct sg_table;

struct i915_gem_apply_to_region;

/**
 * struct i915_gem_apply_to_region_ops - ops to use when iterating over all
 * region objects.
 */
struct i915_gem_apply_to_region_ops {
	/**
	 * process_obj - Process the current object
	 * @apply: Embed this for private data.
	 * @obj: The current object.
	 *
	 * Note that if this function is part of a ww transaction, and
	 * if returns -EDEADLK for one of the objects, it may be
	 * rerun for that same object in the same pass.
	 */
	int (*process_obj)(struct i915_gem_apply_to_region *apply,
			   struct drm_i915_gem_object *obj);
};

/**
 * struct i915_gem_apply_to_region - Argument to the struct
 * i915_gem_apply_to_region_ops functions.
 * @ops: The ops for the operation.
 * @ww: Locking context used for the transaction.
 * @interruptible: Whether to perform object locking interruptible.
 *
 * This structure is intended to be embedded in a private struct if needed
 */
struct i915_gem_apply_to_region {
	const struct i915_gem_apply_to_region_ops *ops;
	struct i915_gem_ww_ctx *ww;
	u32 interruptible:1;
};

void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
					struct intel_memory_region *mem);
void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj);
@@ -22,4 +57,6 @@ i915_gem_object_create_region(struct intel_memory_region *mem,
			      resource_size_t page_size,
			      unsigned int flags);

int i915_gem_process_region(struct intel_memory_region *mr,
			    struct i915_gem_apply_to_region *apply);
#endif