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