brintos

brintos / linux-shallow public Read only

0
0
Text · 9.0 KiB · cbcd1e9 Raw
385 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2020 Intel Corporation4 */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 13struct intel_global_commit {14	struct kref ref;15	struct completion done;16};17 18static struct intel_global_commit *commit_new(void)19{20	struct intel_global_commit *commit;21 22	commit = kzalloc(sizeof(*commit), GFP_KERNEL);23	if (!commit)24		return NULL;25 26	init_completion(&commit->done);27	kref_init(&commit->ref);28 29	return commit;30}31 32static void __commit_free(struct kref *kref)33{34	struct intel_global_commit *commit =35		container_of(kref, typeof(*commit), ref);36 37	kfree(commit);38}39 40static struct intel_global_commit *commit_get(struct intel_global_commit *commit)41{42	if (commit)43		kref_get(&commit->ref);44 45	return commit;46}47 48static void commit_put(struct intel_global_commit *commit)49{50	if (commit)51		kref_put(&commit->ref, __commit_free);52}53 54static void __intel_atomic_global_state_free(struct kref *kref)55{56	struct intel_global_state *obj_state =57		container_of(kref, struct intel_global_state, ref);58	struct intel_global_obj *obj = obj_state->obj;59 60	commit_put(obj_state->commit);61 62	obj->funcs->atomic_destroy_state(obj, obj_state);63}64 65static void intel_atomic_global_state_put(struct intel_global_state *obj_state)66{67	kref_put(&obj_state->ref, __intel_atomic_global_state_free);68}69 70static struct intel_global_state *71intel_atomic_global_state_get(struct intel_global_state *obj_state)72{73	kref_get(&obj_state->ref);74 75	return obj_state;76}77 78void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,79				  struct intel_global_obj *obj,80				  struct intel_global_state *state,81				  const struct intel_global_state_funcs *funcs)82{83	memset(obj, 0, sizeof(*obj));84 85	state->obj = obj;86 87	kref_init(&state->ref);88 89	obj->state = state;90	obj->funcs = funcs;91	list_add_tail(&obj->head, &dev_priv->display.global.obj_list);92}93 94void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)95{96	struct intel_global_obj *obj, *next;97 98	list_for_each_entry_safe(obj, next, &dev_priv->display.global.obj_list, head) {99		list_del(&obj->head);100 101		drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1);102		intel_atomic_global_state_put(obj->state);103	}104}105 106static void assert_global_state_write_locked(struct drm_i915_private *dev_priv)107{108	struct intel_crtc *crtc;109 110	for_each_intel_crtc(&dev_priv->drm, crtc)111		drm_modeset_lock_assert_held(&crtc->base.mutex);112}113 114static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,115				 struct drm_modeset_lock *lock)116{117	struct drm_modeset_lock *l;118 119	list_for_each_entry(l, &ctx->locked, head) {120		if (lock == l)121			return true;122	}123 124	return false;125}126 127static void assert_global_state_read_locked(struct intel_atomic_state *state)128{129	struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;130	struct drm_i915_private *dev_priv = to_i915(state->base.dev);131	struct intel_crtc *crtc;132 133	for_each_intel_crtc(&dev_priv->drm, crtc) {134		if (modeset_lock_is_held(ctx, &crtc->base.mutex))135			return;136	}137 138	drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n");139}140 141struct intel_global_state *142intel_atomic_get_global_obj_state(struct intel_atomic_state *state,143				  struct intel_global_obj *obj)144{145	struct drm_i915_private *i915 = to_i915(state->base.dev);146	int index, num_objs, i;147	size_t size;148	struct __intel_global_objs_state *arr;149	struct intel_global_state *obj_state;150 151	for (i = 0; i < state->num_global_objs; i++)152		if (obj == state->global_objs[i].ptr)153			return state->global_objs[i].state;154 155	assert_global_state_read_locked(state);156 157	num_objs = state->num_global_objs + 1;158	size = sizeof(*state->global_objs) * num_objs;159	arr = krealloc(state->global_objs, size, GFP_KERNEL);160	if (!arr)161		return ERR_PTR(-ENOMEM);162 163	state->global_objs = arr;164	index = state->num_global_objs;165	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));166 167	obj_state = obj->funcs->atomic_duplicate_state(obj);168	if (!obj_state)169		return ERR_PTR(-ENOMEM);170 171	obj_state->obj = obj;172	obj_state->changed = false;173	obj_state->serialized = false;174	obj_state->commit = NULL;175 176	kref_init(&obj_state->ref);177 178	state->global_objs[index].state = obj_state;179	state->global_objs[index].old_state =180		intel_atomic_global_state_get(obj->state);181	state->global_objs[index].new_state = obj_state;182	state->global_objs[index].ptr = obj;183	obj_state->state = state;184 185	state->num_global_objs = num_objs;186 187	drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n",188		       obj, obj_state, state);189 190	return obj_state;191}192 193struct intel_global_state *194intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,195				      struct intel_global_obj *obj)196{197	int i;198 199	for (i = 0; i < state->num_global_objs; i++)200		if (obj == state->global_objs[i].ptr)201			return state->global_objs[i].old_state;202 203	return NULL;204}205 206struct intel_global_state *207intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,208				      struct intel_global_obj *obj)209{210	int i;211 212	for (i = 0; i < state->num_global_objs; i++)213		if (obj == state->global_objs[i].ptr)214			return state->global_objs[i].new_state;215 216	return NULL;217}218 219void intel_atomic_swap_global_state(struct intel_atomic_state *state)220{221	struct drm_i915_private *dev_priv = to_i915(state->base.dev);222	struct intel_global_state *old_obj_state, *new_obj_state;223	struct intel_global_obj *obj;224	int i;225 226	for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,227					    new_obj_state, i) {228		drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state);229 230		/*231		 * If the new state wasn't modified (and properly232		 * locked for write access) we throw it away.233		 */234		if (!new_obj_state->changed)235			continue;236 237		assert_global_state_write_locked(dev_priv);238 239		old_obj_state->state = state;240		new_obj_state->state = NULL;241 242		state->global_objs[i].state = old_obj_state;243 244		intel_atomic_global_state_put(obj->state);245		obj->state = intel_atomic_global_state_get(new_obj_state);246	}247}248 249void intel_atomic_clear_global_state(struct intel_atomic_state *state)250{251	int i;252 253	for (i = 0; i < state->num_global_objs; i++) {254		intel_atomic_global_state_put(state->global_objs[i].old_state);255		intel_atomic_global_state_put(state->global_objs[i].new_state);256 257		state->global_objs[i].ptr = NULL;258		state->global_objs[i].state = NULL;259		state->global_objs[i].old_state = NULL;260		state->global_objs[i].new_state = NULL;261	}262	state->num_global_objs = 0;263}264 265int intel_atomic_lock_global_state(struct intel_global_state *obj_state)266{267	struct intel_atomic_state *state = obj_state->state;268	struct drm_i915_private *dev_priv = to_i915(state->base.dev);269	struct intel_crtc *crtc;270 271	for_each_intel_crtc(&dev_priv->drm, crtc) {272		int ret;273 274		ret = drm_modeset_lock(&crtc->base.mutex,275				       state->base.acquire_ctx);276		if (ret)277			return ret;278	}279 280	obj_state->changed = true;281 282	return 0;283}284 285int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)286{287	int ret;288 289	ret = intel_atomic_lock_global_state(obj_state);290	if (ret)291		return ret;292 293	obj_state->serialized = true;294 295	return 0;296}297 298bool299intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)300{301	struct drm_i915_private *i915 = to_i915(state->base.dev);302	struct intel_crtc *crtc;303 304	for_each_intel_crtc(&i915->drm, crtc)305		if (!intel_atomic_get_new_crtc_state(state, crtc))306			return false;307	return true;308}309 310int311intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)312{313	const struct intel_global_state *old_obj_state;314	struct intel_global_state *new_obj_state;315	struct intel_global_obj *obj;316	int i;317 318	for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,319					    new_obj_state, i) {320		struct intel_global_commit *commit = NULL;321 322		if (new_obj_state->serialized) {323			/*324			 * New commit which is going to be completed325			 * after the hardware reprogramming is done.326			 */327			commit = commit_new();328			if (!commit)329				return -ENOMEM;330		} else if (new_obj_state->changed) {331			/*332			 * We're going to swap to this state, so carry the333			 * previous commit along, in case it's not yet done.334			 */335			commit = commit_get(old_obj_state->commit);336		}337 338		new_obj_state->commit = commit;339	}340 341	return 0;342}343 344int345intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)346{347	struct drm_i915_private *i915 = to_i915(state->base.dev);348	const struct intel_global_state *old_obj_state;349	struct intel_global_obj *obj;350	int i;351 352	for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {353		struct intel_global_commit *commit = old_obj_state->commit;354		long ret;355 356		if (!commit)357			continue;358 359		ret = wait_for_completion_timeout(&commit->done, 10 * HZ);360		if (ret == 0) {361			drm_err(&i915->drm, "global state timed out\n");362			return -ETIMEDOUT;363		}364	}365 366	return 0;367}368 369void370intel_atomic_global_state_commit_done(struct intel_atomic_state *state)371{372	const struct intel_global_state *new_obj_state;373	struct intel_global_obj *obj;374	int i;375 376	for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {377		struct intel_global_commit *commit = new_obj_state->commit;378 379		if (!new_obj_state->serialized)380			continue;381 382		complete_all(&commit->done);383	}384}385