xref: /linux/drivers/gpu/drm/drm_mode_object.c (revision bd628c1bed7902ec1f24ba0fe70758949146abbe)
1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #include <linux/export.h>
24 #include <drm/drmP.h>
25 #include <drm/drm_mode_object.h>
26 #include <drm/drm_atomic.h>
27 
28 #include "drm_crtc_internal.h"
29 
30 /*
31  * Internal function to assign a slot in the object idr and optionally
32  * register the object into the idr.
33  */
34 int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
35 			  uint32_t obj_type, bool register_obj,
36 			  void (*obj_free_cb)(struct kref *kref))
37 {
38 	int ret;
39 
40 	mutex_lock(&dev->mode_config.idr_mutex);
41 	ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL,
42 			1, 0, GFP_KERNEL);
43 	if (ret >= 0) {
44 		/*
45 		 * Set up the object linking under the protection of the idr
46 		 * lock so that other users can't see inconsistent state.
47 		 */
48 		obj->id = ret;
49 		obj->type = obj_type;
50 		if (obj_free_cb) {
51 			obj->free_cb = obj_free_cb;
52 			kref_init(&obj->refcount);
53 		}
54 	}
55 	mutex_unlock(&dev->mode_config.idr_mutex);
56 
57 	return ret < 0 ? ret : 0;
58 }
59 
60 /**
61  * drm_mode_object_add - allocate a new modeset identifier
62  * @dev: DRM device
63  * @obj: object pointer, used to generate unique ID
64  * @obj_type: object type
65  *
66  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
67  * for tracking modes, CRTCs and connectors.
68  *
69  * Returns:
70  * Zero on success, error code on failure.
71  */
72 int drm_mode_object_add(struct drm_device *dev,
73 			struct drm_mode_object *obj, uint32_t obj_type)
74 {
75 	return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
76 }
77 
78 void drm_mode_object_register(struct drm_device *dev,
79 			      struct drm_mode_object *obj)
80 {
81 	mutex_lock(&dev->mode_config.idr_mutex);
82 	idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
83 	mutex_unlock(&dev->mode_config.idr_mutex);
84 }
85 
86 /**
87  * drm_mode_object_unregister - free a modeset identifer
88  * @dev: DRM device
89  * @object: object to free
90  *
91  * Free @id from @dev's unique identifier pool.
92  * This function can be called multiple times, and guards against
93  * multiple removals.
94  * These modeset identifiers are _not_ reference counted. Hence don't use this
95  * for reference counted modeset objects like framebuffers.
96  */
97 void drm_mode_object_unregister(struct drm_device *dev,
98 				struct drm_mode_object *object)
99 {
100 	mutex_lock(&dev->mode_config.idr_mutex);
101 	if (object->id) {
102 		idr_remove(&dev->mode_config.crtc_idr, object->id);
103 		object->id = 0;
104 	}
105 	mutex_unlock(&dev->mode_config.idr_mutex);
106 }
107 
108 /**
109  * drm_lease_required - check types which must be leased to be used
110  * @type: type of object
111  *
112  * Returns whether the provided type of drm_mode_object must
113  * be owned or leased to be used by a process.
114  */
115 bool drm_mode_object_lease_required(uint32_t type)
116 {
117 	switch(type) {
118 	case DRM_MODE_OBJECT_CRTC:
119 	case DRM_MODE_OBJECT_CONNECTOR:
120 	case DRM_MODE_OBJECT_PLANE:
121 		return true;
122 	default:
123 		return false;
124 	}
125 }
126 
127 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
128 					       struct drm_file *file_priv,
129 					       uint32_t id, uint32_t type)
130 {
131 	struct drm_mode_object *obj = NULL;
132 
133 	mutex_lock(&dev->mode_config.idr_mutex);
134 	obj = idr_find(&dev->mode_config.crtc_idr, id);
135 	if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
136 		obj = NULL;
137 	if (obj && obj->id != id)
138 		obj = NULL;
139 
140 	if (obj && drm_mode_object_lease_required(obj->type) &&
141 	    !_drm_lease_held(file_priv, obj->id))
142 		obj = NULL;
143 
144 	if (obj && obj->free_cb) {
145 		if (!kref_get_unless_zero(&obj->refcount))
146 			obj = NULL;
147 	}
148 	mutex_unlock(&dev->mode_config.idr_mutex);
149 
150 	return obj;
151 }
152 
153 /**
154  * drm_mode_object_find - look up a drm object with static lifetime
155  * @dev: drm device
156  * @file_priv: drm file
157  * @id: id of the mode object
158  * @type: type of the mode object
159  *
160  * This function is used to look up a modeset object. It will acquire a
161  * reference for reference counted objects. This reference must be dropped again
162  * by callind drm_mode_object_put().
163  */
164 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
165 		struct drm_file *file_priv,
166 		uint32_t id, uint32_t type)
167 {
168 	struct drm_mode_object *obj = NULL;
169 
170 	obj = __drm_mode_object_find(dev, file_priv, id, type);
171 	return obj;
172 }
173 EXPORT_SYMBOL(drm_mode_object_find);
174 
175 /**
176  * drm_mode_object_put - release a mode object reference
177  * @obj: DRM mode object
178  *
179  * This function decrements the object's refcount if it is a refcounted modeset
180  * object. It is a no-op on any other object. This is used to drop references
181  * acquired with drm_mode_object_get().
182  */
183 void drm_mode_object_put(struct drm_mode_object *obj)
184 {
185 	if (obj->free_cb) {
186 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
187 		kref_put(&obj->refcount, obj->free_cb);
188 	}
189 }
190 EXPORT_SYMBOL(drm_mode_object_put);
191 
192 /**
193  * drm_mode_object_get - acquire a mode object reference
194  * @obj: DRM mode object
195  *
196  * This function increments the object's refcount if it is a refcounted modeset
197  * object. It is a no-op on any other object. References should be dropped again
198  * by calling drm_mode_object_put().
199  */
200 void drm_mode_object_get(struct drm_mode_object *obj)
201 {
202 	if (obj->free_cb) {
203 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
204 		kref_get(&obj->refcount);
205 	}
206 }
207 EXPORT_SYMBOL(drm_mode_object_get);
208 
209 /**
210  * drm_object_attach_property - attach a property to a modeset object
211  * @obj: drm modeset object
212  * @property: property to attach
213  * @init_val: initial value of the property
214  *
215  * This attaches the given property to the modeset object with the given initial
216  * value. Currently this function cannot fail since the properties are stored in
217  * a statically sized array.
218  */
219 void drm_object_attach_property(struct drm_mode_object *obj,
220 				struct drm_property *property,
221 				uint64_t init_val)
222 {
223 	int count = obj->properties->count;
224 
225 	if (count == DRM_OBJECT_MAX_PROPERTY) {
226 		WARN(1, "Failed to attach object property (type: 0x%x). Please "
227 			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
228 			"you see this message on the same object type.\n",
229 			obj->type);
230 		return;
231 	}
232 
233 	obj->properties->properties[count] = property;
234 	obj->properties->values[count] = init_val;
235 	obj->properties->count++;
236 }
237 EXPORT_SYMBOL(drm_object_attach_property);
238 
239 /**
240  * drm_object_property_set_value - set the value of a property
241  * @obj: drm mode object to set property value for
242  * @property: property to set
243  * @val: value the property should be set to
244  *
245  * This function sets a given property on a given object. This function only
246  * changes the software state of the property, it does not call into the
247  * driver's ->set_property callback.
248  *
249  * Note that atomic drivers should not have any need to call this, the core will
250  * ensure consistency of values reported back to userspace through the
251  * appropriate ->atomic_get_property callback. Only legacy drivers should call
252  * this function to update the tracked value (after clamping and other
253  * restrictions have been applied).
254  *
255  * Returns:
256  * Zero on success, error code on failure.
257  */
258 int drm_object_property_set_value(struct drm_mode_object *obj,
259 				  struct drm_property *property, uint64_t val)
260 {
261 	int i;
262 
263 	WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
264 		!(property->flags & DRM_MODE_PROP_IMMUTABLE));
265 
266 	for (i = 0; i < obj->properties->count; i++) {
267 		if (obj->properties->properties[i] == property) {
268 			obj->properties->values[i] = val;
269 			return 0;
270 		}
271 	}
272 
273 	return -EINVAL;
274 }
275 EXPORT_SYMBOL(drm_object_property_set_value);
276 
277 static int __drm_object_property_get_value(struct drm_mode_object *obj,
278 					   struct drm_property *property,
279 					   uint64_t *val)
280 {
281 	int i;
282 
283 	/* read-only properties bypass atomic mechanism and still store
284 	 * their value in obj->properties->values[].. mostly to avoid
285 	 * having to deal w/ EDID and similar props in atomic paths:
286 	 */
287 	if (drm_drv_uses_atomic_modeset(property->dev) &&
288 			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
289 		return drm_atomic_get_property(obj, property, val);
290 
291 	for (i = 0; i < obj->properties->count; i++) {
292 		if (obj->properties->properties[i] == property) {
293 			*val = obj->properties->values[i];
294 			return 0;
295 		}
296 
297 	}
298 
299 	return -EINVAL;
300 }
301 
302 /**
303  * drm_object_property_get_value - retrieve the value of a property
304  * @obj: drm mode object to get property value from
305  * @property: property to retrieve
306  * @val: storage for the property value
307  *
308  * This function retrieves the softare state of the given property for the given
309  * property. Since there is no driver callback to retrieve the current property
310  * value this might be out of sync with the hardware, depending upon the driver
311  * and property.
312  *
313  * Atomic drivers should never call this function directly, the core will read
314  * out property values through the various ->atomic_get_property callbacks.
315  *
316  * Returns:
317  * Zero on success, error code on failure.
318  */
319 int drm_object_property_get_value(struct drm_mode_object *obj,
320 				  struct drm_property *property, uint64_t *val)
321 {
322 	WARN_ON(drm_drv_uses_atomic_modeset(property->dev));
323 
324 	return __drm_object_property_get_value(obj, property, val);
325 }
326 EXPORT_SYMBOL(drm_object_property_get_value);
327 
328 /* helper for getconnector and getproperties ioctls */
329 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
330 				   uint32_t __user *prop_ptr,
331 				   uint64_t __user *prop_values,
332 				   uint32_t *arg_count_props)
333 {
334 	int i, ret, count;
335 
336 	for (i = 0, count = 0; i < obj->properties->count; i++) {
337 		struct drm_property *prop = obj->properties->properties[i];
338 		uint64_t val;
339 
340 		if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
341 			continue;
342 
343 		if (*arg_count_props > count) {
344 			ret = __drm_object_property_get_value(obj, prop, &val);
345 			if (ret)
346 				return ret;
347 
348 			if (put_user(prop->base.id, prop_ptr + count))
349 				return -EFAULT;
350 
351 			if (put_user(val, prop_values + count))
352 				return -EFAULT;
353 		}
354 
355 		count++;
356 	}
357 	*arg_count_props = count;
358 
359 	return 0;
360 }
361 
362 /**
363  * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
364  * @dev: DRM device
365  * @data: ioctl data
366  * @file_priv: DRM file info
367  *
368  * This function retrieves the current value for an object's property. Compared
369  * to the connector specific ioctl this one is extended to also work on crtc and
370  * plane objects.
371  *
372  * Called by the user via ioctl.
373  *
374  * Returns:
375  * Zero on success, negative errno on failure.
376  */
377 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
378 				      struct drm_file *file_priv)
379 {
380 	struct drm_mode_obj_get_properties *arg = data;
381 	struct drm_mode_object *obj;
382 	int ret = 0;
383 
384 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
385 		return -EOPNOTSUPP;
386 
387 	drm_modeset_lock_all(dev);
388 
389 	obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
390 	if (!obj) {
391 		ret = -ENOENT;
392 		goto out;
393 	}
394 	if (!obj->properties) {
395 		ret = -EINVAL;
396 		goto out_unref;
397 	}
398 
399 	ret = drm_mode_object_get_properties(obj, file_priv->atomic,
400 			(uint32_t __user *)(unsigned long)(arg->props_ptr),
401 			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
402 			&arg->count_props);
403 
404 out_unref:
405 	drm_mode_object_put(obj);
406 out:
407 	drm_modeset_unlock_all(dev);
408 	return ret;
409 }
410 
411 struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
412 					       uint32_t prop_id)
413 {
414 	int i;
415 
416 	for (i = 0; i < obj->properties->count; i++)
417 		if (obj->properties->properties[i]->base.id == prop_id)
418 			return obj->properties->properties[i];
419 
420 	return NULL;
421 }
422 
423 static int set_property_legacy(struct drm_mode_object *obj,
424 			       struct drm_property *prop,
425 			       uint64_t prop_value)
426 {
427 	struct drm_device *dev = prop->dev;
428 	struct drm_mode_object *ref;
429 	int ret = -EINVAL;
430 
431 	if (!drm_property_change_valid_get(prop, prop_value, &ref))
432 		return -EINVAL;
433 
434 	drm_modeset_lock_all(dev);
435 	switch (obj->type) {
436 	case DRM_MODE_OBJECT_CONNECTOR:
437 		ret = drm_connector_set_obj_prop(obj, prop, prop_value);
438 		break;
439 	case DRM_MODE_OBJECT_CRTC:
440 		ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
441 		break;
442 	case DRM_MODE_OBJECT_PLANE:
443 		ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
444 						  prop, prop_value);
445 		break;
446 	}
447 	drm_property_change_valid_put(prop, ref);
448 	drm_modeset_unlock_all(dev);
449 
450 	return ret;
451 }
452 
453 static int set_property_atomic(struct drm_mode_object *obj,
454 			       struct drm_property *prop,
455 			       uint64_t prop_value)
456 {
457 	struct drm_device *dev = prop->dev;
458 	struct drm_atomic_state *state;
459 	struct drm_modeset_acquire_ctx ctx;
460 	int ret;
461 
462 	drm_modeset_acquire_init(&ctx, 0);
463 
464 	state = drm_atomic_state_alloc(dev);
465 	if (!state)
466 		return -ENOMEM;
467 	state->acquire_ctx = &ctx;
468 retry:
469 	if (prop == state->dev->mode_config.dpms_property) {
470 		if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
471 			ret = -EINVAL;
472 			goto out;
473 		}
474 
475 		ret = drm_atomic_connector_commit_dpms(state,
476 						       obj_to_connector(obj),
477 						       prop_value);
478 	} else {
479 		ret = drm_atomic_set_property(state, obj, prop, prop_value);
480 		if (ret)
481 			goto out;
482 		ret = drm_atomic_commit(state);
483 	}
484 out:
485 	if (ret == -EDEADLK) {
486 		drm_atomic_state_clear(state);
487 		drm_modeset_backoff(&ctx);
488 		goto retry;
489 	}
490 
491 	drm_atomic_state_put(state);
492 
493 	drm_modeset_drop_locks(&ctx);
494 	drm_modeset_acquire_fini(&ctx);
495 
496 	return ret;
497 }
498 
499 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
500 				    struct drm_file *file_priv)
501 {
502 	struct drm_mode_obj_set_property *arg = data;
503 	struct drm_mode_object *arg_obj;
504 	struct drm_property *property;
505 	int ret = -EINVAL;
506 
507 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
508 		return -EOPNOTSUPP;
509 
510 	arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
511 	if (!arg_obj)
512 		return -ENOENT;
513 
514 	if (!arg_obj->properties)
515 		goto out_unref;
516 
517 	property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
518 	if (!property)
519 		goto out_unref;
520 
521 	if (drm_drv_uses_atomic_modeset(property->dev))
522 		ret = set_property_atomic(arg_obj, property, arg->value);
523 	else
524 		ret = set_property_legacy(arg_obj, property, arg->value);
525 
526 out_unref:
527 	drm_mode_object_put(arg_obj);
528 	return ret;
529 }
530