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