1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2020 Intel Corporation 4 */ 5 6 #include <linux/string.h> 7 8 #include "i915_drv.h" 9 #include "intel_atomic.h" 10 #include "intel_display_types.h" 11 #include "intel_global_state.h" 12 13 static void __intel_atomic_global_state_free(struct kref *kref) 14 { 15 struct intel_global_state *obj_state = 16 container_of(kref, struct intel_global_state, ref); 17 struct intel_global_obj *obj = obj_state->obj; 18 19 obj->funcs->atomic_destroy_state(obj, obj_state); 20 } 21 22 static void intel_atomic_global_state_put(struct intel_global_state *obj_state) 23 { 24 kref_put(&obj_state->ref, __intel_atomic_global_state_free); 25 } 26 27 static struct intel_global_state * 28 intel_atomic_global_state_get(struct intel_global_state *obj_state) 29 { 30 kref_get(&obj_state->ref); 31 32 return obj_state; 33 } 34 35 void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv, 36 struct intel_global_obj *obj, 37 struct intel_global_state *state, 38 const struct intel_global_state_funcs *funcs) 39 { 40 memset(obj, 0, sizeof(*obj)); 41 42 state->obj = obj; 43 44 kref_init(&state->ref); 45 46 obj->state = state; 47 obj->funcs = funcs; 48 list_add_tail(&obj->head, &dev_priv->global_obj_list); 49 } 50 51 void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv) 52 { 53 struct intel_global_obj *obj, *next; 54 55 list_for_each_entry_safe(obj, next, &dev_priv->global_obj_list, head) { 56 list_del(&obj->head); 57 58 drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1); 59 intel_atomic_global_state_put(obj->state); 60 } 61 } 62 63 static void assert_global_state_write_locked(struct drm_i915_private *dev_priv) 64 { 65 struct intel_crtc *crtc; 66 67 for_each_intel_crtc(&dev_priv->drm, crtc) 68 drm_modeset_lock_assert_held(&crtc->base.mutex); 69 } 70 71 static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx, 72 struct drm_modeset_lock *lock) 73 { 74 struct drm_modeset_lock *l; 75 76 list_for_each_entry(l, &ctx->locked, head) { 77 if (lock == l) 78 return true; 79 } 80 81 return false; 82 } 83 84 static void assert_global_state_read_locked(struct intel_atomic_state *state) 85 { 86 struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx; 87 struct drm_i915_private *dev_priv = to_i915(state->base.dev); 88 struct intel_crtc *crtc; 89 90 for_each_intel_crtc(&dev_priv->drm, crtc) { 91 if (modeset_lock_is_held(ctx, &crtc->base.mutex)) 92 return; 93 } 94 95 drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n"); 96 } 97 98 struct intel_global_state * 99 intel_atomic_get_global_obj_state(struct intel_atomic_state *state, 100 struct intel_global_obj *obj) 101 { 102 struct drm_i915_private *i915 = to_i915(state->base.dev); 103 int index, num_objs, i; 104 size_t size; 105 struct __intel_global_objs_state *arr; 106 struct intel_global_state *obj_state; 107 108 for (i = 0; i < state->num_global_objs; i++) 109 if (obj == state->global_objs[i].ptr) 110 return state->global_objs[i].state; 111 112 assert_global_state_read_locked(state); 113 114 num_objs = state->num_global_objs + 1; 115 size = sizeof(*state->global_objs) * num_objs; 116 #ifdef __linux__ 117 arr = krealloc(state->global_objs, size, GFP_KERNEL); 118 if (!arr) 119 return ERR_PTR(-ENOMEM); 120 #else 121 arr = kmalloc(size, GFP_KERNEL); 122 if (!arr) 123 return ERR_PTR(-ENOMEM); 124 memcpy(arr, state->global_objs, 125 sizeof(*state->global_objs) * state->num_global_objs); 126 kfree(state->global_objs); 127 #endif 128 129 state->global_objs = arr; 130 index = state->num_global_objs; 131 memset(&state->global_objs[index], 0, sizeof(*state->global_objs)); 132 133 obj_state = obj->funcs->atomic_duplicate_state(obj); 134 if (!obj_state) 135 return ERR_PTR(-ENOMEM); 136 137 obj_state->obj = obj; 138 obj_state->changed = false; 139 140 kref_init(&obj_state->ref); 141 142 state->global_objs[index].state = obj_state; 143 state->global_objs[index].old_state = 144 intel_atomic_global_state_get(obj->state); 145 state->global_objs[index].new_state = obj_state; 146 state->global_objs[index].ptr = obj; 147 obj_state->state = state; 148 149 state->num_global_objs = num_objs; 150 151 drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n", 152 obj, obj_state, state); 153 154 return obj_state; 155 } 156 157 struct intel_global_state * 158 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state, 159 struct intel_global_obj *obj) 160 { 161 int i; 162 163 for (i = 0; i < state->num_global_objs; i++) 164 if (obj == state->global_objs[i].ptr) 165 return state->global_objs[i].old_state; 166 167 return NULL; 168 } 169 170 struct intel_global_state * 171 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state, 172 struct intel_global_obj *obj) 173 { 174 int i; 175 176 for (i = 0; i < state->num_global_objs; i++) 177 if (obj == state->global_objs[i].ptr) 178 return state->global_objs[i].new_state; 179 180 return NULL; 181 } 182 183 void intel_atomic_swap_global_state(struct intel_atomic_state *state) 184 { 185 struct drm_i915_private *dev_priv = to_i915(state->base.dev); 186 struct intel_global_state *old_obj_state, *new_obj_state; 187 struct intel_global_obj *obj; 188 int i; 189 190 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state, 191 new_obj_state, i) { 192 drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state); 193 194 /* 195 * If the new state wasn't modified (and properly 196 * locked for write access) we throw it away. 197 */ 198 if (!new_obj_state->changed) 199 continue; 200 201 assert_global_state_write_locked(dev_priv); 202 203 old_obj_state->state = state; 204 new_obj_state->state = NULL; 205 206 state->global_objs[i].state = old_obj_state; 207 208 intel_atomic_global_state_put(obj->state); 209 obj->state = intel_atomic_global_state_get(new_obj_state); 210 } 211 } 212 213 void intel_atomic_clear_global_state(struct intel_atomic_state *state) 214 { 215 int i; 216 217 for (i = 0; i < state->num_global_objs; i++) { 218 intel_atomic_global_state_put(state->global_objs[i].old_state); 219 intel_atomic_global_state_put(state->global_objs[i].new_state); 220 221 state->global_objs[i].ptr = NULL; 222 state->global_objs[i].state = NULL; 223 state->global_objs[i].old_state = NULL; 224 state->global_objs[i].new_state = NULL; 225 } 226 state->num_global_objs = 0; 227 } 228 229 int intel_atomic_lock_global_state(struct intel_global_state *obj_state) 230 { 231 struct intel_atomic_state *state = obj_state->state; 232 struct drm_i915_private *dev_priv = to_i915(state->base.dev); 233 struct intel_crtc *crtc; 234 235 for_each_intel_crtc(&dev_priv->drm, crtc) { 236 int ret; 237 238 ret = drm_modeset_lock(&crtc->base.mutex, 239 state->base.acquire_ctx); 240 if (ret) 241 return ret; 242 } 243 244 obj_state->changed = true; 245 246 return 0; 247 } 248 249 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state) 250 { 251 struct intel_atomic_state *state = obj_state->state; 252 struct drm_i915_private *dev_priv = to_i915(state->base.dev); 253 struct intel_crtc *crtc; 254 255 for_each_intel_crtc(&dev_priv->drm, crtc) { 256 struct intel_crtc_state *crtc_state; 257 258 crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); 259 if (IS_ERR(crtc_state)) 260 return PTR_ERR(crtc_state); 261 } 262 263 obj_state->changed = true; 264 265 return 0; 266 } 267