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