xref: /linux/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.c (revision 13c072b8e91a5ccb5855ca1ba6fe3ea467dbf94d)
1 // SPDX-License-Identifier: MIT
2 /* Copyright © 2025 Intel Corporation */
3 
4 #include <drm/intel/display_parent_interface.h>
5 
6 #include "i915_drv.h"
7 #include "i915_gem_object_frontbuffer.h"
8 
9 static int frontbuffer_active(struct i915_active *ref)
10 {
11 	struct i915_frontbuffer *front =
12 		container_of(ref, typeof(*front), write);
13 
14 	kref_get(&front->ref);
15 	return 0;
16 }
17 
18 static void frontbuffer_retire(struct i915_active *ref)
19 {
20 	struct i915_frontbuffer *front =
21 		container_of(ref, typeof(*front), write);
22 
23 	intel_frontbuffer_flush(&front->base, ORIGIN_CS);
24 	i915_gem_object_frontbuffer_put(front);
25 }
26 
27 struct i915_frontbuffer *
28 i915_gem_object_frontbuffer_get(struct drm_i915_gem_object *obj)
29 {
30 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
31 	struct i915_frontbuffer *front, *cur;
32 
33 	front = i915_gem_object_frontbuffer_lookup(obj);
34 	if (front)
35 		return front;
36 
37 	front = kmalloc_obj(*front);
38 	if (!front)
39 		return NULL;
40 
41 	intel_frontbuffer_init(&front->base, &i915->drm);
42 
43 	kref_init(&front->ref);
44 	i915_gem_object_get(obj);
45 	front->obj = obj;
46 
47 	i915_active_init(&front->write,
48 			 frontbuffer_active,
49 			 frontbuffer_retire,
50 			 I915_ACTIVE_RETIRE_SLEEPS);
51 
52 	spin_lock(&i915->frontbuffer_lock);
53 	if (rcu_access_pointer(obj->frontbuffer)) {
54 		cur = rcu_dereference_protected(obj->frontbuffer, true);
55 		kref_get(&cur->ref);
56 	} else {
57 		cur = front;
58 		rcu_assign_pointer(obj->frontbuffer, front);
59 	}
60 	spin_unlock(&i915->frontbuffer_lock);
61 
62 	if (cur != front) {
63 		i915_gem_object_put(obj);
64 		intel_frontbuffer_fini(&front->base);
65 		kfree(front);
66 	}
67 
68 	return cur;
69 }
70 
71 void i915_gem_object_frontbuffer_ref(struct i915_frontbuffer *front)
72 {
73 	kref_get(&front->ref);
74 }
75 
76 static void frontbuffer_release(struct kref *ref)
77 	__releases(&i915->frontbuffer_lock)
78 {
79 	struct i915_frontbuffer *front =
80 		container_of(ref, typeof(*front), ref);
81 	struct drm_i915_gem_object *obj = front->obj;
82 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
83 
84 	i915_ggtt_clear_scanout(obj);
85 
86 	RCU_INIT_POINTER(obj->frontbuffer, NULL);
87 
88 	spin_unlock(&i915->frontbuffer_lock);
89 
90 	i915_active_fini(&front->write);
91 
92 	i915_gem_object_put(obj);
93 
94 	intel_frontbuffer_fini(&front->base);
95 
96 	kfree_rcu(front, rcu);
97 }
98 
99 void i915_gem_object_frontbuffer_put(struct i915_frontbuffer *front)
100 {
101 	struct drm_i915_private *i915 = to_i915(front->obj->base.dev);
102 
103 	kref_put_lock(&front->ref, frontbuffer_release,
104 		      &i915->frontbuffer_lock);
105 }
106 
107 void __i915_gem_object_frontbuffer_flush(struct drm_i915_gem_object *obj,
108 					 enum fb_op_origin origin)
109 {
110 	struct i915_frontbuffer *front;
111 
112 	front = i915_gem_object_frontbuffer_lookup(obj);
113 	if (front) {
114 		intel_frontbuffer_flush(&front->base, origin);
115 		i915_gem_object_frontbuffer_put(front);
116 	}
117 }
118 
119 void __i915_gem_object_frontbuffer_invalidate(struct drm_i915_gem_object *obj,
120 					      enum fb_op_origin origin)
121 {
122 	struct i915_frontbuffer *front;
123 
124 	front = i915_gem_object_frontbuffer_lookup(obj);
125 	if (front) {
126 		intel_frontbuffer_invalidate(&front->base, origin);
127 		i915_gem_object_frontbuffer_put(front);
128 	}
129 }
130 
131 static struct intel_frontbuffer *i915_frontbuffer_get(struct drm_gem_object *_obj)
132 {
133 	struct drm_i915_gem_object *obj = to_intel_bo(_obj);
134 	struct i915_frontbuffer *front;
135 
136 	front = i915_gem_object_frontbuffer_get(obj);
137 	if (!front)
138 		return NULL;
139 
140 	return &front->base;
141 }
142 
143 static void i915_frontbuffer_ref(struct intel_frontbuffer *_front)
144 {
145 	struct i915_frontbuffer *front =
146 		container_of(_front, typeof(*front), base);
147 
148 	i915_gem_object_frontbuffer_ref(front);
149 }
150 
151 static void i915_frontbuffer_put(struct intel_frontbuffer *_front)
152 {
153 	struct i915_frontbuffer *front =
154 		container_of(_front, typeof(*front), base);
155 
156 	return i915_gem_object_frontbuffer_put(front);
157 }
158 
159 static void i915_frontbuffer_flush_for_display(struct intel_frontbuffer *_front)
160 {
161 	struct i915_frontbuffer *front =
162 		container_of(_front, typeof(*front), base);
163 
164 	i915_gem_object_flush_if_display(front->obj);
165 }
166 
167 const struct intel_display_frontbuffer_interface i915_display_frontbuffer_interface = {
168 	.get = i915_frontbuffer_get,
169 	.ref = i915_frontbuffer_ref,
170 	.put = i915_frontbuffer_put,
171 	.flush_for_display = i915_frontbuffer_flush_for_display,
172 };
173