File Index
Files and directories
Sign in
FILE

drm_atomic_uapi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/drm_atomic_uapi.c C
   1/*
   2 * Copyright (C) 2014 Red Hat
   3 * Copyright (C) 2014 Intel Corp.
   4 * Copyright (C) 2018 Intel Corp.
   5 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a
   8 * copy of this software and associated documentation files (the "Software"),
   9 * to deal in the Software without restriction, including without limitation
  10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11 * and/or sell copies of the Software, and to permit persons to whom the
  12 * Software is furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23 * OTHER DEALINGS IN THE SOFTWARE.
  24 *
  25 * Authors:
  26 * Rob Clark <robdclark@gmail.com>
  27 * Daniel Vetter <daniel.vetter@ffwll.ch>
  28 */
  29
  30#include <drm/drm_atomic.h>
  31#include <drm/drm_atomic_helper.h>
  32#include <drm/drm_atomic_uapi.h>
  33#include <drm/drm_framebuffer.h>
  34#include <drm/drm_print.h>
  35#include <drm/drm_drv.h>
  36#include <drm/drm_writeback.h>
  37#include <drm/drm_vblank.h>
  38#include <drm/drm_colorop.h>
  39
  40#include <linux/export.h>
  41#include <linux/dma-fence.h>
  42#include <linux/uaccess.h>
  43#include <linux/sync_file.h>
  44#include <linux/file.h>
  45
  46#include "drm_crtc_internal.h"
  47
  48/**
  49 * DOC: overview
  50 *
  51 * This file contains the marshalling and demarshalling glue for the atomic UAPI
  52 * in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
  53 * SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and
  54 * drivers which have special needs to construct their own atomic updates, e.g.
  55 * for load detect or similar.
  56 */
  57
  58/**
  59 * drm_atomic_set_mode_for_crtc - set mode for CRTC
  60 * @state: the CRTC whose incoming state to update
  61 * @mode: kernel-internal mode to use for the CRTC, or NULL to disable
  62 *
  63 * Set a mode (originating from the kernel) on the desired CRTC state and update
  64 * the enable property.
  65 *
  66 * RETURNS:
  67 * Zero on success, error code on failure. Cannot return -EDEADLK.
  68 */
  69int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
  70				 const struct drm_display_mode *mode)
  71{
  72	struct drm_crtc *crtc = state->crtc;
  73	struct drm_mode_modeinfo umode;
  74
  75	/* Early return for no change. */
  76	if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
  77		return 0;
  78
  79	drm_property_blob_put(state->mode_blob);
  80	state->mode_blob = NULL;
  81
  82	if (mode) {
  83		struct drm_property_blob *blob;
  84
  85		drm_mode_convert_to_umode(&umode, mode);
  86		blob = drm_property_create_blob(crtc->dev,
  87						sizeof(umode), &umode);
  88		if (IS_ERR(blob))
  89			return PTR_ERR(blob);
  90
  91		drm_mode_copy(&state->mode, mode);
  92
  93		state->mode_blob = blob;
  94		state->enable = true;
  95		drm_dbg_atomic(crtc->dev,
  96			       "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
  97			       mode->name, crtc->base.id, crtc->name, state);
  98	} else {
  99		memset(&state->mode, 0, sizeof(state->mode));
 100		state->enable = false;
 101		drm_dbg_atomic(crtc->dev,
 102			       "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
 103			       crtc->base.id, crtc->name, state);
 104	}
 105
 106	return 0;
 107}
 108EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
 109
 110/**
 111 * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC
 112 * @state: the CRTC whose incoming state to update
 113 * @blob: pointer to blob property to use for mode
 114 *
 115 * Set a mode (originating from a blob property) on the desired CRTC state.
 116 * This function will take a reference on the blob property for the CRTC state,
 117 * and release the reference held on the state's existing mode property, if any
 118 * was set.
 119 *
 120 * RETURNS:
 121 * Zero on success, error code on failure. Cannot return -EDEADLK.
 122 */
 123int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
 124				      struct drm_property_blob *blob)
 125{
 126	struct drm_crtc *crtc = state->crtc;
 127
 128	if (blob == state->mode_blob)
 129		return 0;
 130
 131	drm_property_blob_put(state->mode_blob);
 132	state->mode_blob = NULL;
 133
 134	memset(&state->mode, 0, sizeof(state->mode));
 135
 136	if (blob) {
 137		int ret;
 138
 139		if (blob->length != sizeof(struct drm_mode_modeinfo)) {
 140			drm_dbg_atomic(crtc->dev,
 141				       "[CRTC:%d:%s] bad mode blob length: %zu\n",
 142				       crtc->base.id, crtc->name,
 143				       blob->length);
 144			return -EINVAL;
 145		}
 146
 147		ret = drm_mode_convert_umode(crtc->dev,
 148					     &state->mode, blob->data);
 149		if (ret) {
 150			drm_dbg_atomic(crtc->dev,
 151				       "[CRTC:%d:%s] invalid mode (%s, %pe): " DRM_MODE_FMT "\n",
 152				       crtc->base.id, crtc->name,
 153				       drm_get_mode_status_name(state->mode.status),
 154				       ERR_PTR(ret), DRM_MODE_ARG(&state->mode));
 155			return -EINVAL;
 156		}
 157
 158		state->mode_blob = drm_property_blob_get(blob);
 159		state->enable = true;
 160		drm_dbg_atomic(crtc->dev,
 161			       "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
 162			       state->mode.name, crtc->base.id, crtc->name,
 163			       state);
 164	} else {
 165		state->enable = false;
 166		drm_dbg_atomic(crtc->dev,
 167			       "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
 168			       crtc->base.id, crtc->name, state);
 169	}
 170
 171	return 0;
 172}
 173EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
 174
 175/**
 176 * drm_atomic_set_crtc_for_plane - set CRTC for plane
 177 * @plane_state: the plane whose incoming state to update
 178 * @crtc: CRTC to use for the plane
 179 *
 180 * Changing the assigned CRTC for a plane requires us to grab the lock and state
 181 * for the new CRTC, as needed. This function takes care of all these details
 182 * besides updating the pointer in the state object itself.
 183 *
 184 * Returns:
 185 * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
 186 * then the w/w mutex code has detected a deadlock and the entire atomic
 187 * sequence must be restarted. All other errors are fatal.
 188 */
 189int
 190drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
 191			      struct drm_crtc *crtc)
 192{
 193	struct drm_plane *plane = plane_state->plane;
 194	struct drm_crtc_state *crtc_state;
 195	/* Nothing to do for same crtc*/
 196	if (plane_state->crtc == crtc)
 197		return 0;
 198	if (plane_state->crtc) {
 199		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
 200						       plane_state->crtc);
 201		if (WARN_ON(IS_ERR(crtc_state)))
 202			return PTR_ERR(crtc_state);
 203
 204		crtc_state->plane_mask &= ~drm_plane_mask(plane);
 205	}
 206
 207	plane_state->crtc = crtc;
 208
 209	if (crtc) {
 210		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
 211						       crtc);
 212		if (IS_ERR(crtc_state))
 213			return PTR_ERR(crtc_state);
 214		crtc_state->plane_mask |= drm_plane_mask(plane);
 215	}
 216
 217	if (crtc)
 218		drm_dbg_atomic(plane->dev,
 219			       "Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
 220			       plane->base.id, plane->name, plane_state,
 221			       crtc->base.id, crtc->name);
 222	else
 223		drm_dbg_atomic(plane->dev,
 224			       "Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
 225			       plane->base.id, plane->name, plane_state);
 226
 227	return 0;
 228}
 229EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
 230
 231/**
 232 * drm_atomic_set_fb_for_plane - set framebuffer for plane
 233 * @plane_state: atomic state object for the plane
 234 * @fb: fb to use for the plane
 235 *
 236 * Changing the assigned framebuffer for a plane requires us to grab a reference
 237 * to the new fb and drop the reference to the old fb, if there is one. This
 238 * function takes care of all these details besides updating the pointer in the
 239 * state object itself.
 240 */
 241void
 242drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
 243			    struct drm_framebuffer *fb)
 244{
 245	struct drm_plane *plane = plane_state->plane;
 246
 247	if (fb)
 248		drm_dbg_atomic(plane->dev,
 249			       "Set [FB:%d] for [PLANE:%d:%s] state %p\n",
 250			       fb->base.id, plane->base.id, plane->name,
 251			       plane_state);
 252	else
 253		drm_dbg_atomic(plane->dev,
 254			       "Set [NOFB] for [PLANE:%d:%s] state %p\n",
 255			       plane->base.id, plane->name, plane_state);
 256
 257	drm_framebuffer_assign(&plane_state->fb, fb);
 258}
 259EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
 260
 261/**
 262 * drm_atomic_set_colorop_for_plane - set colorop for plane
 263 * @plane_state: atomic state object for the plane
 264 * @colorop: colorop to use for the plane
 265 *
 266 * Helper function to select the color pipeline on a plane by setting
 267 * it to the first drm_colorop element of the pipeline.
 268 */
 269void
 270drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state,
 271				 struct drm_colorop *colorop)
 272{
 273	struct drm_plane *plane = plane_state->plane;
 274
 275	if (colorop)
 276		drm_dbg_atomic(plane->dev,
 277			       "Set [COLOROP:%d] for [PLANE:%d:%s] state %p\n",
 278			       colorop->base.id, plane->base.id, plane->name,
 279			       plane_state);
 280	else
 281		drm_dbg_atomic(plane->dev,
 282			       "Set [NOCOLOROP] for [PLANE:%d:%s] state %p\n",
 283			       plane->base.id, plane->name, plane_state);
 284
 285	plane_state->color_pipeline = colorop;
 286}
 287EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane);
 288
 289/**
 290 * drm_atomic_set_crtc_for_connector - set CRTC for connector
 291 * @conn_state: atomic state object for the connector
 292 * @crtc: CRTC to use for the connector
 293 *
 294 * Changing the assigned CRTC for a connector requires us to grab the lock and
 295 * state for the new CRTC, as needed. This function takes care of all these
 296 * details besides updating the pointer in the state object itself.
 297 *
 298 * Returns:
 299 * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
 300 * then the w/w mutex code has detected a deadlock and the entire atomic
 301 * sequence must be restarted. All other errors are fatal.
 302 */
 303int
 304drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 305				  struct drm_crtc *crtc)
 306{
 307	struct drm_connector *connector = conn_state->connector;
 308	struct drm_crtc_state *crtc_state;
 309
 310	if (conn_state->crtc == crtc)
 311		return 0;
 312
 313	if (conn_state->crtc) {
 314		crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
 315							   conn_state->crtc);
 316
 317		crtc_state->connector_mask &=
 318			~drm_connector_mask(conn_state->connector);
 319
 320		drm_connector_put(conn_state->connector);
 321		conn_state->crtc = NULL;
 322	}
 323
 324	if (crtc) {
 325		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
 326		if (IS_ERR(crtc_state))
 327			return PTR_ERR(crtc_state);
 328
 329		crtc_state->connector_mask |=
 330			drm_connector_mask(conn_state->connector);
 331
 332		drm_connector_get(conn_state->connector);
 333		conn_state->crtc = crtc;
 334
 335		drm_dbg_atomic(connector->dev,
 336			       "Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
 337			       connector->base.id, connector->name,
 338			       conn_state, crtc->base.id, crtc->name);
 339	} else {
 340		drm_dbg_atomic(connector->dev,
 341			       "Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
 342			       connector->base.id, connector->name,
 343			       conn_state);
 344	}
 345
 346	return 0;
 347}
 348EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
 349
 350static void set_out_fence_for_crtc(struct drm_atomic_state *state,
 351				   struct drm_crtc *crtc, s32 __user *fence_ptr)
 352{
 353	state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
 354}
 355
 356static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
 357					  struct drm_crtc *crtc)
 358{
 359	s32 __user *fence_ptr;
 360
 361	fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
 362	state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
 363
 364	return fence_ptr;
 365}
 366
 367static int set_out_fence_for_connector(struct drm_atomic_state *state,
 368					struct drm_connector *connector,
 369					s32 __user *fence_ptr)
 370{
 371	unsigned int index = drm_connector_index(connector);
 372
 373	if (!fence_ptr)
 374		return 0;
 375
 376	if (put_user(-1, fence_ptr))
 377		return -EFAULT;
 378
 379	state->connectors[index].out_fence_ptr = fence_ptr;
 380
 381	return 0;
 382}
 383
 384static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
 385					       struct drm_connector *connector)
 386{
 387	unsigned int index = drm_connector_index(connector);
 388	s32 __user *fence_ptr;
 389
 390	fence_ptr = state->connectors[index].out_fence_ptr;
 391	state->connectors[index].out_fence_ptr = NULL;
 392
 393	return fence_ptr;
 394}
 395
 396static int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 397		struct drm_crtc_state *state, struct drm_property *property,
 398		uint64_t val)
 399{
 400	struct drm_device *dev = crtc->dev;
 401	struct drm_mode_config *config = &dev->mode_config;
 402	bool replaced = false;
 403	int ret;
 404
 405	if (property == config->prop_active)
 406		state->active = val;
 407	else if (property == config->prop_mode_id) {
 408		struct drm_property_blob *mode =
 409			drm_property_lookup_blob(dev, val);
 410		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
 411		drm_property_blob_put(mode);
 412		return ret;
 413	} else if (property == config->prop_vrr_enabled) {
 414		state->vrr_enabled = val;
 415	} else if (property == config->degamma_lut_property) {
 416		ret = drm_property_replace_blob_from_id(dev,
 417					&state->degamma_lut,
 418					val,
 419					-1, sizeof(struct drm_color_lut),
 420					&replaced);
 421		state->color_mgmt_changed |= replaced;
 422		return ret;
 423	} else if (property == config->ctm_property) {
 424		ret = drm_property_replace_blob_from_id(dev,
 425					&state->ctm,
 426					val,
 427					sizeof(struct drm_color_ctm), -1,
 428					&replaced);
 429		state->color_mgmt_changed |= replaced;
 430		return ret;
 431	} else if (property == config->gamma_lut_property) {
 432		ret = drm_property_replace_blob_from_id(dev,
 433					&state->gamma_lut,
 434					val,
 435					-1, sizeof(struct drm_color_lut),
 436					&replaced);
 437		state->color_mgmt_changed |= replaced;
 438		return ret;
 439	} else if (property == config->prop_out_fence_ptr) {
 440		s32 __user *fence_ptr = u64_to_user_ptr(val);
 441
 442		if (!fence_ptr)
 443			return 0;
 444
 445		if (put_user(-1, fence_ptr))
 446			return -EFAULT;
 447
 448		set_out_fence_for_crtc(state->state, crtc, fence_ptr);
 449	} else if (property == crtc->scaling_filter_property) {
 450		state->scaling_filter = val;
 451	} else if (property == crtc->sharpness_strength_property) {
 452		state->sharpness_strength = val;
 453	} else if (crtc->funcs->atomic_set_property) {
 454		return crtc->funcs->atomic_set_property(crtc, state, property, val);
 455	} else {
 456		drm_dbg_atomic(crtc->dev,
 457			       "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n",
 458			       crtc->base.id, crtc->name,
 459			       property->base.id, property->name);
 460		return -EINVAL;
 461	}
 462
 463	return 0;
 464}
 465
 466static int
 467drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 468		const struct drm_crtc_state *state,
 469		struct drm_property *property, uint64_t *val)
 470{
 471	struct drm_device *dev = crtc->dev;
 472	struct drm_mode_config *config = &dev->mode_config;
 473
 474	if (property == config->prop_active)
 475		*val = drm_atomic_crtc_effectively_active(state);
 476	else if (property == config->prop_mode_id)
 477		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
 478	else if (property == config->prop_vrr_enabled)
 479		*val = state->vrr_enabled;
 480	else if (property == config->degamma_lut_property)
 481		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
 482	else if (property == config->ctm_property)
 483		*val = (state->ctm) ? state->ctm->base.id : 0;
 484	else if (property == config->gamma_lut_property)
 485		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
 486	else if (property == config->prop_out_fence_ptr)
 487		*val = 0;
 488	else if (property == crtc->scaling_filter_property)
 489		*val = state->scaling_filter;
 490	else if (property == crtc->sharpness_strength_property)
 491		*val = state->sharpness_strength;
 492	else if (crtc->funcs->atomic_get_property)
 493		return crtc->funcs->atomic_get_property(crtc, state, property, val);
 494	else {
 495		drm_dbg_atomic(dev,
 496			       "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n",
 497			       crtc->base.id, crtc->name,
 498			       property->base.id, property->name);
 499		return -EINVAL;
 500	}
 501
 502	return 0;
 503}
 504
 505static int drm_atomic_plane_set_property(struct drm_plane *plane,
 506		struct drm_plane_state *state, struct drm_file *file_priv,
 507		struct drm_property *property, uint64_t val)
 508{
 509	struct drm_device *dev = plane->dev;
 510	struct drm_mode_config *config = &dev->mode_config;
 511	bool replaced = false;
 512	int ret;
 513
 514	if (property == config->prop_fb_id) {
 515		struct drm_framebuffer *fb;
 516
 517		fb = drm_framebuffer_lookup(dev, file_priv, val);
 518		drm_atomic_set_fb_for_plane(state, fb);
 519		if (fb)
 520			drm_framebuffer_put(fb);
 521	} else if (property == config->prop_in_fence_fd) {
 522		if (state->fence)
 523			return -EINVAL;
 524
 525		if (U642I64(val) == -1)
 526			return 0;
 527
 528		state->fence = sync_file_get_fence(val);
 529		if (!state->fence)
 530			return -EINVAL;
 531
 532	} else if (property == config->prop_crtc_id) {
 533		struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
 534
 535		if (val && !crtc) {
 536			drm_dbg_atomic(dev,
 537				       "[PROP:%d:%s] cannot find CRTC with ID %llu\n",
 538				       property->base.id, property->name, val);
 539			return -EACCES;
 540		}
 541		return drm_atomic_set_crtc_for_plane(state, crtc);
 542	} else if (property == config->prop_crtc_x) {
 543		state->crtc_x = U642I64(val);
 544	} else if (property == config->prop_crtc_y) {
 545		state->crtc_y = U642I64(val);
 546	} else if (property == config->prop_crtc_w) {
 547		state->crtc_w = val;
 548	} else if (property == config->prop_crtc_h) {
 549		state->crtc_h = val;
 550	} else if (property == config->prop_src_x) {
 551		state->src_x = val;
 552	} else if (property == config->prop_src_y) {
 553		state->src_y = val;
 554	} else if (property == config->prop_src_w) {
 555		state->src_w = val;
 556	} else if (property == config->prop_src_h) {
 557		state->src_h = val;
 558	} else if (property == plane->alpha_property) {
 559		state->alpha = val;
 560	} else if (property == plane->blend_mode_property) {
 561		state->pixel_blend_mode = val;
 562	} else if (property == plane->rotation_property) {
 563		if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
 564			drm_dbg_atomic(plane->dev,
 565				       "[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
 566				       plane->base.id, plane->name, val);
 567			return -EINVAL;
 568		}
 569		state->rotation = val;
 570	} else if (property == plane->zpos_property) {
 571		state->zpos = val;
 572	} else if (property == plane->color_encoding_property) {
 573		state->color_encoding = val;
 574	} else if (property == plane->color_range_property) {
 575		state->color_range = val;
 576	} else if (property == plane->color_pipeline_property) {
 577		/* find DRM colorop object */
 578		struct drm_colorop *colorop = NULL;
 579
 580		colorop = drm_colorop_find(dev, file_priv, val);
 581
 582		if (val && !colorop)
 583			return -EACCES;
 584
 585		drm_atomic_set_colorop_for_plane(state, colorop);
 586	} else if (property == config->prop_fb_damage_clips) {
 587		ret = drm_property_replace_blob_from_id(dev,
 588					&state->fb_damage_clips,
 589					val,
 590					-1,
 591					sizeof(struct drm_mode_rect),
 592					&replaced);
 593		return ret;
 594	} else if (property == plane->scaling_filter_property) {
 595		state->scaling_filter = val;
 596	} else if (plane->funcs->atomic_set_property) {
 597		return plane->funcs->atomic_set_property(plane, state,
 598				property, val);
 599	} else if (property == plane->hotspot_x_property) {
 600		if (plane->type != DRM_PLANE_TYPE_CURSOR) {
 601			drm_dbg_atomic(plane->dev,
 602				       "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n",
 603				       plane->base.id, plane->name, val);
 604			return -EINVAL;
 605		}
 606		state->hotspot_x = val;
 607	} else if (property == plane->hotspot_y_property) {
 608		if (plane->type != DRM_PLANE_TYPE_CURSOR) {
 609			drm_dbg_atomic(plane->dev,
 610				       "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n",
 611				       plane->base.id, plane->name, val);
 612			return -EINVAL;
 613		}
 614		state->hotspot_y = val;
 615	} else {
 616		drm_dbg_atomic(plane->dev,
 617			       "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
 618			       plane->base.id, plane->name,
 619			       property->base.id, property->name);
 620		return -EINVAL;
 621	}
 622
 623	return 0;
 624}
 625
 626static int
 627drm_atomic_plane_get_property(struct drm_plane *plane,
 628		const struct drm_plane_state *state,
 629		struct drm_property *property, uint64_t *val)
 630{
 631	struct drm_device *dev = plane->dev;
 632	struct drm_mode_config *config = &dev->mode_config;
 633
 634	if (property == config->prop_fb_id) {
 635		*val = (state->fb) ? state->fb->base.id : 0;
 636	} else if (property == config->prop_in_fence_fd) {
 637		*val = -1;
 638	} else if (property == config->prop_crtc_id) {
 639		*val = (state->crtc) ? state->crtc->base.id : 0;
 640	} else if (property == config->prop_crtc_x) {
 641		*val = I642U64(state->crtc_x);
 642	} else if (property == config->prop_crtc_y) {
 643		*val = I642U64(state->crtc_y);
 644	} else if (property == config->prop_crtc_w) {
 645		*val = state->crtc_w;
 646	} else if (property == config->prop_crtc_h) {
 647		*val = state->crtc_h;
 648	} else if (property == config->prop_src_x) {
 649		*val = state->src_x;
 650	} else if (property == config->prop_src_y) {
 651		*val = state->src_y;
 652	} else if (property == config->prop_src_w) {
 653		*val = state->src_w;
 654	} else if (property == config->prop_src_h) {
 655		*val = state->src_h;
 656	} else if (property == plane->alpha_property) {
 657		*val = state->alpha;
 658	} else if (property == plane->blend_mode_property) {
 659		*val = state->pixel_blend_mode;
 660	} else if (property == plane->rotation_property) {
 661		*val = state->rotation;
 662	} else if (property == plane->zpos_property) {
 663		*val = state->zpos;
 664	} else if (property == plane->color_encoding_property) {
 665		*val = state->color_encoding;
 666	} else if (property == plane->color_range_property) {
 667		*val = state->color_range;
 668	} else if (property == plane->color_pipeline_property) {
 669		*val = (state->color_pipeline) ? state->color_pipeline->base.id : 0;
 670	} else if (property == config->prop_fb_damage_clips) {
 671		*val = (state->fb_damage_clips) ?
 672			state->fb_damage_clips->base.id : 0;
 673	} else if (property == plane->scaling_filter_property) {
 674		*val = state->scaling_filter;
 675	} else if (plane->funcs->atomic_get_property) {
 676		return plane->funcs->atomic_get_property(plane, state, property, val);
 677	} else if (property == plane->hotspot_x_property) {
 678		*val = state->hotspot_x;
 679	} else if (property == plane->hotspot_y_property) {
 680		*val = state->hotspot_y;
 681	} else {
 682		drm_dbg_atomic(dev,
 683			       "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
 684			       plane->base.id, plane->name,
 685			       property->base.id, property->name);
 686		return -EINVAL;
 687	}
 688
 689	return 0;
 690}
 691
 692static int drm_atomic_color_set_data_property(struct drm_colorop *colorop,
 693					      struct drm_colorop_state *state,
 694					      struct drm_property *property,
 695					      uint64_t val)
 696{
 697	ssize_t elem_size = -1;
 698	ssize_t size = -1;
 699	bool replaced = false;
 700
 701	switch (colorop->type) {
 702	case DRM_COLOROP_1D_LUT:
 703		size = colorop->size * sizeof(struct drm_color_lut32);
 704		break;
 705	case DRM_COLOROP_CTM_3X4:
 706		size = sizeof(struct drm_color_ctm_3x4);
 707		break;
 708	case DRM_COLOROP_3D_LUT:
 709		size = colorop->size * colorop->size * colorop->size *
 710		       sizeof(struct drm_color_lut32);
 711		break;
 712	default:
 713		/* should never get here */
 714		return -EINVAL;
 715	}
 716
 717	return drm_property_replace_blob_from_id(colorop->dev,
 718						 &state->data,
 719						 val,
 720						 size,
 721						 elem_size,
 722						 &replaced);
 723}
 724
 725static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
 726					   struct drm_colorop_state *state,
 727					   struct drm_file *file_priv,
 728					   struct drm_property *property,
 729					   uint64_t val)
 730{
 731	if (property == colorop->bypass_property) {
 732		state->bypass = val;
 733	} else if (property == colorop->lut1d_interpolation_property) {
 734		colorop->lut1d_interpolation = val;
 735	} else if (property == colorop->curve_1d_type_property) {
 736		state->curve_1d_type = val;
 737	} else if (property == colorop->multiplier_property) {
 738		state->multiplier = val;
 739	} else if (property == colorop->lut3d_interpolation_property) {
 740		colorop->lut3d_interpolation = val;
 741	} else if (property == colorop->data_property) {
 742		return drm_atomic_color_set_data_property(colorop, state,
 743							  property, val);
 744	} else {
 745		drm_dbg_atomic(colorop->dev,
 746			       "[COLOROP:%d:%d] unknown property [PROP:%d:%s]\n",
 747			       colorop->base.id, colorop->type,
 748			       property->base.id, property->name);
 749		return -EINVAL;
 750	}
 751
 752	return 0;
 753}
 754
 755static int
 756drm_atomic_colorop_get_property(struct drm_colorop *colorop,
 757				const struct drm_colorop_state *state,
 758				struct drm_property *property, uint64_t *val)
 759{
 760	if (property == colorop->type_property)
 761		*val = colorop->type;
 762	else if (property == colorop->bypass_property)
 763		*val = state->bypass;
 764	else if (property == colorop->lut1d_interpolation_property)
 765		*val = colorop->lut1d_interpolation;
 766	else if (property == colorop->curve_1d_type_property)
 767		*val = state->curve_1d_type;
 768	else if (property == colorop->multiplier_property)
 769		*val = state->multiplier;
 770	else if (property == colorop->size_property)
 771		*val = colorop->size;
 772	else if (property == colorop->lut3d_interpolation_property)
 773		*val = colorop->lut3d_interpolation;
 774	else if (property == colorop->data_property)
 775		*val = (state->data) ? state->data->base.id : 0;
 776	else
 777		return -EINVAL;
 778
 779	return 0;
 780}
 781
 782static int drm_atomic_set_writeback_fb_for_connector(
 783		struct drm_connector_state *conn_state,
 784		struct drm_framebuffer *fb)
 785{
 786	int ret;
 787	struct drm_connector *conn = conn_state->connector;
 788
 789	ret = drm_writeback_set_fb(conn_state, fb);
 790	if (ret < 0)
 791		return ret;
 792
 793	if (fb)
 794		drm_dbg_atomic(conn->dev,
 795			       "Set [FB:%d] for connector state %p\n",
 796			       fb->base.id, conn_state);
 797	else
 798		drm_dbg_atomic(conn->dev,
 799			       "Set [NOFB] for connector state %p\n",
 800			       conn_state);
 801
 802	return 0;
 803}
 804
 805static int drm_atomic_connector_set_property(struct drm_connector *connector,
 806		struct drm_connector_state *state, struct drm_file *file_priv,
 807		struct drm_property *property, uint64_t val)
 808{
 809	struct drm_device *dev = connector->dev;
 810	struct drm_mode_config *config = &dev->mode_config;
 811	bool replaced = false;
 812	int ret;
 813
 814	if (property == config->prop_crtc_id) {
 815		struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
 816
 817		if (val && !crtc) {
 818			drm_dbg_atomic(dev,
 819				       "[PROP:%d:%s] cannot find CRTC with ID %llu\n",
 820				       property->base.id, property->name, val);
 821			return -EACCES;
 822		}
 823		return drm_atomic_set_crtc_for_connector(state, crtc);
 824	} else if (property == config->dpms_property) {
 825		/* setting DPMS property requires special handling, which
 826		 * is done in legacy setprop path for us.  Disallow (for
 827		 * now?) atomic writes to DPMS property:
 828		 */
 829		drm_dbg_atomic(dev,
 830			       "legacy [PROP:%d:%s] can only be set via legacy uAPI\n",
 831			       property->base.id, property->name);
 832		return -EINVAL;
 833	} else if (property == config->tv_select_subconnector_property) {
 834		state->tv.select_subconnector = val;
 835	} else if (property == config->tv_subconnector_property) {
 836		state->tv.subconnector = val;
 837	} else if (property == config->tv_left_margin_property) {
 838		state->tv.margins.left = val;
 839	} else if (property == config->tv_right_margin_property) {
 840		state->tv.margins.right = val;
 841	} else if (property == config->tv_top_margin_property) {
 842		state->tv.margins.top = val;
 843	} else if (property == config->tv_bottom_margin_property) {
 844		state->tv.margins.bottom = val;
 845	} else if (property == config->legacy_tv_mode_property) {
 846		state->tv.legacy_mode = val;
 847	} else if (property == config->tv_mode_property) {
 848		state->tv.mode = val;
 849	} else if (property == config->tv_brightness_property) {
 850		state->tv.brightness = val;
 851	} else if (property == config->tv_contrast_property) {
 852		state->tv.contrast = val;
 853	} else if (property == config->tv_flicker_reduction_property) {
 854		state->tv.flicker_reduction = val;
 855	} else if (property == config->tv_overscan_property) {
 856		state->tv.overscan = val;
 857	} else if (property == config->tv_saturation_property) {
 858		state->tv.saturation = val;
 859	} else if (property == config->tv_hue_property) {
 860		state->tv.hue = val;
 861	} else if (property == config->link_status_property) {
 862		/* Never downgrade from GOOD to BAD on userspace's request here,
 863		 * only hw issues can do that.
 864		 *
 865		 * For an atomic property the userspace doesn't need to be able
 866		 * to understand all the properties, but needs to be able to
 867		 * restore the state it wants on VT switch. So if the userspace
 868		 * tries to change the link_status from GOOD to BAD, driver
 869		 * silently rejects it and returns a 0. This prevents userspace
 870		 * from accidentally breaking  the display when it restores the
 871		 * state.
 872		 */
 873		if (state->link_status != DRM_LINK_STATUS_GOOD)
 874			state->link_status = val;
 875	} else if (property == config->hdr_output_metadata_property) {
 876		ret = drm_property_replace_blob_from_id(dev,
 877				&state->hdr_output_metadata,
 878				val,
 879				sizeof(struct hdr_output_metadata), -1,
 880				&replaced);
 881		return ret;
 882	} else if (property == config->aspect_ratio_property) {
 883		state->picture_aspect_ratio = val;
 884	} else if (property == config->content_type_property) {
 885		state->content_type = val;
 886	} else if (property == connector->scaling_mode_property) {
 887		state->scaling_mode = val;
 888	} else if (property == config->content_protection_property) {
 889		if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
 890			drm_dbg_kms(dev, "only drivers can set CP Enabled\n");
 891			return -EINVAL;
 892		}
 893		state->content_protection = val;
 894	} else if (property == config->hdcp_content_type_property) {
 895		state->hdcp_content_type = val;
 896	} else if (property == connector->colorspace_property) {
 897		state->colorspace = val;
 898	} else if (property == config->writeback_fb_id_property) {
 899		struct drm_framebuffer *fb;
 900		int ret;
 901
 902		fb = drm_framebuffer_lookup(dev, file_priv, val);
 903		ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
 904		if (fb)
 905			drm_framebuffer_put(fb);
 906		return ret;
 907	} else if (property == config->writeback_out_fence_ptr_property) {
 908		s32 __user *fence_ptr = u64_to_user_ptr(val);
 909
 910		return set_out_fence_for_connector(state->state, connector,
 911						   fence_ptr);
 912	} else if (property == connector->max_bpc_property) {
 913		state->max_requested_bpc = val;
 914	} else if (property == connector->privacy_screen_sw_state_property) {
 915		state->privacy_screen_sw_state = val;
 916	} else if (property == connector->broadcast_rgb_property) {
 917		state->hdmi.broadcast_rgb = val;
 918	} else if (connector->funcs->atomic_set_property) {
 919		return connector->funcs->atomic_set_property(connector,
 920				state, property, val);
 921	} else {
 922		drm_dbg_atomic(connector->dev,
 923			       "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n",
 924			       connector->base.id, connector->name,
 925			       property->base.id, property->name);
 926		return -EINVAL;
 927	}
 928
 929	return 0;
 930}
 931
 932static int
 933drm_atomic_connector_get_property(struct drm_connector *connector,
 934		const struct drm_connector_state *state,
 935		struct drm_property *property, uint64_t *val)
 936{
 937	struct drm_device *dev = connector->dev;
 938	struct drm_mode_config *config = &dev->mode_config;
 939
 940	if (property == config->prop_crtc_id) {
 941		*val = (state->crtc) ? state->crtc->base.id : 0;
 942	} else if (property == config->dpms_property) {
 943		if (state->crtc && state->crtc->state->self_refresh_active)
 944			*val = DRM_MODE_DPMS_ON;
 945		else
 946			*val = connector->dpms;
 947	} else if (property == config->tv_select_subconnector_property) {
 948		*val = state->tv.select_subconnector;
 949	} else if (property == config->tv_subconnector_property) {
 950		*val = state->tv.subconnector;
 951	} else if (property == config->tv_left_margin_property) {
 952		*val = state->tv.margins.left;
 953	} else if (property == config->tv_right_margin_property) {
 954		*val = state->tv.margins.right;
 955	} else if (property == config->tv_top_margin_property) {
 956		*val = state->tv.margins.top;
 957	} else if (property == config->tv_bottom_margin_property) {
 958		*val = state->tv.margins.bottom;
 959	} else if (property == config->legacy_tv_mode_property) {
 960		*val = state->tv.legacy_mode;
 961	} else if (property == config->tv_mode_property) {
 962		*val = state->tv.mode;
 963	} else if (property == config->tv_brightness_property) {
 964		*val = state->tv.brightness;
 965	} else if (property == config->tv_contrast_property) {
 966		*val = state->tv.contrast;
 967	} else if (property == config->tv_flicker_reduction_property) {
 968		*val = state->tv.flicker_reduction;
 969	} else if (property == config->tv_overscan_property) {
 970		*val = state->tv.overscan;
 971	} else if (property == config->tv_saturation_property) {
 972		*val = state->tv.saturation;
 973	} else if (property == config->tv_hue_property) {
 974		*val = state->tv.hue;
 975	} else if (property == config->link_status_property) {
 976		*val = state->link_status;
 977	} else if (property == config->aspect_ratio_property) {
 978		*val = state->picture_aspect_ratio;
 979	} else if (property == config->content_type_property) {
 980		*val = state->content_type;
 981	} else if (property == connector->colorspace_property) {
 982		*val = state->colorspace;
 983	} else if (property == connector->scaling_mode_property) {
 984		*val = state->scaling_mode;
 985	} else if (property == config->hdr_output_metadata_property) {
 986		*val = state->hdr_output_metadata ?
 987			state->hdr_output_metadata->base.id : 0;
 988	} else if (property == config->content_protection_property) {
 989		*val = state->content_protection;
 990	} else if (property == config->hdcp_content_type_property) {
 991		*val = state->hdcp_content_type;
 992	} else if (property == config->writeback_fb_id_property) {
 993		/* Writeback framebuffer is one-shot, write and forget */
 994		*val = 0;
 995	} else if (property == config->writeback_out_fence_ptr_property) {
 996		*val = 0;
 997	} else if (property == connector->max_bpc_property) {
 998		*val = state->max_requested_bpc;
 999	} else if (property == connector->privacy_screen_sw_state_property) {
1000		*val = state->privacy_screen_sw_state;
1001	} else if (property == connector->broadcast_rgb_property) {
1002		*val = state->hdmi.broadcast_rgb;
1003	} else if (connector->funcs->atomic_get_property) {
1004		return connector->funcs->atomic_get_property(connector,
1005				state, property, val);
1006	} else {
1007		drm_dbg_atomic(dev,
1008			       "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n",
1009			       connector->base.id, connector->name,
1010			       property->base.id, property->name);
1011		return -EINVAL;
1012	}
1013
1014	return 0;
1015}
1016
1017int drm_atomic_get_property(struct drm_mode_object *obj,
1018		struct drm_property *property, uint64_t *val)
1019{
1020	struct drm_device *dev = property->dev;
1021	int ret;
1022
1023	switch (obj->type) {
1024	case DRM_MODE_OBJECT_CONNECTOR: {
1025		struct drm_connector *connector = obj_to_connector(obj);
1026
1027		WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
1028		ret = drm_atomic_connector_get_property(connector,
1029				connector->state, property, val);
1030		break;
1031	}
1032	case DRM_MODE_OBJECT_CRTC: {
1033		struct drm_crtc *crtc = obj_to_crtc(obj);
1034
1035		WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
1036		ret = drm_atomic_crtc_get_property(crtc,
1037				crtc->state, property, val);
1038		break;
1039	}
1040	case DRM_MODE_OBJECT_PLANE: {
1041		struct drm_plane *plane = obj_to_plane(obj);
1042
1043		WARN_ON(!drm_modeset_is_locked(&plane->mutex));
1044		ret = drm_atomic_plane_get_property(plane,
1045				plane->state, property, val);
1046		break;
1047	}
1048	case DRM_MODE_OBJECT_COLOROP: {
1049		struct drm_colorop *colorop = obj_to_colorop(obj);
1050
1051		if (colorop->plane)
1052			WARN_ON(!drm_modeset_is_locked(&colorop->plane->mutex));
1053
1054		ret = drm_atomic_colorop_get_property(colorop, colorop->state, property, val);
1055		break;
1056	}
1057	default:
1058		drm_dbg_atomic(dev, "[OBJECT:%d] has no properties\n", obj->id);
1059		ret = -EINVAL;
1060		break;
1061	}
1062
1063	return ret;
1064}
1065
1066/*
1067 * The big monster ioctl
1068 */
1069
1070static struct drm_pending_vblank_event *create_vblank_event(
1071		struct drm_crtc *crtc, uint64_t user_data)
1072{
1073	struct drm_pending_vblank_event *e = NULL;
1074
1075	e = kzalloc(sizeof *e, GFP_KERNEL);
1076	if (!e)
1077		return NULL;
1078
1079	e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1080	e->event.base.length = sizeof(e->event);
1081	e->event.vbl.crtc_id = crtc->base.id;
1082	e->event.vbl.user_data = user_data;
1083
1084	return e;
1085}
1086
1087int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
1088				     struct drm_connector *connector,
1089				     int mode)
1090{
1091	struct drm_connector *tmp_connector;
1092	struct drm_connector_state *new_conn_state;
1093	struct drm_crtc *crtc;
1094	struct drm_crtc_state *crtc_state;
1095	int i, ret, old_mode = connector->dpms;
1096	bool active = false;
1097
1098	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
1099			       state->acquire_ctx);
1100	if (ret)
1101		return ret;
1102
1103	if (mode != DRM_MODE_DPMS_ON)
1104		mode = DRM_MODE_DPMS_OFF;
1105
1106	if (connector->dpms == mode)
1107		goto out;
1108
1109	connector->dpms = mode;
1110
1111	crtc = connector->state->crtc;
1112	if (!crtc)
1113		goto out;
1114	ret = drm_atomic_add_affected_connectors(state, crtc);
1115	if (ret)
1116		goto out;
1117
1118	crtc_state = drm_atomic_get_crtc_state(state, crtc);
1119	if (IS_ERR(crtc_state)) {
1120		ret = PTR_ERR(crtc_state);
1121		goto out;
1122	}
1123
1124	for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
1125		if (new_conn_state->crtc != crtc)
1126			continue;
1127		if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
1128			active = true;
1129			break;
1130		}
1131	}
1132
1133	crtc_state->active = active;
1134	ret = drm_atomic_commit(state);
1135out:
1136	if (ret != 0)
1137		connector->dpms = old_mode;
1138	return ret;
1139}
1140
1141static int drm_atomic_check_prop_changes(int ret, uint64_t old_val, uint64_t prop_value,
1142					 struct drm_property *prop)
1143{
1144	if (ret != 0 || old_val != prop_value) {
1145		drm_dbg_atomic(prop->dev,
1146			       "[PROP:%d:%s] No prop can be changed during async flip\n",
1147			       prop->base.id, prop->name);
1148		return -EINVAL;
1149	}
1150
1151	return 0;
1152}
1153
1154int drm_atomic_set_property(struct drm_atomic_state *state,
1155			    struct drm_file *file_priv,
1156			    struct drm_mode_object *obj,
1157			    struct drm_property *prop,
1158			    u64 prop_value,
1159			    bool async_flip)
1160{
1161	struct drm_mode_object *ref;
1162	u64 old_val;
1163	int ret;
1164
1165	if (!drm_property_change_valid_get(prop, prop_value, &ref))
1166		return -EINVAL;
1167
1168	switch (obj->type) {
1169	case DRM_MODE_OBJECT_CONNECTOR: {
1170		struct drm_connector *connector = obj_to_connector(obj);
1171		struct drm_connector_state *connector_state;
1172
1173		connector_state = drm_atomic_get_connector_state(state, connector);
1174		if (IS_ERR(connector_state)) {
1175			ret = PTR_ERR(connector_state);
1176			break;
1177		}
1178
1179		if (async_flip) {
1180			ret = drm_atomic_connector_get_property(connector, connector_state,
1181								prop, &old_val);
1182			ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
1183			break;
1184		}
1185
1186		ret = drm_atomic_connector_set_property(connector,
1187				connector_state, file_priv,
1188				prop, prop_value);
1189		break;
1190	}
1191	case DRM_MODE_OBJECT_CRTC: {
1192		struct drm_crtc *crtc = obj_to_crtc(obj);
1193		struct drm_crtc_state *crtc_state;
1194
1195		crtc_state = drm_atomic_get_crtc_state(state, crtc);
1196		if (IS_ERR(crtc_state)) {
1197			ret = PTR_ERR(crtc_state);
1198			break;
1199		}
1200
1201		if (async_flip) {
1202			ret = drm_atomic_crtc_get_property(crtc, crtc_state,
1203							   prop, &old_val);
1204			ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
1205			break;
1206		}
1207
1208		ret = drm_atomic_crtc_set_property(crtc,
1209				crtc_state, prop, prop_value);
1210		break;
1211	}
1212	case DRM_MODE_OBJECT_PLANE: {
1213		struct drm_plane *plane = obj_to_plane(obj);
1214		struct drm_plane_state *plane_state;
1215		struct drm_mode_config *config = &plane->dev->mode_config;
1216		const struct drm_plane_helper_funcs *plane_funcs = plane->helper_private;
1217
1218		plane_state = drm_atomic_get_plane_state(state, plane);
1219		if (IS_ERR(plane_state)) {
1220			ret = PTR_ERR(plane_state);
1221			break;
1222		}
1223
1224		if (async_flip) {
1225			/* no-op changes are always allowed */
1226			ret = drm_atomic_plane_get_property(plane, plane_state,
1227							    prop, &old_val);
1228			ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
1229
1230			/* fail everything that isn't no-op or a pure flip */
1231			if (ret && prop != config->prop_fb_id &&
1232			    prop != config->prop_in_fence_fd &&
1233			    prop != config->prop_fb_damage_clips) {
1234				break;
1235			}
1236
1237			if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY) {
1238				/* ask the driver if this non-primary plane is supported */
1239				if (plane_funcs && plane_funcs->atomic_async_check)
1240					ret = plane_funcs->atomic_async_check(plane, state, true);
1241
1242				if (ret) {
1243					drm_dbg_atomic(prop->dev,
1244						       "[PLANE:%d:%s] does not support async flips\n",
1245						       obj->id, plane->name);
1246					break;
1247				}
1248			}
1249		}
1250
1251		ret = drm_atomic_plane_set_property(plane,
1252				plane_state, file_priv,
1253				prop, prop_value);
1254
1255		break;
1256	}
1257	case DRM_MODE_OBJECT_COLOROP: {
1258		struct drm_colorop *colorop = obj_to_colorop(obj);
1259		struct drm_colorop_state *colorop_state;
1260
1261		colorop_state = drm_atomic_get_colorop_state(state, colorop);
1262		if (IS_ERR(colorop_state)) {
1263			ret = PTR_ERR(colorop_state);
1264			break;
1265		}
1266
1267		ret = drm_atomic_colorop_set_property(colorop, colorop_state,
1268						      file_priv, prop, prop_value);
1269		break;
1270	}
1271	default:
1272		drm_dbg_atomic(prop->dev, "[OBJECT:%d] has no properties\n", obj->id);
1273		ret = -EINVAL;
1274		break;
1275	}
1276
1277	drm_property_change_valid_put(prop, ref);
1278	return ret;
1279}
1280
1281/**
1282 * DOC: explicit fencing properties
1283 *
1284 * Explicit fencing allows userspace to control the buffer synchronization
1285 * between devices. A Fence or a group of fences are transferred to/from
1286 * userspace using Sync File fds and there are two DRM properties for that.
1287 * IN_FENCE_FD on each DRM Plane to send fences to the kernel and
1288 * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
1289 *
1290 * As a contrast, with implicit fencing the kernel keeps track of any
1291 * ongoing rendering, and automatically ensures that the atomic update waits
1292 * for any pending rendering to complete. This is usually tracked in &struct
1293 * dma_resv which can also contain mandatory kernel fences. Implicit syncing
1294 * is how Linux traditionally worked (e.g. DRI2/3 on X.org), whereas explicit
1295 * fencing is what Android wants.
1296 *
1297 * "IN_FENCE_FD”:
1298 *	Use this property to pass a fence that DRM should wait on before
1299 *	proceeding with the Atomic Commit request and show the framebuffer for
1300 *	the plane on the screen. The fence can be either a normal fence or a
1301 *	merged one, the sync_file framework will handle both cases and use a
1302 *	fence_array if a merged fence is received. Passing -1 here means no
1303 *	fences to wait on.
1304 *
1305 *	If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag
1306 *	it will only check if the Sync File is a valid one.
1307 *
1308 *	On the driver side the fence is stored on the @fence parameter of
1309 *	&struct drm_plane_state. Drivers which also support implicit fencing
1310 *	should extract the implicit fence using drm_gem_plane_helper_prepare_fb(),
1311 *	to make sure there's consistent behaviour between drivers in precedence
1312 *	of implicit vs. explicit fencing.
1313 *
1314 * "OUT_FENCE_PTR”:
1315 *	Use this property to pass a file descriptor pointer to DRM. Once the
1316 *	Atomic Commit request call returns OUT_FENCE_PTR will be filled with
1317 *	the file descriptor number of a Sync File. This Sync File contains the
1318 *	CRTC fence that will be signaled when all framebuffers present on the
1319 *	Atomic Commit * request for that given CRTC are scanned out on the
1320 *	screen.
1321 *
1322 *	The Atomic Commit request fails if a invalid pointer is passed. If the
1323 *	Atomic Commit request fails for any other reason the out fence fd
1324 *	returned will be -1. On a Atomic Commit with the
1325 *	DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1.
1326 *
1327 *	Note that out-fences don't have a special interface to drivers and are
1328 *	internally represented by a &struct drm_pending_vblank_event in struct
1329 *	&drm_crtc_state, which is also used by the nonblocking atomic commit
1330 *	helpers and for the DRM event handling for existing userspace.
1331 */
1332
1333struct drm_out_fence_state {
1334	s32 __user *out_fence_ptr;
1335	struct sync_file *sync_file;
1336	int fd;
1337};
1338
1339static int setup_out_fence(struct drm_out_fence_state *fence_state,
1340			   struct dma_fence *fence)
1341{
1342	fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1343	if (fence_state->fd < 0)
1344		return fence_state->fd;
1345
1346	if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1347		return -EFAULT;
1348
1349	fence_state->sync_file = sync_file_create(fence);
1350	if (!fence_state->sync_file)
1351		return -ENOMEM;
1352
1353	return 0;
1354}
1355
1356static int prepare_signaling(struct drm_device *dev,
1357				  struct drm_atomic_state *state,
1358				  struct drm_mode_atomic *arg,
1359				  struct drm_file *file_priv,
1360				  struct drm_out_fence_state **fence_state,
1361				  unsigned int *num_fences)
1362{
1363	struct drm_crtc *crtc;
1364	struct drm_crtc_state *crtc_state;
1365	struct drm_connector *conn;
1366	struct drm_connector_state *conn_state;
1367	int i, c = 0, ret;
1368
1369	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1370		return 0;
1371
1372	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1373		s32 __user *fence_ptr;
1374
1375		fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1376
1377		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1378			struct drm_pending_vblank_event *e;
1379
1380			e = create_vblank_event(crtc, arg->user_data);
1381			if (!e)
1382				return -ENOMEM;
1383
1384			crtc_state->event = e;
1385		}
1386
1387		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1388			struct drm_pending_vblank_event *e = crtc_state->event;
1389
1390			if (!file_priv)
1391				continue;
1392
1393			ret = drm_event_reserve_init(dev, file_priv, &e->base,
1394						     &e->event.base);
1395			if (ret) {
1396				kfree(e);
1397				crtc_state->event = NULL;
1398				return ret;
1399			}
1400		}
1401
1402		if (fence_ptr) {
1403			struct dma_fence *fence;
1404			struct drm_out_fence_state *f;
1405
1406			f = krealloc(*fence_state, sizeof(**fence_state) *
1407				     (*num_fences + 1), GFP_KERNEL);
1408			if (!f)
1409				return -ENOMEM;
1410
1411			memset(&f[*num_fences], 0, sizeof(*f));
1412
1413			f[*num_fences].out_fence_ptr = fence_ptr;
1414			*fence_state = f;
1415
1416			fence = drm_crtc_create_fence(crtc);
1417			if (!fence)
1418				return -ENOMEM;
1419
1420			ret = setup_out_fence(&f[(*num_fences)++], fence);
1421			if (ret) {
1422				dma_fence_put(fence);
1423				return ret;
1424			}
1425
1426			crtc_state->event->base.fence = fence;
1427		}
1428
1429		c++;
1430	}
1431
1432	for_each_new_connector_in_state(state, conn, conn_state, i) {
1433		struct drm_writeback_connector *wb_conn;
1434		struct drm_out_fence_state *f;
1435		struct dma_fence *fence;
1436		s32 __user *fence_ptr;
1437
1438		if (!conn_state->writeback_job)
1439			continue;
1440
1441		fence_ptr = get_out_fence_for_connector(state, conn);
1442		if (!fence_ptr)
1443			continue;
1444
1445		f = krealloc(*fence_state, sizeof(**fence_state) *
1446			     (*num_fences + 1), GFP_KERNEL);
1447		if (!f)
1448			return -ENOMEM;
1449
1450		memset(&f[*num_fences], 0, sizeof(*f));
1451
1452		f[*num_fences].out_fence_ptr = fence_ptr;
1453		*fence_state = f;
1454
1455		wb_conn = drm_connector_to_writeback(conn);
1456		fence = drm_writeback_get_out_fence(wb_conn);
1457		if (!fence)
1458			return -ENOMEM;
1459
1460		ret = setup_out_fence(&f[(*num_fences)++], fence);
1461		if (ret) {
1462			dma_fence_put(fence);
1463			return ret;
1464		}
1465
1466		conn_state->writeback_job->out_fence = fence;
1467	}
1468
1469	/*
1470	 * Having this flag means user mode pends on event which will never
1471	 * reach due to lack of at least one CRTC for signaling
1472	 */
1473	if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
1474		drm_dbg_atomic(dev, "need at least one CRTC for DRM_MODE_PAGE_FLIP_EVENT");
1475		return -EINVAL;
1476	}
1477
1478	return 0;
1479}
1480
1481static void complete_signaling(struct drm_device *dev,
1482			       struct drm_atomic_state *state,
1483			       struct drm_out_fence_state *fence_state,
1484			       unsigned int num_fences,
1485			       bool install_fds)
1486{
1487	struct drm_crtc *crtc;
1488	struct drm_crtc_state *crtc_state;
1489	int i;
1490
1491	if (install_fds) {
1492		for (i = 0; i < num_fences; i++)
1493			fd_install(fence_state[i].fd,
1494				   fence_state[i].sync_file->file);
1495
1496		kfree(fence_state);
1497		return;
1498	}
1499
1500	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1501		struct drm_pending_vblank_event *event = crtc_state->event;
1502		/*
1503		 * Free the allocated event. drm_atomic_helper_setup_commit
1504		 * can allocate an event too, so only free it if it's ours
1505		 * to prevent a double free in drm_atomic_state_clear.
1506		 */
1507		if (event && (event->base.fence || event->base.file_priv)) {
1508			drm_event_cancel_free(dev, &event->base);
1509			crtc_state->event = NULL;
1510		}
1511	}
1512
1513	if (!fence_state)
1514		return;
1515
1516	for (i = 0; i < num_fences; i++) {
1517		if (fence_state[i].sync_file)
1518			fput(fence_state[i].sync_file->file);
1519		if (fence_state[i].fd >= 0)
1520			put_unused_fd(fence_state[i].fd);
1521
1522		/* If this fails log error to the user */
1523		if (fence_state[i].out_fence_ptr &&
1524		    put_user(-1, fence_state[i].out_fence_ptr))
1525			drm_dbg_atomic(dev, "Couldn't clear out_fence_ptr\n");
1526	}
1527
1528	kfree(fence_state);
1529}
1530
1531static void
1532set_async_flip(struct drm_atomic_state *state)
1533{
1534	struct drm_crtc *crtc;
1535	struct drm_crtc_state *crtc_state;
1536	int i;
1537
1538	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1539		crtc_state->async_flip = true;
1540	}
1541}
1542
1543int drm_mode_atomic_ioctl(struct drm_device *dev,
1544			  void *data, struct drm_file *file_priv)
1545{
1546	struct drm_mode_atomic *arg = data;
1547	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
1548	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
1549	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
1550	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
1551	unsigned int copied_objs, copied_props;
1552	struct drm_atomic_state *state;
1553	struct drm_modeset_acquire_ctx ctx;
1554	struct drm_out_fence_state *fence_state;
1555	int ret = 0;
1556	unsigned int i, j, num_fences;
1557	bool async_flip = false;
1558
1559	/* disallow for drivers not supporting atomic: */
1560	if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
1561		return -EOPNOTSUPP;
1562
1563	/* disallow for userspace that has not enabled atomic cap (even
1564	 * though this may be a bit overkill, since legacy userspace
1565	 * wouldn't know how to call this ioctl)
1566	 */
1567	if (!file_priv->atomic) {
1568		drm_dbg_atomic(dev,
1569			       "commit failed: atomic cap not enabled\n");
1570		return -EINVAL;
1571	}
1572
1573	if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) {
1574		drm_dbg_atomic(dev, "commit failed: invalid flag\n");
1575		return -EINVAL;
1576	}
1577
1578	if (arg->reserved) {
1579		drm_dbg_atomic(dev, "commit failed: reserved field set\n");
1580		return -EINVAL;
1581	}
1582
1583	if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1584		if (!dev->mode_config.async_page_flip) {
1585			drm_dbg_atomic(dev,
1586				       "commit failed: DRM_MODE_PAGE_FLIP_ASYNC not supported\n");
1587			return -EINVAL;
1588		}
1589
1590		async_flip = true;
1591	}
1592
1593	/* can't test and expect an event at the same time. */
1594	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
1595			(arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
1596		drm_dbg_atomic(dev,
1597			       "commit failed: page-flip event requested with test-only commit\n");
1598		return -EINVAL;
1599	}
1600
1601	state = drm_atomic_state_alloc(dev);
1602	if (!state)
1603		return -ENOMEM;
1604
1605	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
1606	state->acquire_ctx = &ctx;
1607	state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
1608	state->plane_color_pipeline = file_priv->plane_color_pipeline;
1609
1610retry:
1611	copied_objs = 0;
1612	copied_props = 0;
1613	fence_state = NULL;
1614	num_fences = 0;
1615
1616	for (i = 0; i < arg->count_objs; i++) {
1617		uint32_t obj_id, count_props;
1618		struct drm_mode_object *obj;
1619
1620		if (get_user(obj_id, objs_ptr + copied_objs)) {
1621			ret = -EFAULT;
1622			goto out;
1623		}
1624
1625		obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
1626		if (!obj) {
1627			drm_dbg_atomic(dev, "cannot find object ID %d", obj_id);
1628			ret = -ENOENT;
1629			goto out;
1630		}
1631
1632		if (!obj->properties) {
1633			drm_dbg_atomic(dev, "[OBJECT:%d] has no properties", obj_id);
1634			drm_mode_object_put(obj);
1635			ret = -ENOENT;
1636			goto out;
1637		}
1638
1639		if (get_user(count_props, count_props_ptr + copied_objs)) {
1640			drm_mode_object_put(obj);
1641			ret = -EFAULT;
1642			goto out;
1643		}
1644
1645		copied_objs++;
1646
1647		for (j = 0; j < count_props; j++) {
1648			uint32_t prop_id;
1649			uint64_t prop_value;
1650			struct drm_property *prop;
1651
1652			if (get_user(prop_id, props_ptr + copied_props)) {
1653				drm_mode_object_put(obj);
1654				ret = -EFAULT;
1655				goto out;
1656			}
1657
1658			prop = drm_mode_obj_find_prop_id(obj, prop_id);
1659			if (!prop) {
1660				drm_dbg_atomic(dev,
1661					       "[OBJECT:%d] cannot find property ID %d",
1662					       obj_id, prop_id);
1663				drm_mode_object_put(obj);
1664				ret = -ENOENT;
1665				goto out;
1666			}
1667
1668			if (copy_from_user(&prop_value,
1669					   prop_values_ptr + copied_props,
1670					   sizeof(prop_value))) {
1671				drm_mode_object_put(obj);
1672				ret = -EFAULT;
1673				goto out;
1674			}
1675
1676			ret = drm_atomic_set_property(state, file_priv, obj,
1677						      prop, prop_value, async_flip);
1678			if (ret) {
1679				drm_mode_object_put(obj);
1680				goto out;
1681			}
1682
1683			copied_props++;
1684		}
1685
1686		drm_mode_object_put(obj);
1687	}
1688
1689	ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
1690				&num_fences);
1691	if (ret)
1692		goto out;
1693
1694	if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC)
1695		set_async_flip(state);
1696
1697	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1698		ret = drm_atomic_check_only(state);
1699	} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
1700		ret = drm_atomic_nonblocking_commit(state);
1701	} else {
1702		ret = drm_atomic_commit(state);
1703	}
1704
1705out:
1706	complete_signaling(dev, state, fence_state, num_fences, !ret);
1707
1708	if (ret == -EDEADLK) {
1709		drm_atomic_state_clear(state);
1710		ret = drm_modeset_backoff(&ctx);
1711		if (!ret)
1712			goto retry;
1713	}
1714
1715	drm_atomic_state_put(state);
1716
1717	drm_modeset_drop_locks(&ctx);
1718	drm_modeset_acquire_fini(&ctx);
1719
1720	return ret;
1721}
~/ Read-only file preview.