drm_mode_object.c 14.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Copyright (c) 2016 Intel Corporation
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_mode_object.h>
26
#include <drm/drm_atomic.h>
27 28 29 30 31 32 33

#include "drm_crtc_internal.h"

/*
 * Internal function to assign a slot in the object idr and optionally
 * register the object into the idr.
 */
34 35 36
int __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))
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
{
	int ret;

	mutex_lock(&dev->mode_config.idr_mutex);
	ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
	if (ret >= 0) {
		/*
		 * Set up the object linking under the protection of the idr
		 * lock so that other users can't see inconsistent state.
		 */
		obj->id = ret;
		obj->type = obj_type;
		if (obj_free_cb) {
			obj->free_cb = obj_free_cb;
			kref_init(&obj->refcount);
		}
	}
	mutex_unlock(&dev->mode_config.idr_mutex);

	return ret < 0 ? ret : 0;
}

/**
60
 * drm_mode_object_add - allocate a new modeset identifier
61 62 63 64 65
 * @dev: DRM device
 * @obj: object pointer, used to generate unique ID
 * @obj_type: object type
 *
 * Create a unique identifier based on @ptr in @dev's identifier space.  Used
66
 * for tracking modes, CRTCs and connectors.
67 68 69 70
 *
 * Returns:
 * Zero on success, error code on failure.
 */
71
int drm_mode_object_add(struct drm_device *dev,
72 73
			struct drm_mode_object *obj, uint32_t obj_type)
{
74
	return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
}

void drm_mode_object_register(struct drm_device *dev,
			      struct drm_mode_object *obj)
{
	mutex_lock(&dev->mode_config.idr_mutex);
	idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
	mutex_unlock(&dev->mode_config.idr_mutex);
}

/**
 * drm_mode_object_unregister - free a modeset identifer
 * @dev: DRM device
 * @object: object to free
 *
 * Free @id from @dev's unique identifier pool.
 * This function can be called multiple times, and guards against
 * multiple removals.
 * These modeset identifiers are _not_ reference counted. Hence don't use this
 * for reference counted modeset objects like framebuffers.
 */
void drm_mode_object_unregister(struct drm_device *dev,
97
				struct drm_mode_object *object)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
{
	mutex_lock(&dev->mode_config.idr_mutex);
	if (object->id) {
		idr_remove(&dev->mode_config.crtc_idr, object->id);
		object->id = 0;
	}
	mutex_unlock(&dev->mode_config.idr_mutex);
}

struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
					       uint32_t id, uint32_t type)
{
	struct drm_mode_object *obj = NULL;

	mutex_lock(&dev->mode_config.idr_mutex);
	obj = idr_find(&dev->mode_config.crtc_idr, id);
	if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
		obj = NULL;
	if (obj && obj->id != id)
		obj = NULL;

	if (obj && obj->free_cb) {
		if (!kref_get_unless_zero(&obj->refcount))
			obj = NULL;
	}
	mutex_unlock(&dev->mode_config.idr_mutex);

	return obj;
}

/**
 * drm_mode_object_find - look up a drm object with static lifetime
 * @dev: drm device
 * @id: id of the mode object
 * @type: type of the mode object
 *
 * This function is used to look up a modeset object. It will acquire a
 * reference for reference counted objects. This reference must be dropped again
136
 * by callind drm_mode_object_put().
137 138 139 140 141 142 143 144 145 146 147 148
 */
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
		uint32_t id, uint32_t type)
{
	struct drm_mode_object *obj = NULL;

	obj = __drm_mode_object_find(dev, id, type);
	return obj;
}
EXPORT_SYMBOL(drm_mode_object_find);

/**
149 150
 * drm_mode_object_put - release a mode object reference
 * @obj: DRM mode object
151
 *
152
 * This function decrements the object's refcount if it is a refcounted modeset
153
 * object. It is a no-op on any other object. This is used to drop references
154
 * acquired with drm_mode_object_get().
155
 */
156
void drm_mode_object_put(struct drm_mode_object *obj)
157 158
{
	if (obj->free_cb) {
159
		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
160 161 162
		kref_put(&obj->refcount, obj->free_cb);
	}
}
163
EXPORT_SYMBOL(drm_mode_object_put);
164 165

/**
166 167
 * drm_mode_object_get - acquire a mode object reference
 * @obj: DRM mode object
168
 *
169
 * This function increments the object's refcount if it is a refcounted modeset
170
 * object. It is a no-op on any other object. References should be dropped again
171
 * by calling drm_mode_object_put().
172
 */
173
void drm_mode_object_get(struct drm_mode_object *obj)
174 175
{
	if (obj->free_cb) {
176
		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
177 178 179
		kref_get(&obj->refcount);
	}
}
180
EXPORT_SYMBOL(drm_mode_object_get);
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

/**
 * drm_object_attach_property - attach a property to a modeset object
 * @obj: drm modeset object
 * @property: property to attach
 * @init_val: initial value of the property
 *
 * This attaches the given property to the modeset object with the given initial
 * value. Currently this function cannot fail since the properties are stored in
 * a statically sized array.
 */
void drm_object_attach_property(struct drm_mode_object *obj,
				struct drm_property *property,
				uint64_t init_val)
{
	int count = obj->properties->count;

	if (count == DRM_OBJECT_MAX_PROPERTY) {
		WARN(1, "Failed to attach object property (type: 0x%x). Please "
			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
			"you see this message on the same object type.\n",
			obj->type);
		return;
	}

	obj->properties->properties[count] = property;
	obj->properties->values[count] = init_val;
	obj->properties->count++;
}
EXPORT_SYMBOL(drm_object_attach_property);

/**
 * drm_object_property_set_value - set the value of a property
 * @obj: drm mode object to set property value for
 * @property: property to set
 * @val: value the property should be set to
 *
218
 * This function sets a given property on a given object. This function only
219 220 221
 * changes the software state of the property, it does not call into the
 * driver's ->set_property callback.
 *
222 223 224 225 226 227
 * Note that atomic drivers should not have any need to call this, the core will
 * ensure consistency of values reported back to userspace through the
 * appropriate ->atomic_get_property callback. Only legacy drivers should call
 * this function to update the tracked value (after clamping and other
 * restrictions have been applied).
 *
228 229 230 231 232 233 234 235
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_object_property_set_value(struct drm_mode_object *obj,
				  struct drm_property *property, uint64_t val)
{
	int i;

236 237 238
	WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
		!(property->flags & DRM_MODE_PROP_IMMUTABLE));

239 240 241 242 243 244 245 246 247 248 249
	for (i = 0; i < obj->properties->count; i++) {
		if (obj->properties->properties[i] == property) {
			obj->properties->values[i] = val;
			return 0;
		}
	}

	return -EINVAL;
}
EXPORT_SYMBOL(drm_object_property_set_value);

250
int __drm_object_property_get_value(struct drm_mode_object *obj,
251 252 253 254 255 256 257 258
				  struct drm_property *property, uint64_t *val)
{
	int i;

	/* read-only properties bypass atomic mechanism and still store
	 * their value in obj->properties->values[].. mostly to avoid
	 * having to deal w/ EDID and similar props in atomic paths:
	 */
259
	if (drm_drv_uses_atomic_modeset(property->dev) &&
260 261 262 263 264 265 266 267 268 269 270 271 272
			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
		return drm_atomic_get_property(obj, property, val);

	for (i = 0; i < obj->properties->count; i++) {
		if (obj->properties->properties[i] == property) {
			*val = obj->properties->values[i];
			return 0;
		}

	}

	return -EINVAL;
}
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297

/**
 * drm_object_property_get_value - retrieve the value of a property
 * @obj: drm mode object to get property value from
 * @property: property to retrieve
 * @val: storage for the property value
 *
 * This function retrieves the softare state of the given property for the given
 * property. Since there is no driver callback to retrieve the current property
 * value this might be out of sync with the hardware, depending upon the driver
 * and property.
 *
 * Atomic drivers should never call this function directly, the core will read
 * out property values through the various ->atomic_get_property callbacks.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_object_property_get_value(struct drm_mode_object *obj,
				  struct drm_property *property, uint64_t *val)
{
	WARN_ON(drm_drv_uses_atomic_modeset(property->dev));

	return __drm_object_property_get_value(obj, property, val);
}
298 299 300 301 302 303 304 305
EXPORT_SYMBOL(drm_object_property_get_value);

/* helper for getconnector and getproperties ioctls */
int 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)
{
306
	int i, ret, count;
307

308 309 310
	for (i = 0, count = 0; i < obj->properties->count; i++) {
		struct drm_property *prop = obj->properties->properties[i];
		uint64_t val;
311

312 313
		if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
			continue;
314

315
		if (*arg_count_props > count) {
316
			ret = __drm_object_property_get_value(obj, prop, &val);
317 318 319
			if (ret)
				return ret;

320
			if (put_user(prop->base.id, prop_ptr + count))
321 322
				return -EFAULT;

323
			if (put_user(val, prop_values + count))
324 325
				return -EFAULT;
		}
326 327

		count++;
328
	}
329
	*arg_count_props = count;
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

	return 0;
}

/**
 * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
 * @dev: DRM device
 * @data: ioctl data
 * @file_priv: DRM file info
 *
 * This function retrieves the current value for an object's property. Compared
 * to the connector specific ioctl this one is extended to also work on crtc and
 * plane objects.
 *
 * Called by the user via ioctl.
 *
 * Returns:
 * Zero on success, negative errno on failure.
 */
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
				      struct drm_file *file_priv)
{
	struct drm_mode_obj_get_properties *arg = data;
	struct drm_mode_object *obj;
	int ret = 0;

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

	drm_modeset_lock_all(dev);

	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
	if (!obj) {
		ret = -ENOENT;
		goto out;
	}
	if (!obj->properties) {
		ret = -EINVAL;
		goto out_unref;
	}

	ret = drm_mode_object_get_properties(obj, file_priv->atomic,
			(uint32_t __user *)(unsigned long)(arg->props_ptr),
			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
			&arg->count_props);

out_unref:
377
	drm_mode_object_put(obj);
378 379 380 381 382
out:
	drm_modeset_unlock_all(dev);
	return ret;
}

383 384 385 386 387 388 389 390 391 392 393 394
struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
					       uint32_t prop_id)
{
	int i;

	for (i = 0; i < obj->properties->count; i++)
		if (obj->properties->properties[i]->base.id == prop_id)
			return obj->properties->properties[i];

	return NULL;
}

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
static int set_property_legacy(struct drm_mode_object *obj,
			       struct drm_property *prop,
			       uint64_t prop_value)
{
	struct drm_device *dev = prop->dev;
	struct drm_mode_object *ref;
	int ret = -EINVAL;

	if (!drm_property_change_valid_get(prop, prop_value, &ref))
		return -EINVAL;

	drm_modeset_lock_all(dev);
	switch (obj->type) {
	case DRM_MODE_OBJECT_CONNECTOR:
		ret = drm_mode_connector_set_obj_prop(obj, prop,
						      prop_value);
		break;
	case DRM_MODE_OBJECT_CRTC:
		ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
		break;
	case DRM_MODE_OBJECT_PLANE:
		ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
						  prop, prop_value);
		break;
	}
	drm_property_change_valid_put(prop, ref);
	drm_modeset_unlock_all(dev);

	return ret;
}

static int set_property_atomic(struct drm_mode_object *obj,
			       struct drm_property *prop,
			       uint64_t prop_value)
{
	struct drm_device *dev = prop->dev;
	struct drm_atomic_state *state;
	struct drm_modeset_acquire_ctx ctx;
	int ret;

	drm_modeset_acquire_init(&ctx, 0);

	state = drm_atomic_state_alloc(dev);
	if (!state)
		return -ENOMEM;
	state->acquire_ctx = &ctx;
retry:
	if (prop == state->dev->mode_config.dpms_property) {
		if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
			ret = -EINVAL;
			goto out;
		}

		ret = drm_atomic_connector_commit_dpms(state,
						       obj_to_connector(obj),
						       prop_value);
	} else {
		ret = drm_atomic_set_property(state, obj, prop, prop_value);
		if (ret)
			goto out;
		ret = drm_atomic_commit(state);
	}
out:
	if (ret == -EDEADLK) {
		drm_atomic_state_clear(state);
		drm_modeset_backoff(&ctx);
		goto retry;
	}

	drm_atomic_state_put(state);

	drm_modeset_drop_locks(&ctx);
	drm_modeset_acquire_fini(&ctx);

	return ret;
}

472 473 474 475 476 477
int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
				    struct drm_file *file_priv)
{
	struct drm_mode_obj_set_property *arg = data;
	struct drm_mode_object *arg_obj;
	struct drm_property *property;
478
	int ret = -EINVAL;
479 480 481 482 483

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
484 485
	if (!arg_obj)
		return -ENOENT;
486

487
	if (!arg_obj->properties)
488 489
		goto out_unref;

490 491
	property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
	if (!property)
492 493
		goto out_unref;

494 495 496 497
	if (drm_drv_uses_atomic_modeset(property->dev))
		ret = set_property_atomic(arg_obj, property, arg->value);
	else
		ret = set_property_legacy(arg_obj, property, arg->value);
498 499

out_unref:
500
	drm_mode_object_put(arg_obj);
501 502
	return ret;
}