aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2014-12-18 16:01:51 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-01-05 07:55:27 -0500
commit5e743737421fe9be9d7b25475427a3698e6f70a5 (patch)
treefbe422bfdd6a7df29489ecba3a8b66ec263cd938
parent88a48e297b3a3bac6022c03babfb038f1a886cea (diff)
drm/atomic: atomic_check functions
Add functions to check core plane/crtc state. v2: comments, int-overflow checks, call from core rather than helpers to be sure drivers can't find a way to bypass core checks Signed-off-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_atomic.c139
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c4
2 files changed, 137 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index ce3c681d60f8..1c472b1baeb8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -269,6 +269,29 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
269EXPORT_SYMBOL(drm_atomic_crtc_get_property); 269EXPORT_SYMBOL(drm_atomic_crtc_get_property);
270 270
271/** 271/**
272 * drm_atomic_crtc_check - check crtc state
273 * @crtc: crtc to check
274 * @state: crtc state to check
275 *
276 * Provides core sanity checks for crtc state.
277 *
278 * RETURNS:
279 * Zero on success, error code on failure
280 */
281static int drm_atomic_crtc_check(struct drm_crtc *crtc,
282 struct drm_crtc_state *state)
283{
284 /* NOTE: we explicitly don't enforce constraints such as primary
285 * layer covering entire screen, since that is something we want
286 * to allow (on hw that supports it). For hw that does not, it
287 * should be checked in driver's crtc->atomic_check() vfunc.
288 *
289 * TODO: Add generic modeset state checks once we support those.
290 */
291 return 0;
292}
293
294/**
272 * drm_atomic_get_plane_state - get plane state 295 * drm_atomic_get_plane_state - get plane state
273 * @state: global atomic state object 296 * @state: global atomic state object
274 * @plane: plane to get state object for 297 * @plane: plane to get state object for
@@ -376,6 +399,82 @@ int drm_atomic_plane_get_property(struct drm_plane *plane,
376EXPORT_SYMBOL(drm_atomic_plane_get_property); 399EXPORT_SYMBOL(drm_atomic_plane_get_property);
377 400
378/** 401/**
402 * drm_atomic_plane_check - check plane state
403 * @plane: plane to check
404 * @state: plane state to check
405 *
406 * Provides core sanity checks for plane state.
407 *
408 * RETURNS:
409 * Zero on success, error code on failure
410 */
411static int drm_atomic_plane_check(struct drm_plane *plane,
412 struct drm_plane_state *state)
413{
414 unsigned int fb_width, fb_height;
415 unsigned int i;
416
417 /* either *both* CRTC and FB must be set, or neither */
418 if (WARN_ON(state->crtc && !state->fb)) {
419 DRM_DEBUG_KMS("CRTC set but no FB\n");
420 return -EINVAL;
421 } else if (WARN_ON(state->fb && !state->crtc)) {
422 DRM_DEBUG_KMS("FB set but no CRTC\n");
423 return -EINVAL;
424 }
425
426 /* if disabled, we don't care about the rest of the state: */
427 if (!state->crtc)
428 return 0;
429
430 /* Check whether this plane is usable on this CRTC */
431 if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
432 DRM_DEBUG_KMS("Invalid crtc for plane\n");
433 return -EINVAL;
434 }
435
436 /* Check whether this plane supports the fb pixel format. */
437 for (i = 0; i < plane->format_count; i++)
438 if (state->fb->pixel_format == plane->format_types[i])
439 break;
440 if (i == plane->format_count) {
441 DRM_DEBUG_KMS("Invalid pixel format %s\n",
442 drm_get_format_name(state->fb->pixel_format));
443 return -EINVAL;
444 }
445
446 /* Give drivers some help against integer overflows */
447 if (state->crtc_w > INT_MAX ||
448 state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
449 state->crtc_h > INT_MAX ||
450 state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
451 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
452 state->crtc_w, state->crtc_h,
453 state->crtc_x, state->crtc_y);
454 return -ERANGE;
455 }
456
457 fb_width = state->fb->width << 16;
458 fb_height = state->fb->height << 16;
459
460 /* Make sure source coordinates are inside the fb. */
461 if (state->src_w > fb_width ||
462 state->src_x > fb_width - state->src_w ||
463 state->src_h > fb_height ||
464 state->src_y > fb_height - state->src_h) {
465 DRM_DEBUG_KMS("Invalid source coordinates "
466 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
467 state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
468 state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
469 state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
470 state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
471 return -ENOSPC;
472 }
473
474 return 0;
475}
476
477/**
379 * drm_atomic_get_connector_state - get connector state 478 * drm_atomic_get_connector_state - get connector state
380 * @state: global atomic state object 479 * @state: global atomic state object
381 * @connector: connector to get state object for 480 * @connector: connector to get state object for
@@ -801,14 +900,46 @@ EXPORT_SYMBOL(drm_atomic_legacy_backoff);
801 */ 900 */
802int drm_atomic_check_only(struct drm_atomic_state *state) 901int drm_atomic_check_only(struct drm_atomic_state *state)
803{ 902{
804 struct drm_mode_config *config = &state->dev->mode_config; 903 struct drm_device *dev = state->dev;
904 struct drm_mode_config *config = &dev->mode_config;
905 int nplanes = config->num_total_plane;
906 int ncrtcs = config->num_crtc;
907 int i, ret = 0;
805 908
806 DRM_DEBUG_KMS("checking %p\n", state); 909 DRM_DEBUG_KMS("checking %p\n", state);
807 910
911 for (i = 0; i < nplanes; i++) {
912 struct drm_plane *plane = state->planes[i];
913
914 if (!plane)
915 continue;
916
917 ret = drm_atomic_plane_check(plane, state->plane_states[i]);
918 if (ret) {
919 DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n",
920 plane->base.id);
921 return ret;
922 }
923 }
924
925 for (i = 0; i < ncrtcs; i++) {
926 struct drm_crtc *crtc = state->crtcs[i];
927
928 if (!crtc)
929 continue;
930
931 ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
932 if (ret) {
933 DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n",
934 crtc->base.id);
935 return ret;
936 }
937 }
938
808 if (config->funcs->atomic_check) 939 if (config->funcs->atomic_check)
809 return config->funcs->atomic_check(state->dev, state); 940 ret = config->funcs->atomic_check(state->dev, state);
810 else 941
811 return 0; 942 return ret;
812} 943}
813EXPORT_SYMBOL(drm_atomic_check_only); 944EXPORT_SYMBOL(drm_atomic_check_only);
814 945
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 57e5540259cc..541ba833ed36 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -467,7 +467,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
467 467
468 ret = funcs->atomic_check(plane, plane_state); 468 ret = funcs->atomic_check(plane, plane_state);
469 if (ret) { 469 if (ret) {
470 DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n", 470 DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n",
471 plane->base.id); 471 plane->base.id);
472 return ret; 472 return ret;
473 } 473 }
@@ -487,7 +487,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
487 487
488 ret = funcs->atomic_check(crtc, state->crtc_states[i]); 488 ret = funcs->atomic_check(crtc, state->crtc_states[i]);
489 if (ret) { 489 if (ret) {
490 DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n", 490 DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n",
491 crtc->base.id); 491 crtc->base.id);
492 return ret; 492 return ret;
493 } 493 }