diff options
author | Rob Clark <robdclark@gmail.com> | 2014-12-18 16:01:51 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-01-05 07:55:27 -0500 |
commit | 5e743737421fe9be9d7b25475427a3698e6f70a5 (patch) | |
tree | fbe422bfdd6a7df29489ecba3a8b66ec263cd938 | |
parent | 88a48e297b3a3bac6022c03babfb038f1a886cea (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.c | 139 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic_helper.c | 4 |
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, | |||
269 | EXPORT_SYMBOL(drm_atomic_crtc_get_property); | 269 | EXPORT_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 | */ | ||
281 | static 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, | |||
376 | EXPORT_SYMBOL(drm_atomic_plane_get_property); | 399 | EXPORT_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 | */ | ||
411 | static 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 | */ |
802 | int drm_atomic_check_only(struct drm_atomic_state *state) | 901 | int 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 | } |
813 | EXPORT_SYMBOL(drm_atomic_check_only); | 944 | EXPORT_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 | } |