xref: /linux/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1 // SPDX-License-Identifier: MIT
2 /* Copyright © 2025 Intel Corporation */
3 
4 #include "i915_drv.h"
5 #include "i915_gem_object_frontbuffer.h"
6 
7 static int frontbuffer_active(struct i915_active *ref)
8 {
9 	struct i915_frontbuffer *front =
10 		container_of(ref, typeof(*front), write);
11 
12 	kref_get(&front->ref);
13 	return 0;
14 }
15 
16 static void frontbuffer_retire(struct i915_active *ref)
17 {
18 	struct i915_frontbuffer *front =
19 		container_of(ref, typeof(*front), write);
20 
21 	intel_frontbuffer_flush(&front->base, ORIGIN_CS);
22 	i915_gem_object_frontbuffer_put(front);
23 }
24 
25 struct i915_frontbuffer *
26 i915_gem_object_frontbuffer_get(struct drm_i915_gem_object *obj)
27 {
28 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
29 	struct i915_frontbuffer *front, *cur;
30 
31 	front = i915_gem_object_frontbuffer_lookup(obj);
32 	if (front)
33 		return front;
34 
35 	front = kmalloc(sizeof(*front), GFP_KERNEL);
36 	if (!front)
37 		return NULL;
38 
39 	intel_frontbuffer_init(&front->base, &i915->drm);
40 
41 	kref_init(&front->ref);
42 	i915_gem_object_get(obj);
43 	front->obj = obj;
44 
45 	i915_active_init(&front->write,
46 			 frontbuffer_active,
47 			 frontbuffer_retire,
48 			 I915_ACTIVE_RETIRE_SLEEPS);
49 
50 	spin_lock(&i915->frontbuffer_lock);
51 	if (rcu_access_pointer(obj->frontbuffer)) {
52 		cur = rcu_dereference_protected(obj->frontbuffer, true);
53 		kref_get(&cur->ref);
54 	} else {
55 		cur = front;
56 		rcu_assign_pointer(obj->frontbuffer, front);
57 	}
58 	spin_unlock(&i915->frontbuffer_lock);
59 
60 	if (cur != front) {
61 		i915_gem_object_put(obj);
62 		intel_frontbuffer_fini(&front->base);
63 		kfree(front);
64 	}
65 
66 	return cur;
67 }
68 
69 void i915_gem_object_frontbuffer_ref(struct i915_frontbuffer *front)
70 {
71 	kref_get(&front->ref);
72 }
73 
74 static void frontbuffer_release(struct kref *ref)
75 	__releases(&i915->frontbuffer_lock)
76 {
77 	struct i915_frontbuffer *front =
78 		container_of(ref, typeof(*front), ref);
79 	struct drm_i915_gem_object *obj = front->obj;
80 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
81 
82 	i915_ggtt_clear_scanout(obj);
83 
84 	RCU_INIT_POINTER(obj->frontbuffer, NULL);
85 
86 	spin_unlock(&i915->frontbuffer_lock);
87 
88 	i915_active_fini(&front->write);
89 
90 	i915_gem_object_put(obj);
91 
92 	intel_frontbuffer_fini(&front->base);
93 
94 	kfree_rcu(front, rcu);
95 }
96 
97 void i915_gem_object_frontbuffer_put(struct i915_frontbuffer *front)
98 {
99 	struct drm_i915_private *i915 = to_i915(front->obj->base.dev);
100 
101 	kref_put_lock(&front->ref, frontbuffer_release,
102 		      &i915->frontbuffer_lock);
103 }
104