| // SPDX-License-Identifier: MIT |
| /* Copyright © 2025 Intel Corporation */ |
| |
| #include "i915_drv.h" |
| #include "i915_gem_object_frontbuffer.h" |
| |
| static int frontbuffer_active(struct i915_active *ref) |
| { |
| struct i915_frontbuffer *front = |
| container_of(ref, typeof(*front), write); |
| |
| kref_get(&front->ref); |
| return 0; |
| } |
| |
| static void frontbuffer_retire(struct i915_active *ref) |
| { |
| struct i915_frontbuffer *front = |
| container_of(ref, typeof(*front), write); |
| |
| intel_frontbuffer_flush(&front->base, ORIGIN_CS); |
| i915_gem_object_frontbuffer_put(front); |
| } |
| |
| struct i915_frontbuffer * |
| i915_gem_object_frontbuffer_get(struct drm_i915_gem_object *obj) |
| { |
| struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| struct i915_frontbuffer *front, *cur; |
| |
| front = i915_gem_object_frontbuffer_lookup(obj); |
| if (front) |
| return front; |
| |
| front = kmalloc(sizeof(*front), GFP_KERNEL); |
| if (!front) |
| return NULL; |
| |
| intel_frontbuffer_init(&front->base, &i915->drm); |
| |
| kref_init(&front->ref); |
| i915_gem_object_get(obj); |
| front->obj = obj; |
| |
| i915_active_init(&front->write, |
| frontbuffer_active, |
| frontbuffer_retire, |
| I915_ACTIVE_RETIRE_SLEEPS); |
| |
| spin_lock(&i915->frontbuffer_lock); |
| if (rcu_access_pointer(obj->frontbuffer)) { |
| cur = rcu_dereference_protected(obj->frontbuffer, true); |
| kref_get(&cur->ref); |
| } else { |
| cur = front; |
| rcu_assign_pointer(obj->frontbuffer, front); |
| } |
| spin_unlock(&i915->frontbuffer_lock); |
| |
| if (cur != front) { |
| i915_gem_object_put(obj); |
| intel_frontbuffer_fini(&front->base); |
| kfree(front); |
| } |
| |
| return cur; |
| } |
| |
| void i915_gem_object_frontbuffer_ref(struct i915_frontbuffer *front) |
| { |
| kref_get(&front->ref); |
| } |
| |
| static void frontbuffer_release(struct kref *ref) |
| __releases(&i915->frontbuffer_lock) |
| { |
| struct i915_frontbuffer *front = |
| container_of(ref, typeof(*front), ref); |
| struct drm_i915_gem_object *obj = front->obj; |
| struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| |
| i915_ggtt_clear_scanout(obj); |
| |
| RCU_INIT_POINTER(obj->frontbuffer, NULL); |
| |
| spin_unlock(&i915->frontbuffer_lock); |
| |
| i915_active_fini(&front->write); |
| |
| i915_gem_object_put(obj); |
| |
| intel_frontbuffer_fini(&front->base); |
| |
| kfree_rcu(front, rcu); |
| } |
| |
| void i915_gem_object_frontbuffer_put(struct i915_frontbuffer *front) |
| { |
| struct drm_i915_private *i915 = to_i915(front->obj->base.dev); |
| |
| kref_put_lock(&front->ref, frontbuffer_release, |
| &i915->frontbuffer_lock); |
| } |