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 27 #include "drm_crtc_internal.h" 28 29 /* 30 * Internal function to assign a slot in the object idr and optionally 31 * register the object into the idr. 32 */ 33 int drm_mode_object_get_reg(struct drm_device *dev, 34 struct drm_mode_object *obj, 35 uint32_t obj_type, 36 bool register_obj, 37 void (*obj_free_cb)(struct kref *kref)) 38 { 39 int ret; 40 41 mutex_lock(&dev->mode_config.idr_mutex); 42 ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 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_get - 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. Note that despite the _get postfix 68 * modeset identifiers are _not_ reference counted. Hence don't use this for 69 * reference counted modeset objects like framebuffers. 70 * 71 * Returns: 72 * Zero on success, error code on failure. 73 */ 74 int drm_mode_object_get(struct drm_device *dev, 75 struct drm_mode_object *obj, uint32_t obj_type) 76 { 77 return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); 78 } 79 80 void drm_mode_object_register(struct drm_device *dev, 81 struct drm_mode_object *obj) 82 { 83 mutex_lock(&dev->mode_config.idr_mutex); 84 idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 85 mutex_unlock(&dev->mode_config.idr_mutex); 86 } 87 88 /** 89 * drm_mode_object_unregister - free a modeset identifer 90 * @dev: DRM device 91 * @object: object to free 92 * 93 * Free @id from @dev's unique identifier pool. 94 * This function can be called multiple times, and guards against 95 * multiple removals. 96 * These modeset identifiers are _not_ reference counted. Hence don't use this 97 * for reference counted modeset objects like framebuffers. 98 */ 99 void drm_mode_object_unregister(struct drm_device *dev, 100 struct drm_mode_object *object) 101 { 102 mutex_lock(&dev->mode_config.idr_mutex); 103 if (object->id) { 104 idr_remove(&dev->mode_config.crtc_idr, object->id); 105 object->id = 0; 106 } 107 mutex_unlock(&dev->mode_config.idr_mutex); 108 } 109 110 struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, 111 uint32_t id, uint32_t type) 112 { 113 struct drm_mode_object *obj = NULL; 114 115 mutex_lock(&dev->mode_config.idr_mutex); 116 obj = idr_find(&dev->mode_config.crtc_idr, id); 117 if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 118 obj = NULL; 119 if (obj && obj->id != id) 120 obj = NULL; 121 122 if (obj && obj->free_cb) { 123 if (!kref_get_unless_zero(&obj->refcount)) 124 obj = NULL; 125 } 126 mutex_unlock(&dev->mode_config.idr_mutex); 127 128 return obj; 129 } 130 131 /** 132 * drm_mode_object_find - look up a drm object with static lifetime 133 * @dev: drm device 134 * @id: id of the mode object 135 * @type: type of the mode object 136 * 137 * This function is used to look up a modeset object. It will acquire a 138 * reference for reference counted objects. This reference must be dropped again 139 * by callind drm_mode_object_unreference(). 140 */ 141 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 142 uint32_t id, uint32_t type) 143 { 144 struct drm_mode_object *obj = NULL; 145 146 obj = __drm_mode_object_find(dev, id, type); 147 return obj; 148 } 149 EXPORT_SYMBOL(drm_mode_object_find); 150 151 /** 152 * drm_mode_object_unreference - decr the object refcnt 153 * @obj: mode_object 154 * 155 * This function decrements the object's refcount if it is a refcounted modeset 156 * object. It is a no-op on any other object. This is used to drop references 157 * acquired with drm_mode_object_reference(). 158 */ 159 void drm_mode_object_unreference(struct drm_mode_object *obj) 160 { 161 if (obj->free_cb) { 162 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); 163 kref_put(&obj->refcount, obj->free_cb); 164 } 165 } 166 EXPORT_SYMBOL(drm_mode_object_unreference); 167 168 /** 169 * drm_mode_object_reference - incr the object refcnt 170 * @obj: mode_object 171 * 172 * This function increments the object's refcount if it is a refcounted modeset 173 * object. It is a no-op on any other object. References should be dropped again 174 * by calling drm_mode_object_unreference(). 175 */ 176 void drm_mode_object_reference(struct drm_mode_object *obj) 177 { 178 if (obj->free_cb) { 179 DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); 180 kref_get(&obj->refcount); 181 } 182 } 183 EXPORT_SYMBOL(drm_mode_object_reference); 184 185 /** 186 * drm_object_attach_property - attach a property to a modeset object 187 * @obj: drm modeset object 188 * @property: property to attach 189 * @init_val: initial value of the property 190 * 191 * This attaches the given property to the modeset object with the given initial 192 * value. Currently this function cannot fail since the properties are stored in 193 * a statically sized array. 194 */ 195 void drm_object_attach_property(struct drm_mode_object *obj, 196 struct drm_property *property, 197 uint64_t init_val) 198 { 199 int count = obj->properties->count; 200 201 if (count == DRM_OBJECT_MAX_PROPERTY) { 202 WARN(1, "Failed to attach object property (type: 0x%x). Please " 203 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 204 "you see this message on the same object type.\n", 205 obj->type); 206 return; 207 } 208 209 obj->properties->properties[count] = property; 210 obj->properties->values[count] = init_val; 211 obj->properties->count++; 212 } 213 EXPORT_SYMBOL(drm_object_attach_property); 214 215 /** 216 * drm_object_property_set_value - set the value of a property 217 * @obj: drm mode object to set property value for 218 * @property: property to set 219 * @val: value the property should be set to 220 * 221 * This function sets a given property on a given object. This function only 222 * changes the software state of the property, it does not call into the 223 * driver's ->set_property callback. 224 * 225 * Note that atomic drivers should not have any need to call this, the core will 226 * ensure consistency of values reported back to userspace through the 227 * appropriate ->atomic_get_property callback. Only legacy drivers should call 228 * this function to update the tracked value (after clamping and other 229 * restrictions have been applied). 230 * 231 * Returns: 232 * Zero on success, error code on failure. 233 */ 234 int drm_object_property_set_value(struct drm_mode_object *obj, 235 struct drm_property *property, uint64_t val) 236 { 237 int i; 238 239 for (i = 0; i < obj->properties->count; i++) { 240 if (obj->properties->properties[i] == property) { 241 obj->properties->values[i] = val; 242 return 0; 243 } 244 } 245 246 return -EINVAL; 247 } 248 EXPORT_SYMBOL(drm_object_property_set_value); 249 250 /** 251 * drm_object_property_get_value - retrieve the value of a property 252 * @obj: drm mode object to get property value from 253 * @property: property to retrieve 254 * @val: storage for the property value 255 * 256 * This function retrieves the softare state of the given property for the given 257 * property. Since there is no driver callback to retrieve the current property 258 * value this might be out of sync with the hardware, depending upon the driver 259 * and property. 260 * 261 * Atomic drivers should never call this function directly, the core will read 262 * out property values through the various ->atomic_get_property callbacks. 263 * 264 * Returns: 265 * Zero on success, error code on failure. 266 */ 267 int drm_object_property_get_value(struct drm_mode_object *obj, 268 struct drm_property *property, uint64_t *val) 269 { 270 int i; 271 272 /* read-only properties bypass atomic mechanism and still store 273 * their value in obj->properties->values[].. mostly to avoid 274 * having to deal w/ EDID and similar props in atomic paths: 275 */ 276 if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 277 !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 278 return drm_atomic_get_property(obj, property, val); 279 280 for (i = 0; i < obj->properties->count; i++) { 281 if (obj->properties->properties[i] == property) { 282 *val = obj->properties->values[i]; 283 return 0; 284 } 285 286 } 287 288 return -EINVAL; 289 } 290 EXPORT_SYMBOL(drm_object_property_get_value); 291 292 /* helper for getconnector and getproperties ioctls */ 293 int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, 294 uint32_t __user *prop_ptr, 295 uint64_t __user *prop_values, 296 uint32_t *arg_count_props) 297 { 298 int i, ret, count; 299 300 for (i = 0, count = 0; i < obj->properties->count; i++) { 301 struct drm_property *prop = obj->properties->properties[i]; 302 uint64_t val; 303 304 if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 305 continue; 306 307 if (*arg_count_props > count) { 308 ret = drm_object_property_get_value(obj, prop, &val); 309 if (ret) 310 return ret; 311 312 if (put_user(prop->base.id, prop_ptr + count)) 313 return -EFAULT; 314 315 if (put_user(val, prop_values + count)) 316 return -EFAULT; 317 } 318 319 count++; 320 } 321 *arg_count_props = count; 322 323 return 0; 324 } 325 326 /** 327 * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 328 * @dev: DRM device 329 * @data: ioctl data 330 * @file_priv: DRM file info 331 * 332 * This function retrieves the current value for an object's property. Compared 333 * to the connector specific ioctl this one is extended to also work on crtc and 334 * plane objects. 335 * 336 * Called by the user via ioctl. 337 * 338 * Returns: 339 * Zero on success, negative errno on failure. 340 */ 341 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 342 struct drm_file *file_priv) 343 { 344 struct drm_mode_obj_get_properties *arg = data; 345 struct drm_mode_object *obj; 346 int ret = 0; 347 348 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 349 return -EINVAL; 350 351 drm_modeset_lock_all(dev); 352 353 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 354 if (!obj) { 355 ret = -ENOENT; 356 goto out; 357 } 358 if (!obj->properties) { 359 ret = -EINVAL; 360 goto out_unref; 361 } 362 363 ret = drm_mode_object_get_properties(obj, file_priv->atomic, 364 (uint32_t __user *)(unsigned long)(arg->props_ptr), 365 (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 366 &arg->count_props); 367 368 out_unref: 369 drm_mode_object_unreference(obj); 370 out: 371 drm_modeset_unlock_all(dev); 372 return ret; 373 } 374 375 struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj, 376 uint32_t prop_id) 377 { 378 int i; 379 380 for (i = 0; i < obj->properties->count; i++) 381 if (obj->properties->properties[i]->base.id == prop_id) 382 return obj->properties->properties[i]; 383 384 return NULL; 385 } 386 387 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 388 struct drm_file *file_priv) 389 { 390 struct drm_mode_obj_set_property *arg = data; 391 struct drm_mode_object *arg_obj; 392 struct drm_property *property; 393 int ret = -EINVAL; 394 struct drm_mode_object *ref; 395 396 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 397 return -EINVAL; 398 399 drm_modeset_lock_all(dev); 400 401 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 402 if (!arg_obj) { 403 ret = -ENOENT; 404 goto out; 405 } 406 407 if (!arg_obj->properties) 408 goto out_unref; 409 410 property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id); 411 if (!property) 412 goto out_unref; 413 414 if (!drm_property_change_valid_get(property, arg->value, &ref)) 415 goto out_unref; 416 417 switch (arg_obj->type) { 418 case DRM_MODE_OBJECT_CONNECTOR: 419 ret = drm_mode_connector_set_obj_prop(arg_obj, property, 420 arg->value); 421 break; 422 case DRM_MODE_OBJECT_CRTC: 423 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 424 break; 425 case DRM_MODE_OBJECT_PLANE: 426 ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 427 property, arg->value); 428 break; 429 } 430 431 drm_property_change_valid_put(property, ref); 432 433 out_unref: 434 drm_mode_object_unreference(arg_obj); 435 out: 436 drm_modeset_unlock_all(dev); 437 return ret; 438 } 439