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