| .. | .. |
|---|
| 25 | 25 | * |
|---|
| 26 | 26 | **************************************************************************/ |
|---|
| 27 | 27 | |
|---|
| 28 | | -#include "vmwgfx_kms.h" |
|---|
| 29 | | -#include <drm/drm_plane_helper.h> |
|---|
| 30 | 28 | #include <drm/drm_atomic.h> |
|---|
| 31 | 29 | #include <drm/drm_atomic_helper.h> |
|---|
| 30 | +#include <drm/drm_damage_helper.h> |
|---|
| 31 | +#include <drm/drm_fourcc.h> |
|---|
| 32 | +#include <drm/drm_plane_helper.h> |
|---|
| 32 | 33 | #include <drm/drm_rect.h> |
|---|
| 34 | +#include <drm/drm_sysfs.h> |
|---|
| 35 | +#include <drm/drm_vblank.h> |
|---|
| 36 | + |
|---|
| 37 | +#include "vmwgfx_kms.h" |
|---|
| 33 | 38 | |
|---|
| 34 | 39 | /* Might need a hrtimer here? */ |
|---|
| 35 | 40 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
|---|
| .. | .. |
|---|
| 63 | 68 | if (!image) |
|---|
| 64 | 69 | return -EINVAL; |
|---|
| 65 | 70 | |
|---|
| 66 | | - cmd = vmw_fifo_reserve(dev_priv, cmd_size); |
|---|
| 67 | | - if (unlikely(cmd == NULL)) { |
|---|
| 68 | | - DRM_ERROR("Fifo reserve failed.\n"); |
|---|
| 71 | + cmd = VMW_FIFO_RESERVE(dev_priv, cmd_size); |
|---|
| 72 | + if (unlikely(cmd == NULL)) |
|---|
| 69 | 73 | return -ENOMEM; |
|---|
| 70 | | - } |
|---|
| 71 | 74 | |
|---|
| 72 | 75 | memset(cmd, 0, sizeof(*cmd)); |
|---|
| 73 | 76 | |
|---|
| .. | .. |
|---|
| 179 | 182 | if (cmd->dma.guest.ptr.offset % PAGE_SIZE || |
|---|
| 180 | 183 | box->x != 0 || box->y != 0 || box->z != 0 || |
|---|
| 181 | 184 | box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || |
|---|
| 182 | | - box->d != 1 || box_count != 1) { |
|---|
| 185 | + box->d != 1 || box_count != 1 || |
|---|
| 186 | + box->w > 64 || box->h > 64) { |
|---|
| 183 | 187 | /* TODO handle none page aligned offsets */ |
|---|
| 184 | 188 | /* TODO handle more dst & src != 0 */ |
|---|
| 185 | 189 | /* TODO handle more then one copy */ |
|---|
| 186 | | - DRM_ERROR("Cant snoop dma request for cursor!\n"); |
|---|
| 190 | + DRM_ERROR("Can't snoop dma request for cursor!\n"); |
|---|
| 187 | 191 | DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", |
|---|
| 188 | 192 | box->srcx, box->srcy, box->srcz, |
|---|
| 189 | 193 | box->x, box->y, box->z, |
|---|
| .. | .. |
|---|
| 456 | 460 | struct drm_crtc *crtc = state->crtc; |
|---|
| 457 | 461 | struct vmw_connector_state *vcs; |
|---|
| 458 | 462 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|---|
| 459 | | - struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
|---|
| 460 | | - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); |
|---|
| 461 | 463 | |
|---|
| 462 | 464 | vcs = vmw_connector_state_to_vcs(du->connector.state); |
|---|
| 463 | | - |
|---|
| 464 | | - /* Only one active implicit framebuffer at a time. */ |
|---|
| 465 | | - mutex_lock(&dev_priv->global_kms_state_mutex); |
|---|
| 466 | | - if (vcs->is_implicit && dev_priv->implicit_fb && |
|---|
| 467 | | - !(dev_priv->num_implicit == 1 && du->active_implicit) |
|---|
| 468 | | - && dev_priv->implicit_fb != vfb) { |
|---|
| 469 | | - DRM_ERROR("Multiple implicit framebuffers " |
|---|
| 470 | | - "not supported.\n"); |
|---|
| 471 | | - ret = -EINVAL; |
|---|
| 472 | | - } |
|---|
| 473 | | - mutex_unlock(&dev_priv->global_kms_state_mutex); |
|---|
| 474 | 465 | } |
|---|
| 475 | 466 | |
|---|
| 476 | 467 | |
|---|
| .. | .. |
|---|
| 493 | 484 | struct drm_plane_state *new_state) |
|---|
| 494 | 485 | { |
|---|
| 495 | 486 | int ret = 0; |
|---|
| 487 | + struct drm_crtc_state *crtc_state = NULL; |
|---|
| 496 | 488 | struct vmw_surface *surface = NULL; |
|---|
| 497 | 489 | struct drm_framebuffer *fb = new_state->fb; |
|---|
| 498 | 490 | |
|---|
| 499 | | - struct drm_rect src = drm_plane_state_src(new_state); |
|---|
| 500 | | - struct drm_rect dest = drm_plane_state_dest(new_state); |
|---|
| 491 | + if (new_state->crtc) |
|---|
| 492 | + crtc_state = drm_atomic_get_new_crtc_state(new_state->state, |
|---|
| 493 | + new_state->crtc); |
|---|
| 494 | + |
|---|
| 495 | + ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, |
|---|
| 496 | + DRM_PLANE_HELPER_NO_SCALING, |
|---|
| 497 | + DRM_PLANE_HELPER_NO_SCALING, |
|---|
| 498 | + true, true); |
|---|
| 499 | + if (ret) |
|---|
| 500 | + return ret; |
|---|
| 501 | 501 | |
|---|
| 502 | 502 | /* Turning off */ |
|---|
| 503 | 503 | if (!fb) |
|---|
| 504 | | - return ret; |
|---|
| 505 | | - |
|---|
| 506 | | - ret = drm_plane_helper_check_update(plane, new_state->crtc, fb, |
|---|
| 507 | | - &src, &dest, |
|---|
| 508 | | - DRM_MODE_ROTATE_0, |
|---|
| 509 | | - DRM_PLANE_HELPER_NO_SCALING, |
|---|
| 510 | | - DRM_PLANE_HELPER_NO_SCALING, |
|---|
| 511 | | - true, true, &new_state->visible); |
|---|
| 512 | | - if (!ret) |
|---|
| 513 | | - return ret; |
|---|
| 504 | + return 0; |
|---|
| 514 | 505 | |
|---|
| 515 | 506 | /* A lot of the code assumes this */ |
|---|
| 516 | 507 | if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { |
|---|
| .. | .. |
|---|
| 639 | 630 | return; |
|---|
| 640 | 631 | } |
|---|
| 641 | 632 | |
|---|
| 642 | | - crtc->state = &vcs->base; |
|---|
| 643 | | - crtc->state->crtc = crtc; |
|---|
| 633 | + __drm_atomic_helper_crtc_reset(crtc, &vcs->base); |
|---|
| 644 | 634 | } |
|---|
| 645 | 635 | |
|---|
| 646 | 636 | |
|---|
| .. | .. |
|---|
| 720 | 710 | return; |
|---|
| 721 | 711 | } |
|---|
| 722 | 712 | |
|---|
| 723 | | - plane->state = &vps->base; |
|---|
| 724 | | - plane->state->plane = plane; |
|---|
| 725 | | - plane->state->rotation = DRM_MODE_ROTATE_0; |
|---|
| 713 | + __drm_atomic_helper_plane_reset(plane, &vps->base); |
|---|
| 726 | 714 | } |
|---|
| 727 | 715 | |
|---|
| 728 | 716 | |
|---|
| .. | .. |
|---|
| 848 | 836 | kfree(vfbs); |
|---|
| 849 | 837 | } |
|---|
| 850 | 838 | |
|---|
| 851 | | -static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, |
|---|
| 852 | | - struct drm_file *file_priv, |
|---|
| 853 | | - unsigned flags, unsigned color, |
|---|
| 854 | | - struct drm_clip_rect *clips, |
|---|
| 855 | | - unsigned num_clips) |
|---|
| 856 | | -{ |
|---|
| 857 | | - struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); |
|---|
| 858 | | - struct vmw_framebuffer_surface *vfbs = |
|---|
| 859 | | - vmw_framebuffer_to_vfbs(framebuffer); |
|---|
| 860 | | - struct drm_clip_rect norect; |
|---|
| 861 | | - int ret, inc = 1; |
|---|
| 862 | | - |
|---|
| 863 | | - /* Legacy Display Unit does not support 3D */ |
|---|
| 864 | | - if (dev_priv->active_display_unit == vmw_du_legacy) |
|---|
| 865 | | - return -EINVAL; |
|---|
| 866 | | - |
|---|
| 867 | | - drm_modeset_lock_all(dev_priv->dev); |
|---|
| 868 | | - |
|---|
| 869 | | - ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
|---|
| 870 | | - if (unlikely(ret != 0)) { |
|---|
| 871 | | - drm_modeset_unlock_all(dev_priv->dev); |
|---|
| 872 | | - return ret; |
|---|
| 873 | | - } |
|---|
| 874 | | - |
|---|
| 875 | | - if (!num_clips) { |
|---|
| 876 | | - num_clips = 1; |
|---|
| 877 | | - clips = &norect; |
|---|
| 878 | | - norect.x1 = norect.y1 = 0; |
|---|
| 879 | | - norect.x2 = framebuffer->width; |
|---|
| 880 | | - norect.y2 = framebuffer->height; |
|---|
| 881 | | - } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { |
|---|
| 882 | | - num_clips /= 2; |
|---|
| 883 | | - inc = 2; /* skip source rects */ |
|---|
| 884 | | - } |
|---|
| 885 | | - |
|---|
| 886 | | - if (dev_priv->active_display_unit == vmw_du_screen_object) |
|---|
| 887 | | - ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, |
|---|
| 888 | | - clips, NULL, NULL, 0, 0, |
|---|
| 889 | | - num_clips, inc, NULL, NULL); |
|---|
| 890 | | - else |
|---|
| 891 | | - ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, |
|---|
| 892 | | - clips, NULL, NULL, 0, 0, |
|---|
| 893 | | - num_clips, inc, NULL, NULL); |
|---|
| 894 | | - |
|---|
| 895 | | - vmw_fifo_flush(dev_priv, false); |
|---|
| 896 | | - ttm_read_unlock(&dev_priv->reservation_sem); |
|---|
| 897 | | - |
|---|
| 898 | | - drm_modeset_unlock_all(dev_priv->dev); |
|---|
| 899 | | - |
|---|
| 900 | | - return 0; |
|---|
| 901 | | -} |
|---|
| 902 | | - |
|---|
| 903 | 839 | /** |
|---|
| 904 | 840 | * vmw_kms_readback - Perform a readback from the screen system to |
|---|
| 905 | 841 | * a buffer-object backed framebuffer. |
|---|
| .. | .. |
|---|
| 943 | 879 | |
|---|
| 944 | 880 | static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { |
|---|
| 945 | 881 | .destroy = vmw_framebuffer_surface_destroy, |
|---|
| 946 | | - .dirty = vmw_framebuffer_surface_dirty, |
|---|
| 882 | + .dirty = drm_atomic_helper_dirtyfb, |
|---|
| 947 | 883 | }; |
|---|
| 948 | 884 | |
|---|
| 949 | 885 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, |
|---|
| .. | .. |
|---|
| 969 | 905 | */ |
|---|
| 970 | 906 | |
|---|
| 971 | 907 | /* Surface must be marked as a scanout. */ |
|---|
| 972 | | - if (unlikely(!surface->scanout)) |
|---|
| 908 | + if (unlikely(!surface->metadata.scanout)) |
|---|
| 973 | 909 | return -EINVAL; |
|---|
| 974 | 910 | |
|---|
| 975 | | - if (unlikely(surface->mip_levels[0] != 1 || |
|---|
| 976 | | - surface->num_sizes != 1 || |
|---|
| 977 | | - surface->base_size.width < mode_cmd->width || |
|---|
| 978 | | - surface->base_size.height < mode_cmd->height || |
|---|
| 979 | | - surface->base_size.depth != 1)) { |
|---|
| 911 | + if (unlikely(surface->metadata.mip_levels[0] != 1 || |
|---|
| 912 | + surface->metadata.num_sizes != 1 || |
|---|
| 913 | + surface->metadata.base_size.width < mode_cmd->width || |
|---|
| 914 | + surface->metadata.base_size.height < mode_cmd->height || |
|---|
| 915 | + surface->metadata.base_size.depth != 1)) { |
|---|
| 980 | 916 | DRM_ERROR("Incompatible surface dimensions " |
|---|
| 981 | 917 | "for requested mode.\n"); |
|---|
| 982 | 918 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1005 | 941 | * For DX, surface format validation is done when surface->scanout |
|---|
| 1006 | 942 | * is set. |
|---|
| 1007 | 943 | */ |
|---|
| 1008 | | - if (!dev_priv->has_dx && format != surface->format) { |
|---|
| 944 | + if (!has_sm4_context(dev_priv) && format != surface->metadata.format) { |
|---|
| 1009 | 945 | DRM_ERROR("Invalid surface format for requested mode.\n"); |
|---|
| 1010 | 946 | return -EINVAL; |
|---|
| 1011 | 947 | } |
|---|
| .. | .. |
|---|
| 1086 | 1022 | } |
|---|
| 1087 | 1023 | |
|---|
| 1088 | 1024 | switch (dev_priv->active_display_unit) { |
|---|
| 1089 | | - case vmw_du_screen_target: |
|---|
| 1090 | | - ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, |
|---|
| 1091 | | - clips, NULL, num_clips, increment, |
|---|
| 1092 | | - true, true, NULL); |
|---|
| 1093 | | - break; |
|---|
| 1094 | | - case vmw_du_screen_object: |
|---|
| 1095 | | - ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, |
|---|
| 1096 | | - clips, NULL, num_clips, |
|---|
| 1097 | | - increment, true, NULL, NULL); |
|---|
| 1098 | | - break; |
|---|
| 1099 | 1025 | case vmw_du_legacy: |
|---|
| 1100 | 1026 | ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, |
|---|
| 1101 | 1027 | clips, num_clips, increment); |
|---|
| .. | .. |
|---|
| 1114 | 1040 | return ret; |
|---|
| 1115 | 1041 | } |
|---|
| 1116 | 1042 | |
|---|
| 1043 | +static int vmw_framebuffer_bo_dirty_ext(struct drm_framebuffer *framebuffer, |
|---|
| 1044 | + struct drm_file *file_priv, |
|---|
| 1045 | + unsigned int flags, unsigned int color, |
|---|
| 1046 | + struct drm_clip_rect *clips, |
|---|
| 1047 | + unsigned int num_clips) |
|---|
| 1048 | +{ |
|---|
| 1049 | + struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); |
|---|
| 1050 | + |
|---|
| 1051 | + if (dev_priv->active_display_unit == vmw_du_legacy) |
|---|
| 1052 | + return vmw_framebuffer_bo_dirty(framebuffer, file_priv, flags, |
|---|
| 1053 | + color, clips, num_clips); |
|---|
| 1054 | + |
|---|
| 1055 | + return drm_atomic_helper_dirtyfb(framebuffer, file_priv, flags, color, |
|---|
| 1056 | + clips, num_clips); |
|---|
| 1057 | +} |
|---|
| 1058 | + |
|---|
| 1117 | 1059 | static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { |
|---|
| 1118 | 1060 | .destroy = vmw_framebuffer_bo_destroy, |
|---|
| 1119 | | - .dirty = vmw_framebuffer_bo_dirty, |
|---|
| 1061 | + .dirty = vmw_framebuffer_bo_dirty_ext, |
|---|
| 1120 | 1062 | }; |
|---|
| 1121 | 1063 | |
|---|
| 1122 | 1064 | /** |
|---|
| .. | .. |
|---|
| 1202 | 1144 | struct vmw_buffer_object *bo_mob, |
|---|
| 1203 | 1145 | struct vmw_surface **srf_out) |
|---|
| 1204 | 1146 | { |
|---|
| 1147 | + struct vmw_surface_metadata metadata = {0}; |
|---|
| 1205 | 1148 | uint32_t format; |
|---|
| 1206 | | - struct drm_vmw_size content_base_size = {0}; |
|---|
| 1207 | 1149 | struct vmw_resource *res; |
|---|
| 1208 | 1150 | unsigned int bytes_pp; |
|---|
| 1209 | 1151 | struct drm_format_name_buf format_name; |
|---|
| .. | .. |
|---|
| 1233 | 1175 | return -EINVAL; |
|---|
| 1234 | 1176 | } |
|---|
| 1235 | 1177 | |
|---|
| 1236 | | - content_base_size.width = mode_cmd->pitches[0] / bytes_pp; |
|---|
| 1237 | | - content_base_size.height = mode_cmd->height; |
|---|
| 1238 | | - content_base_size.depth = 1; |
|---|
| 1178 | + metadata.format = format; |
|---|
| 1179 | + metadata.mip_levels[0] = 1; |
|---|
| 1180 | + metadata.num_sizes = 1; |
|---|
| 1181 | + metadata.base_size.width = mode_cmd->pitches[0] / bytes_pp; |
|---|
| 1182 | + metadata.base_size.height = mode_cmd->height; |
|---|
| 1183 | + metadata.base_size.depth = 1; |
|---|
| 1184 | + metadata.scanout = true; |
|---|
| 1239 | 1185 | |
|---|
| 1240 | | - ret = vmw_surface_gb_priv_define(dev, |
|---|
| 1241 | | - 0, /* kernel visible only */ |
|---|
| 1242 | | - 0, /* flags */ |
|---|
| 1243 | | - format, |
|---|
| 1244 | | - true, /* can be a scanout buffer */ |
|---|
| 1245 | | - 1, /* num of mip levels */ |
|---|
| 1246 | | - 0, |
|---|
| 1247 | | - 0, |
|---|
| 1248 | | - content_base_size, |
|---|
| 1249 | | - SVGA3D_MS_PATTERN_NONE, |
|---|
| 1250 | | - SVGA3D_MS_QUALITY_NONE, |
|---|
| 1251 | | - srf_out); |
|---|
| 1186 | + ret = vmw_gb_surface_define(vmw_priv(dev), 0, &metadata, srf_out); |
|---|
| 1252 | 1187 | if (ret) { |
|---|
| 1253 | 1188 | DRM_ERROR("Failed to allocate proxy content buffer\n"); |
|---|
| 1254 | 1189 | return ret; |
|---|
| .. | .. |
|---|
| 1262 | 1197 | vmw_bo_unreference(&res->backup); |
|---|
| 1263 | 1198 | res->backup = vmw_bo_reference(bo_mob); |
|---|
| 1264 | 1199 | res->backup_offset = 0; |
|---|
| 1265 | | - vmw_resource_unreserve(res, false, NULL, 0); |
|---|
| 1200 | + vmw_resource_unreserve(res, false, false, false, NULL, 0); |
|---|
| 1266 | 1201 | mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|---|
| 1267 | 1202 | |
|---|
| 1268 | 1203 | return 0; |
|---|
| .. | .. |
|---|
| 1524 | 1459 | if (dev_priv->active_display_unit == vmw_du_screen_target && |
|---|
| 1525 | 1460 | (drm_rect_width(&rects[i]) > dev_priv->stdu_max_width || |
|---|
| 1526 | 1461 | drm_rect_height(&rects[i]) > dev_priv->stdu_max_height)) { |
|---|
| 1527 | | - DRM_ERROR("Screen size not supported.\n"); |
|---|
| 1462 | + VMW_DEBUG_KMS("Screen size not supported.\n"); |
|---|
| 1528 | 1463 | return -EINVAL; |
|---|
| 1529 | 1464 | } |
|---|
| 1530 | 1465 | |
|---|
| .. | .. |
|---|
| 1548 | 1483 | * limit on primary bounding box |
|---|
| 1549 | 1484 | */ |
|---|
| 1550 | 1485 | if (pixel_mem > dev_priv->prim_bb_mem) { |
|---|
| 1551 | | - DRM_ERROR("Combined output size too large.\n"); |
|---|
| 1486 | + VMW_DEBUG_KMS("Combined output size too large.\n"); |
|---|
| 1552 | 1487 | return -EINVAL; |
|---|
| 1553 | 1488 | } |
|---|
| 1554 | 1489 | |
|---|
| .. | .. |
|---|
| 1558 | 1493 | bb_mem = (u64) bounding_box.x2 * bounding_box.y2 * 4; |
|---|
| 1559 | 1494 | |
|---|
| 1560 | 1495 | if (bb_mem > dev_priv->prim_bb_mem) { |
|---|
| 1561 | | - DRM_ERROR("Topology is beyond supported limits.\n"); |
|---|
| 1496 | + VMW_DEBUG_KMS("Topology is beyond supported limits.\n"); |
|---|
| 1562 | 1497 | return -EINVAL; |
|---|
| 1563 | 1498 | } |
|---|
| 1499 | + } |
|---|
| 1500 | + |
|---|
| 1501 | + return 0; |
|---|
| 1502 | +} |
|---|
| 1503 | + |
|---|
| 1504 | +/** |
|---|
| 1505 | + * vmw_crtc_state_and_lock - Return new or current crtc state with locked |
|---|
| 1506 | + * crtc mutex |
|---|
| 1507 | + * @state: The atomic state pointer containing the new atomic state |
|---|
| 1508 | + * @crtc: The crtc |
|---|
| 1509 | + * |
|---|
| 1510 | + * This function returns the new crtc state if it's part of the state update. |
|---|
| 1511 | + * Otherwise returns the current crtc state. It also makes sure that the |
|---|
| 1512 | + * crtc mutex is locked. |
|---|
| 1513 | + * |
|---|
| 1514 | + * Returns: A valid crtc state pointer or NULL. It may also return a |
|---|
| 1515 | + * pointer error, in particular -EDEADLK if locking needs to be rerun. |
|---|
| 1516 | + */ |
|---|
| 1517 | +static struct drm_crtc_state * |
|---|
| 1518 | +vmw_crtc_state_and_lock(struct drm_atomic_state *state, struct drm_crtc *crtc) |
|---|
| 1519 | +{ |
|---|
| 1520 | + struct drm_crtc_state *crtc_state; |
|---|
| 1521 | + |
|---|
| 1522 | + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); |
|---|
| 1523 | + if (crtc_state) { |
|---|
| 1524 | + lockdep_assert_held(&crtc->mutex.mutex.base); |
|---|
| 1525 | + } else { |
|---|
| 1526 | + int ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx); |
|---|
| 1527 | + |
|---|
| 1528 | + if (ret != 0 && ret != -EALREADY) |
|---|
| 1529 | + return ERR_PTR(ret); |
|---|
| 1530 | + |
|---|
| 1531 | + crtc_state = crtc->state; |
|---|
| 1532 | + } |
|---|
| 1533 | + |
|---|
| 1534 | + return crtc_state; |
|---|
| 1535 | +} |
|---|
| 1536 | + |
|---|
| 1537 | +/** |
|---|
| 1538 | + * vmw_kms_check_implicit - Verify that all implicit display units scan out |
|---|
| 1539 | + * from the same fb after the new state is committed. |
|---|
| 1540 | + * @dev: The drm_device. |
|---|
| 1541 | + * @state: The new state to be checked. |
|---|
| 1542 | + * |
|---|
| 1543 | + * Returns: |
|---|
| 1544 | + * Zero on success, |
|---|
| 1545 | + * -EINVAL on invalid state, |
|---|
| 1546 | + * -EDEADLK if modeset locking needs to be rerun. |
|---|
| 1547 | + */ |
|---|
| 1548 | +static int vmw_kms_check_implicit(struct drm_device *dev, |
|---|
| 1549 | + struct drm_atomic_state *state) |
|---|
| 1550 | +{ |
|---|
| 1551 | + struct drm_framebuffer *implicit_fb = NULL; |
|---|
| 1552 | + struct drm_crtc *crtc; |
|---|
| 1553 | + struct drm_crtc_state *crtc_state; |
|---|
| 1554 | + struct drm_plane_state *plane_state; |
|---|
| 1555 | + |
|---|
| 1556 | + drm_for_each_crtc(crtc, dev) { |
|---|
| 1557 | + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|---|
| 1558 | + |
|---|
| 1559 | + if (!du->is_implicit) |
|---|
| 1560 | + continue; |
|---|
| 1561 | + |
|---|
| 1562 | + crtc_state = vmw_crtc_state_and_lock(state, crtc); |
|---|
| 1563 | + if (IS_ERR(crtc_state)) |
|---|
| 1564 | + return PTR_ERR(crtc_state); |
|---|
| 1565 | + |
|---|
| 1566 | + if (!crtc_state || !crtc_state->enable) |
|---|
| 1567 | + continue; |
|---|
| 1568 | + |
|---|
| 1569 | + /* |
|---|
| 1570 | + * Can't move primary planes across crtcs, so this is OK. |
|---|
| 1571 | + * It also means we don't need to take the plane mutex. |
|---|
| 1572 | + */ |
|---|
| 1573 | + plane_state = du->primary.state; |
|---|
| 1574 | + if (plane_state->crtc != crtc) |
|---|
| 1575 | + continue; |
|---|
| 1576 | + |
|---|
| 1577 | + if (!implicit_fb) |
|---|
| 1578 | + implicit_fb = plane_state->fb; |
|---|
| 1579 | + else if (implicit_fb != plane_state->fb) |
|---|
| 1580 | + return -EINVAL; |
|---|
| 1564 | 1581 | } |
|---|
| 1565 | 1582 | |
|---|
| 1566 | 1583 | return 0; |
|---|
| .. | .. |
|---|
| 1577 | 1594 | static int vmw_kms_check_topology(struct drm_device *dev, |
|---|
| 1578 | 1595 | struct drm_atomic_state *state) |
|---|
| 1579 | 1596 | { |
|---|
| 1580 | | - struct vmw_private *dev_priv = vmw_priv(dev); |
|---|
| 1581 | 1597 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; |
|---|
| 1582 | 1598 | struct drm_rect *rects; |
|---|
| 1583 | 1599 | struct drm_crtc *crtc; |
|---|
| .. | .. |
|---|
| 1589 | 1605 | if (!rects) |
|---|
| 1590 | 1606 | return -ENOMEM; |
|---|
| 1591 | 1607 | |
|---|
| 1592 | | - mutex_lock(&dev_priv->requested_layout_mutex); |
|---|
| 1593 | | - |
|---|
| 1594 | 1608 | drm_for_each_crtc(crtc, dev) { |
|---|
| 1595 | 1609 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|---|
| 1596 | | - struct drm_crtc_state *crtc_state = crtc->state; |
|---|
| 1610 | + struct drm_crtc_state *crtc_state; |
|---|
| 1597 | 1611 | |
|---|
| 1598 | 1612 | i = drm_crtc_index(crtc); |
|---|
| 1599 | 1613 | |
|---|
| 1600 | | - if (crtc_state && crtc_state->enable) { |
|---|
| 1614 | + crtc_state = vmw_crtc_state_and_lock(state, crtc); |
|---|
| 1615 | + if (IS_ERR(crtc_state)) { |
|---|
| 1616 | + ret = PTR_ERR(crtc_state); |
|---|
| 1617 | + goto clean; |
|---|
| 1618 | + } |
|---|
| 1619 | + |
|---|
| 1620 | + if (!crtc_state) |
|---|
| 1621 | + continue; |
|---|
| 1622 | + |
|---|
| 1623 | + if (crtc_state->enable) { |
|---|
| 1601 | 1624 | rects[i].x1 = du->gui_x; |
|---|
| 1602 | 1625 | rects[i].y1 = du->gui_y; |
|---|
| 1603 | 1626 | rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; |
|---|
| 1604 | 1627 | rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; |
|---|
| 1628 | + } else { |
|---|
| 1629 | + rects[i].x1 = 0; |
|---|
| 1630 | + rects[i].y1 = 0; |
|---|
| 1631 | + rects[i].x2 = 0; |
|---|
| 1632 | + rects[i].y2 = 0; |
|---|
| 1605 | 1633 | } |
|---|
| 1606 | 1634 | } |
|---|
| 1607 | 1635 | |
|---|
| .. | .. |
|---|
| 1613 | 1641 | struct drm_connector_state *conn_state; |
|---|
| 1614 | 1642 | struct vmw_connector_state *vmw_conn_state; |
|---|
| 1615 | 1643 | |
|---|
| 1616 | | - if (!new_crtc_state->enable) { |
|---|
| 1617 | | - rects[i].x1 = 0; |
|---|
| 1618 | | - rects[i].y1 = 0; |
|---|
| 1619 | | - rects[i].x2 = 0; |
|---|
| 1620 | | - rects[i].y2 = 0; |
|---|
| 1621 | | - continue; |
|---|
| 1622 | | - } |
|---|
| 1623 | | - |
|---|
| 1624 | | - if (!du->pref_active) { |
|---|
| 1644 | + if (!du->pref_active && new_crtc_state->enable) { |
|---|
| 1645 | + VMW_DEBUG_KMS("Enabling a disabled display unit\n"); |
|---|
| 1625 | 1646 | ret = -EINVAL; |
|---|
| 1626 | 1647 | goto clean; |
|---|
| 1627 | 1648 | } |
|---|
| .. | .. |
|---|
| 1641 | 1662 | vmw_conn_state = vmw_connector_state_to_vcs(conn_state); |
|---|
| 1642 | 1663 | vmw_conn_state->gui_x = du->gui_x; |
|---|
| 1643 | 1664 | vmw_conn_state->gui_y = du->gui_y; |
|---|
| 1644 | | - |
|---|
| 1645 | | - rects[i].x1 = du->gui_x; |
|---|
| 1646 | | - rects[i].y1 = du->gui_y; |
|---|
| 1647 | | - rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; |
|---|
| 1648 | | - rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; |
|---|
| 1649 | 1665 | } |
|---|
| 1650 | 1666 | |
|---|
| 1651 | 1667 | ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, |
|---|
| 1652 | 1668 | rects); |
|---|
| 1653 | 1669 | |
|---|
| 1654 | 1670 | clean: |
|---|
| 1655 | | - mutex_unlock(&dev_priv->requested_layout_mutex); |
|---|
| 1656 | 1671 | kfree(rects); |
|---|
| 1657 | 1672 | return ret; |
|---|
| 1658 | 1673 | } |
|---|
| .. | .. |
|---|
| 1683 | 1698 | if (ret) |
|---|
| 1684 | 1699 | return ret; |
|---|
| 1685 | 1700 | |
|---|
| 1686 | | - if (!state->allow_modeset) |
|---|
| 1701 | + ret = vmw_kms_check_implicit(dev, state); |
|---|
| 1702 | + if (ret) { |
|---|
| 1703 | + VMW_DEBUG_KMS("Invalid implicit state\n"); |
|---|
| 1687 | 1704 | return ret; |
|---|
| 1705 | + } |
|---|
| 1688 | 1706 | |
|---|
| 1689 | | - /* |
|---|
| 1690 | | - * Legacy path do not set allow_modeset properly like |
|---|
| 1691 | | - * @drm_atomic_helper_update_plane, This will result in unnecessary call |
|---|
| 1692 | | - * to vmw_kms_check_topology. So extra set of check. |
|---|
| 1693 | | - */ |
|---|
| 1694 | 1707 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) { |
|---|
| 1695 | 1708 | if (drm_atomic_crtc_needs_modeset(crtc_state)) |
|---|
| 1696 | 1709 | need_modeset = true; |
|---|
| .. | .. |
|---|
| 1877 | 1890 | return 0; |
|---|
| 1878 | 1891 | } |
|---|
| 1879 | 1892 | |
|---|
| 1880 | | -int vmw_kms_save_vga(struct vmw_private *vmw_priv) |
|---|
| 1881 | | -{ |
|---|
| 1882 | | - struct vmw_vga_topology_state *save; |
|---|
| 1883 | | - uint32_t i; |
|---|
| 1884 | | - |
|---|
| 1885 | | - vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); |
|---|
| 1886 | | - vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); |
|---|
| 1887 | | - vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); |
|---|
| 1888 | | - if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
|---|
| 1889 | | - vmw_priv->vga_pitchlock = |
|---|
| 1890 | | - vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); |
|---|
| 1891 | | - else if (vmw_fifo_have_pitchlock(vmw_priv)) |
|---|
| 1892 | | - vmw_priv->vga_pitchlock = vmw_mmio_read(vmw_priv->mmio_virt + |
|---|
| 1893 | | - SVGA_FIFO_PITCHLOCK); |
|---|
| 1894 | | - |
|---|
| 1895 | | - if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
|---|
| 1896 | | - return 0; |
|---|
| 1897 | | - |
|---|
| 1898 | | - vmw_priv->num_displays = vmw_read(vmw_priv, |
|---|
| 1899 | | - SVGA_REG_NUM_GUEST_DISPLAYS); |
|---|
| 1900 | | - |
|---|
| 1901 | | - if (vmw_priv->num_displays == 0) |
|---|
| 1902 | | - vmw_priv->num_displays = 1; |
|---|
| 1903 | | - |
|---|
| 1904 | | - for (i = 0; i < vmw_priv->num_displays; ++i) { |
|---|
| 1905 | | - save = &vmw_priv->vga_save[i]; |
|---|
| 1906 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); |
|---|
| 1907 | | - save->primary = vmw_read(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY); |
|---|
| 1908 | | - save->pos_x = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_X); |
|---|
| 1909 | | - save->pos_y = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y); |
|---|
| 1910 | | - save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH); |
|---|
| 1911 | | - save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT); |
|---|
| 1912 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); |
|---|
| 1913 | | - if (i == 0 && vmw_priv->num_displays == 1 && |
|---|
| 1914 | | - save->width == 0 && save->height == 0) { |
|---|
| 1915 | | - |
|---|
| 1916 | | - /* |
|---|
| 1917 | | - * It should be fairly safe to assume that these |
|---|
| 1918 | | - * values are uninitialized. |
|---|
| 1919 | | - */ |
|---|
| 1920 | | - |
|---|
| 1921 | | - save->width = vmw_priv->vga_width - save->pos_x; |
|---|
| 1922 | | - save->height = vmw_priv->vga_height - save->pos_y; |
|---|
| 1923 | | - } |
|---|
| 1924 | | - } |
|---|
| 1925 | | - |
|---|
| 1926 | | - return 0; |
|---|
| 1927 | | -} |
|---|
| 1928 | | - |
|---|
| 1929 | | -int vmw_kms_restore_vga(struct vmw_private *vmw_priv) |
|---|
| 1930 | | -{ |
|---|
| 1931 | | - struct vmw_vga_topology_state *save; |
|---|
| 1932 | | - uint32_t i; |
|---|
| 1933 | | - |
|---|
| 1934 | | - vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); |
|---|
| 1935 | | - vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); |
|---|
| 1936 | | - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); |
|---|
| 1937 | | - if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
|---|
| 1938 | | - vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, |
|---|
| 1939 | | - vmw_priv->vga_pitchlock); |
|---|
| 1940 | | - else if (vmw_fifo_have_pitchlock(vmw_priv)) |
|---|
| 1941 | | - vmw_mmio_write(vmw_priv->vga_pitchlock, |
|---|
| 1942 | | - vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); |
|---|
| 1943 | | - |
|---|
| 1944 | | - if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
|---|
| 1945 | | - return 0; |
|---|
| 1946 | | - |
|---|
| 1947 | | - for (i = 0; i < vmw_priv->num_displays; ++i) { |
|---|
| 1948 | | - save = &vmw_priv->vga_save[i]; |
|---|
| 1949 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); |
|---|
| 1950 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, save->primary); |
|---|
| 1951 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, save->pos_x); |
|---|
| 1952 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, save->pos_y); |
|---|
| 1953 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, save->width); |
|---|
| 1954 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, save->height); |
|---|
| 1955 | | - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); |
|---|
| 1956 | | - } |
|---|
| 1957 | | - |
|---|
| 1958 | | - return 0; |
|---|
| 1959 | | -} |
|---|
| 1960 | | - |
|---|
| 1961 | 1893 | bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, |
|---|
| 1962 | 1894 | uint32_t pitch, |
|---|
| 1963 | 1895 | uint32_t height) |
|---|
| .. | .. |
|---|
| 1971 | 1903 | /** |
|---|
| 1972 | 1904 | * Function called by DRM code called with vbl_lock held. |
|---|
| 1973 | 1905 | */ |
|---|
| 1974 | | -u32 vmw_get_vblank_counter(struct drm_device *dev, unsigned int pipe) |
|---|
| 1906 | +u32 vmw_get_vblank_counter(struct drm_crtc *crtc) |
|---|
| 1975 | 1907 | { |
|---|
| 1976 | 1908 | return 0; |
|---|
| 1977 | 1909 | } |
|---|
| .. | .. |
|---|
| 1979 | 1911 | /** |
|---|
| 1980 | 1912 | * Function called by DRM code called with vbl_lock held. |
|---|
| 1981 | 1913 | */ |
|---|
| 1982 | | -int vmw_enable_vblank(struct drm_device *dev, unsigned int pipe) |
|---|
| 1914 | +int vmw_enable_vblank(struct drm_crtc *crtc) |
|---|
| 1983 | 1915 | { |
|---|
| 1984 | 1916 | return -EINVAL; |
|---|
| 1985 | 1917 | } |
|---|
| .. | .. |
|---|
| 1987 | 1919 | /** |
|---|
| 1988 | 1920 | * Function called by DRM code called with vbl_lock held. |
|---|
| 1989 | 1921 | */ |
|---|
| 1990 | | -void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe) |
|---|
| 1922 | +void vmw_disable_vblank(struct drm_crtc *crtc) |
|---|
| 1991 | 1923 | { |
|---|
| 1992 | 1924 | } |
|---|
| 1993 | 1925 | |
|---|
| .. | .. |
|---|
| 2005 | 1937 | struct vmw_display_unit *du; |
|---|
| 2006 | 1938 | struct drm_connector *con; |
|---|
| 2007 | 1939 | struct drm_connector_list_iter conn_iter; |
|---|
| 1940 | + struct drm_modeset_acquire_ctx ctx; |
|---|
| 1941 | + struct drm_crtc *crtc; |
|---|
| 1942 | + int ret; |
|---|
| 2008 | 1943 | |
|---|
| 2009 | | - /* |
|---|
| 2010 | | - * Currently only gui_x/y is protected with requested_layout_mutex. |
|---|
| 2011 | | - */ |
|---|
| 2012 | | - mutex_lock(&dev_priv->requested_layout_mutex); |
|---|
| 1944 | + /* Currently gui_x/y is protected with the crtc mutex */ |
|---|
| 1945 | + mutex_lock(&dev->mode_config.mutex); |
|---|
| 1946 | + drm_modeset_acquire_init(&ctx, 0); |
|---|
| 1947 | +retry: |
|---|
| 1948 | + drm_for_each_crtc(crtc, dev) { |
|---|
| 1949 | + ret = drm_modeset_lock(&crtc->mutex, &ctx); |
|---|
| 1950 | + if (ret < 0) { |
|---|
| 1951 | + if (ret == -EDEADLK) { |
|---|
| 1952 | + drm_modeset_backoff(&ctx); |
|---|
| 1953 | + goto retry; |
|---|
| 1954 | + } |
|---|
| 1955 | + goto out_fini; |
|---|
| 1956 | + } |
|---|
| 1957 | + } |
|---|
| 1958 | + |
|---|
| 2013 | 1959 | drm_connector_list_iter_begin(dev, &conn_iter); |
|---|
| 2014 | 1960 | drm_for_each_connector_iter(con, &conn_iter) { |
|---|
| 2015 | 1961 | du = vmw_connector_to_du(con); |
|---|
| .. | .. |
|---|
| 2028 | 1974 | } |
|---|
| 2029 | 1975 | } |
|---|
| 2030 | 1976 | drm_connector_list_iter_end(&conn_iter); |
|---|
| 2031 | | - mutex_unlock(&dev_priv->requested_layout_mutex); |
|---|
| 2032 | 1977 | |
|---|
| 2033 | | - mutex_lock(&dev->mode_config.mutex); |
|---|
| 2034 | 1978 | list_for_each_entry(con, &dev->mode_config.connector_list, head) { |
|---|
| 2035 | 1979 | du = vmw_connector_to_du(con); |
|---|
| 2036 | 1980 | if (num_rects > du->unit) { |
|---|
| .. | .. |
|---|
| 2050 | 1994 | } |
|---|
| 2051 | 1995 | con->status = vmw_du_connector_detect(con, true); |
|---|
| 2052 | 1996 | } |
|---|
| 2053 | | - mutex_unlock(&dev->mode_config.mutex); |
|---|
| 2054 | 1997 | |
|---|
| 2055 | 1998 | drm_sysfs_hotplug_event(dev); |
|---|
| 2056 | | - |
|---|
| 1999 | +out_fini: |
|---|
| 2000 | + drm_modeset_drop_locks(&ctx); |
|---|
| 2001 | + drm_modeset_acquire_fini(&ctx); |
|---|
| 2002 | + mutex_unlock(&dev->mode_config.mutex); |
|---|
| 2003 | + |
|---|
| 2057 | 2004 | return 0; |
|---|
| 2058 | 2005 | } |
|---|
| 2059 | 2006 | |
|---|
| .. | .. |
|---|
| 2191 | 2138 | mode->vtotal = mode->vsync_end + 50; |
|---|
| 2192 | 2139 | |
|---|
| 2193 | 2140 | mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6; |
|---|
| 2194 | | - mode->vrefresh = drm_mode_vrefresh(mode); |
|---|
| 2195 | 2141 | } |
|---|
| 2196 | 2142 | |
|---|
| 2197 | 2143 | |
|---|
| .. | .. |
|---|
| 2265 | 2211 | mode = drm_mode_duplicate(dev, bmode); |
|---|
| 2266 | 2212 | if (!mode) |
|---|
| 2267 | 2213 | return 0; |
|---|
| 2268 | | - mode->vrefresh = drm_mode_vrefresh(mode); |
|---|
| 2269 | 2214 | |
|---|
| 2270 | 2215 | drm_mode_probed_add(connector, mode); |
|---|
| 2271 | 2216 | } |
|---|
| .. | .. |
|---|
| 2275 | 2220 | drm_mode_sort(&connector->modes); |
|---|
| 2276 | 2221 | |
|---|
| 2277 | 2222 | return 1; |
|---|
| 2278 | | -} |
|---|
| 2279 | | - |
|---|
| 2280 | | -int vmw_du_connector_set_property(struct drm_connector *connector, |
|---|
| 2281 | | - struct drm_property *property, |
|---|
| 2282 | | - uint64_t val) |
|---|
| 2283 | | -{ |
|---|
| 2284 | | - struct vmw_display_unit *du = vmw_connector_to_du(connector); |
|---|
| 2285 | | - struct vmw_private *dev_priv = vmw_priv(connector->dev); |
|---|
| 2286 | | - |
|---|
| 2287 | | - if (property == dev_priv->implicit_placement_property) |
|---|
| 2288 | | - du->is_implicit = val; |
|---|
| 2289 | | - |
|---|
| 2290 | | - return 0; |
|---|
| 2291 | | -} |
|---|
| 2292 | | - |
|---|
| 2293 | | - |
|---|
| 2294 | | - |
|---|
| 2295 | | -/** |
|---|
| 2296 | | - * vmw_du_connector_atomic_set_property - Atomic version of get property |
|---|
| 2297 | | - * |
|---|
| 2298 | | - * @crtc - crtc the property is associated with |
|---|
| 2299 | | - * |
|---|
| 2300 | | - * Returns: |
|---|
| 2301 | | - * Zero on success, negative errno on failure. |
|---|
| 2302 | | - */ |
|---|
| 2303 | | -int |
|---|
| 2304 | | -vmw_du_connector_atomic_set_property(struct drm_connector *connector, |
|---|
| 2305 | | - struct drm_connector_state *state, |
|---|
| 2306 | | - struct drm_property *property, |
|---|
| 2307 | | - uint64_t val) |
|---|
| 2308 | | -{ |
|---|
| 2309 | | - struct vmw_private *dev_priv = vmw_priv(connector->dev); |
|---|
| 2310 | | - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); |
|---|
| 2311 | | - struct vmw_display_unit *du = vmw_connector_to_du(connector); |
|---|
| 2312 | | - |
|---|
| 2313 | | - |
|---|
| 2314 | | - if (property == dev_priv->implicit_placement_property) { |
|---|
| 2315 | | - vcs->is_implicit = val; |
|---|
| 2316 | | - |
|---|
| 2317 | | - /* |
|---|
| 2318 | | - * We should really be doing a drm_atomic_commit() to |
|---|
| 2319 | | - * commit the new state, but since this doesn't cause |
|---|
| 2320 | | - * an immedate state change, this is probably ok |
|---|
| 2321 | | - */ |
|---|
| 2322 | | - du->is_implicit = vcs->is_implicit; |
|---|
| 2323 | | - } else { |
|---|
| 2324 | | - return -EINVAL; |
|---|
| 2325 | | - } |
|---|
| 2326 | | - |
|---|
| 2327 | | - return 0; |
|---|
| 2328 | | -} |
|---|
| 2329 | | - |
|---|
| 2330 | | - |
|---|
| 2331 | | -/** |
|---|
| 2332 | | - * vmw_du_connector_atomic_get_property - Atomic version of get property |
|---|
| 2333 | | - * |
|---|
| 2334 | | - * @connector - connector the property is associated with |
|---|
| 2335 | | - * |
|---|
| 2336 | | - * Returns: |
|---|
| 2337 | | - * Zero on success, negative errno on failure. |
|---|
| 2338 | | - */ |
|---|
| 2339 | | -int |
|---|
| 2340 | | -vmw_du_connector_atomic_get_property(struct drm_connector *connector, |
|---|
| 2341 | | - const struct drm_connector_state *state, |
|---|
| 2342 | | - struct drm_property *property, |
|---|
| 2343 | | - uint64_t *val) |
|---|
| 2344 | | -{ |
|---|
| 2345 | | - struct vmw_private *dev_priv = vmw_priv(connector->dev); |
|---|
| 2346 | | - struct vmw_connector_state *vcs = vmw_connector_state_to_vcs(state); |
|---|
| 2347 | | - |
|---|
| 2348 | | - if (property == dev_priv->implicit_placement_property) |
|---|
| 2349 | | - *val = vcs->is_implicit; |
|---|
| 2350 | | - else { |
|---|
| 2351 | | - DRM_ERROR("Invalid Property %s\n", property->name); |
|---|
| 2352 | | - return -EINVAL; |
|---|
| 2353 | | - } |
|---|
| 2354 | | - |
|---|
| 2355 | | - return 0; |
|---|
| 2356 | 2223 | } |
|---|
| 2357 | 2224 | |
|---|
| 2358 | 2225 | /** |
|---|
| .. | .. |
|---|
| 2389 | 2256 | |
|---|
| 2390 | 2257 | if (!arg->num_outputs) { |
|---|
| 2391 | 2258 | struct drm_rect def_rect = {0, 0, 800, 600}; |
|---|
| 2259 | + VMW_DEBUG_KMS("Default layout x1 = %d y1 = %d x2 = %d y2 = %d\n", |
|---|
| 2260 | + def_rect.x1, def_rect.y1, |
|---|
| 2261 | + def_rect.x2, def_rect.y2); |
|---|
| 2392 | 2262 | vmw_du_update_layout(dev_priv, 1, &def_rect); |
|---|
| 2393 | 2263 | return 0; |
|---|
| 2394 | 2264 | } |
|---|
| .. | .. |
|---|
| 2409 | 2279 | |
|---|
| 2410 | 2280 | drm_rects = (struct drm_rect *)rects; |
|---|
| 2411 | 2281 | |
|---|
| 2282 | + VMW_DEBUG_KMS("Layout count = %u\n", arg->num_outputs); |
|---|
| 2412 | 2283 | for (i = 0; i < arg->num_outputs; i++) { |
|---|
| 2413 | 2284 | struct drm_vmw_rect curr_rect; |
|---|
| 2414 | 2285 | |
|---|
| .. | .. |
|---|
| 2425 | 2296 | drm_rects[i].x2 = curr_rect.x + curr_rect.w; |
|---|
| 2426 | 2297 | drm_rects[i].y2 = curr_rect.y + curr_rect.h; |
|---|
| 2427 | 2298 | |
|---|
| 2299 | + VMW_DEBUG_KMS(" x1 = %d y1 = %d x2 = %d y2 = %d\n", |
|---|
| 2300 | + drm_rects[i].x1, drm_rects[i].y1, |
|---|
| 2301 | + drm_rects[i].x2, drm_rects[i].y2); |
|---|
| 2302 | + |
|---|
| 2428 | 2303 | /* |
|---|
| 2429 | 2304 | * Currently this check is limiting the topology within |
|---|
| 2430 | 2305 | * mode_config->max (which actually is max texture size |
|---|
| .. | .. |
|---|
| 2435 | 2310 | if (drm_rects[i].x1 < 0 || drm_rects[i].y1 < 0 || |
|---|
| 2436 | 2311 | drm_rects[i].x2 > mode_config->max_width || |
|---|
| 2437 | 2312 | drm_rects[i].y2 > mode_config->max_height) { |
|---|
| 2438 | | - DRM_ERROR("Invalid GUI layout.\n"); |
|---|
| 2313 | + VMW_DEBUG_KMS("Invalid layout %d %d %d %d\n", |
|---|
| 2314 | + drm_rects[i].x1, drm_rects[i].y1, |
|---|
| 2315 | + drm_rects[i].x2, drm_rects[i].y2); |
|---|
| 2439 | 2316 | ret = -EINVAL; |
|---|
| 2440 | 2317 | goto out_free; |
|---|
| 2441 | 2318 | } |
|---|
| .. | .. |
|---|
| 2508 | 2385 | |
|---|
| 2509 | 2386 | dirty->unit = unit; |
|---|
| 2510 | 2387 | if (dirty->fifo_reserve_size > 0) { |
|---|
| 2511 | | - dirty->cmd = vmw_fifo_reserve(dev_priv, |
|---|
| 2388 | + dirty->cmd = VMW_FIFO_RESERVE(dev_priv, |
|---|
| 2512 | 2389 | dirty->fifo_reserve_size); |
|---|
| 2513 | | - if (!dirty->cmd) { |
|---|
| 2514 | | - DRM_ERROR("Couldn't reserve fifo space " |
|---|
| 2515 | | - "for dirty blits.\n"); |
|---|
| 2390 | + if (!dirty->cmd) |
|---|
| 2516 | 2391 | return -ENOMEM; |
|---|
| 2517 | | - } |
|---|
| 2392 | + |
|---|
| 2518 | 2393 | memset(dirty->cmd, 0, dirty->fifo_reserve_size); |
|---|
| 2519 | 2394 | } |
|---|
| 2520 | 2395 | dirty->num_hits = 0; |
|---|
| .. | .. |
|---|
| 2577 | 2452 | } |
|---|
| 2578 | 2453 | |
|---|
| 2579 | 2454 | /** |
|---|
| 2580 | | - * vmw_kms_helper_buffer_prepare - Reserve and validate a buffer object before |
|---|
| 2581 | | - * command submission. |
|---|
| 2582 | | - * |
|---|
| 2583 | | - * @dev_priv. Pointer to a device private structure. |
|---|
| 2584 | | - * @buf: The buffer object |
|---|
| 2585 | | - * @interruptible: Whether to perform waits as interruptible. |
|---|
| 2586 | | - * @validate_as_mob: Whether the buffer should be validated as a MOB. If false, |
|---|
| 2587 | | - * The buffer will be validated as a GMR. Already pinned buffers will not be |
|---|
| 2588 | | - * validated. |
|---|
| 2589 | | - * |
|---|
| 2590 | | - * Returns 0 on success, negative error code on failure, -ERESTARTSYS if |
|---|
| 2591 | | - * interrupted by a signal. |
|---|
| 2455 | + * vmw_kms_helper_validation_finish - Helper for post KMS command submission |
|---|
| 2456 | + * cleanup and fencing |
|---|
| 2457 | + * @dev_priv: Pointer to the device-private struct |
|---|
| 2458 | + * @file_priv: Pointer identifying the client when user-space fencing is used |
|---|
| 2459 | + * @ctx: Pointer to the validation context |
|---|
| 2460 | + * @out_fence: If non-NULL, returned refcounted fence-pointer |
|---|
| 2461 | + * @user_fence_rep: If non-NULL, pointer to user-space address area |
|---|
| 2462 | + * in which to copy user-space fence info |
|---|
| 2592 | 2463 | */ |
|---|
| 2593 | | -int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, |
|---|
| 2594 | | - struct vmw_buffer_object *buf, |
|---|
| 2595 | | - bool interruptible, |
|---|
| 2596 | | - bool validate_as_mob, |
|---|
| 2597 | | - bool for_cpu_blit) |
|---|
| 2464 | +void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv, |
|---|
| 2465 | + struct drm_file *file_priv, |
|---|
| 2466 | + struct vmw_validation_context *ctx, |
|---|
| 2467 | + struct vmw_fence_obj **out_fence, |
|---|
| 2468 | + struct drm_vmw_fence_rep __user * |
|---|
| 2469 | + user_fence_rep) |
|---|
| 2598 | 2470 | { |
|---|
| 2599 | | - struct ttm_operation_ctx ctx = { |
|---|
| 2600 | | - .interruptible = interruptible, |
|---|
| 2601 | | - .no_wait_gpu = false}; |
|---|
| 2602 | | - struct ttm_buffer_object *bo = &buf->base; |
|---|
| 2603 | | - int ret; |
|---|
| 2471 | + struct vmw_fence_obj *fence = NULL; |
|---|
| 2472 | + uint32_t handle = 0; |
|---|
| 2473 | + int ret = 0; |
|---|
| 2604 | 2474 | |
|---|
| 2605 | | - ttm_bo_reserve(bo, false, false, NULL); |
|---|
| 2606 | | - if (for_cpu_blit) |
|---|
| 2607 | | - ret = ttm_bo_validate(bo, &vmw_nonfixed_placement, &ctx); |
|---|
| 2608 | | - else |
|---|
| 2609 | | - ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, |
|---|
| 2610 | | - validate_as_mob); |
|---|
| 2611 | | - if (ret) |
|---|
| 2612 | | - ttm_bo_unreserve(bo); |
|---|
| 2613 | | - |
|---|
| 2614 | | - return ret; |
|---|
| 2615 | | -} |
|---|
| 2616 | | - |
|---|
| 2617 | | -/** |
|---|
| 2618 | | - * vmw_kms_helper_buffer_revert - Undo the actions of |
|---|
| 2619 | | - * vmw_kms_helper_buffer_prepare. |
|---|
| 2620 | | - * |
|---|
| 2621 | | - * @res: Pointer to the buffer object. |
|---|
| 2622 | | - * |
|---|
| 2623 | | - * Helper to be used if an error forces the caller to undo the actions of |
|---|
| 2624 | | - * vmw_kms_helper_buffer_prepare. |
|---|
| 2625 | | - */ |
|---|
| 2626 | | -void vmw_kms_helper_buffer_revert(struct vmw_buffer_object *buf) |
|---|
| 2627 | | -{ |
|---|
| 2628 | | - if (buf) |
|---|
| 2629 | | - ttm_bo_unreserve(&buf->base); |
|---|
| 2630 | | -} |
|---|
| 2631 | | - |
|---|
| 2632 | | -/** |
|---|
| 2633 | | - * vmw_kms_helper_buffer_finish - Unreserve and fence a buffer object after |
|---|
| 2634 | | - * kms command submission. |
|---|
| 2635 | | - * |
|---|
| 2636 | | - * @dev_priv: Pointer to a device private structure. |
|---|
| 2637 | | - * @file_priv: Pointer to a struct drm_file representing the caller's |
|---|
| 2638 | | - * connection. Must be set to NULL if @user_fence_rep is NULL, and conversely |
|---|
| 2639 | | - * if non-NULL, @user_fence_rep must be non-NULL. |
|---|
| 2640 | | - * @buf: The buffer object. |
|---|
| 2641 | | - * @out_fence: Optional pointer to a fence pointer. If non-NULL, a |
|---|
| 2642 | | - * ref-counted fence pointer is returned here. |
|---|
| 2643 | | - * @user_fence_rep: Optional pointer to a user-space provided struct |
|---|
| 2644 | | - * drm_vmw_fence_rep. If provided, @file_priv must also be provided and the |
|---|
| 2645 | | - * function copies fence data to user-space in a fail-safe manner. |
|---|
| 2646 | | - */ |
|---|
| 2647 | | -void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, |
|---|
| 2648 | | - struct drm_file *file_priv, |
|---|
| 2649 | | - struct vmw_buffer_object *buf, |
|---|
| 2650 | | - struct vmw_fence_obj **out_fence, |
|---|
| 2651 | | - struct drm_vmw_fence_rep __user * |
|---|
| 2652 | | - user_fence_rep) |
|---|
| 2653 | | -{ |
|---|
| 2654 | | - struct vmw_fence_obj *fence; |
|---|
| 2655 | | - uint32_t handle; |
|---|
| 2656 | | - int ret; |
|---|
| 2657 | | - |
|---|
| 2658 | | - ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, |
|---|
| 2659 | | - file_priv ? &handle : NULL); |
|---|
| 2660 | | - if (buf) |
|---|
| 2661 | | - vmw_bo_fence_single(&buf->base, fence); |
|---|
| 2475 | + if (file_priv || user_fence_rep || vmw_validation_has_bos(ctx) || |
|---|
| 2476 | + out_fence) |
|---|
| 2477 | + ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, |
|---|
| 2478 | + file_priv ? &handle : NULL); |
|---|
| 2479 | + vmw_validation_done(ctx, fence); |
|---|
| 2662 | 2480 | if (file_priv) |
|---|
| 2663 | 2481 | vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), |
|---|
| 2664 | 2482 | ret, user_fence_rep, fence, |
|---|
| .. | .. |
|---|
| 2667 | 2485 | *out_fence = fence; |
|---|
| 2668 | 2486 | else |
|---|
| 2669 | 2487 | vmw_fence_obj_unreference(&fence); |
|---|
| 2670 | | - |
|---|
| 2671 | | - vmw_kms_helper_buffer_revert(buf); |
|---|
| 2672 | | -} |
|---|
| 2673 | | - |
|---|
| 2674 | | - |
|---|
| 2675 | | -/** |
|---|
| 2676 | | - * vmw_kms_helper_resource_revert - Undo the actions of |
|---|
| 2677 | | - * vmw_kms_helper_resource_prepare. |
|---|
| 2678 | | - * |
|---|
| 2679 | | - * @res: Pointer to the resource. Typically a surface. |
|---|
| 2680 | | - * |
|---|
| 2681 | | - * Helper to be used if an error forces the caller to undo the actions of |
|---|
| 2682 | | - * vmw_kms_helper_resource_prepare. |
|---|
| 2683 | | - */ |
|---|
| 2684 | | -void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx) |
|---|
| 2685 | | -{ |
|---|
| 2686 | | - struct vmw_resource *res = ctx->res; |
|---|
| 2687 | | - |
|---|
| 2688 | | - vmw_kms_helper_buffer_revert(ctx->buf); |
|---|
| 2689 | | - vmw_bo_unreference(&ctx->buf); |
|---|
| 2690 | | - vmw_resource_unreserve(res, false, NULL, 0); |
|---|
| 2691 | | - mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|---|
| 2692 | | -} |
|---|
| 2693 | | - |
|---|
| 2694 | | -/** |
|---|
| 2695 | | - * vmw_kms_helper_resource_prepare - Reserve and validate a resource before |
|---|
| 2696 | | - * command submission. |
|---|
| 2697 | | - * |
|---|
| 2698 | | - * @res: Pointer to the resource. Typically a surface. |
|---|
| 2699 | | - * @interruptible: Whether to perform waits as interruptible. |
|---|
| 2700 | | - * |
|---|
| 2701 | | - * Reserves and validates also the backup buffer if a guest-backed resource. |
|---|
| 2702 | | - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
|---|
| 2703 | | - * interrupted by a signal. |
|---|
| 2704 | | - */ |
|---|
| 2705 | | -int vmw_kms_helper_resource_prepare(struct vmw_resource *res, |
|---|
| 2706 | | - bool interruptible, |
|---|
| 2707 | | - struct vmw_validation_ctx *ctx) |
|---|
| 2708 | | -{ |
|---|
| 2709 | | - int ret = 0; |
|---|
| 2710 | | - |
|---|
| 2711 | | - ctx->buf = NULL; |
|---|
| 2712 | | - ctx->res = res; |
|---|
| 2713 | | - |
|---|
| 2714 | | - if (interruptible) |
|---|
| 2715 | | - ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex); |
|---|
| 2716 | | - else |
|---|
| 2717 | | - mutex_lock(&res->dev_priv->cmdbuf_mutex); |
|---|
| 2718 | | - |
|---|
| 2719 | | - if (unlikely(ret != 0)) |
|---|
| 2720 | | - return -ERESTARTSYS; |
|---|
| 2721 | | - |
|---|
| 2722 | | - ret = vmw_resource_reserve(res, interruptible, false); |
|---|
| 2723 | | - if (ret) |
|---|
| 2724 | | - goto out_unlock; |
|---|
| 2725 | | - |
|---|
| 2726 | | - if (res->backup) { |
|---|
| 2727 | | - ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, |
|---|
| 2728 | | - interruptible, |
|---|
| 2729 | | - res->dev_priv->has_mob, |
|---|
| 2730 | | - false); |
|---|
| 2731 | | - if (ret) |
|---|
| 2732 | | - goto out_unreserve; |
|---|
| 2733 | | - |
|---|
| 2734 | | - ctx->buf = vmw_bo_reference(res->backup); |
|---|
| 2735 | | - } |
|---|
| 2736 | | - ret = vmw_resource_validate(res); |
|---|
| 2737 | | - if (ret) |
|---|
| 2738 | | - goto out_revert; |
|---|
| 2739 | | - return 0; |
|---|
| 2740 | | - |
|---|
| 2741 | | -out_revert: |
|---|
| 2742 | | - vmw_kms_helper_buffer_revert(ctx->buf); |
|---|
| 2743 | | -out_unreserve: |
|---|
| 2744 | | - vmw_resource_unreserve(res, false, NULL, 0); |
|---|
| 2745 | | -out_unlock: |
|---|
| 2746 | | - mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|---|
| 2747 | | - return ret; |
|---|
| 2748 | | -} |
|---|
| 2749 | | - |
|---|
| 2750 | | -/** |
|---|
| 2751 | | - * vmw_kms_helper_resource_finish - Unreserve and fence a resource after |
|---|
| 2752 | | - * kms command submission. |
|---|
| 2753 | | - * |
|---|
| 2754 | | - * @res: Pointer to the resource. Typically a surface. |
|---|
| 2755 | | - * @out_fence: Optional pointer to a fence pointer. If non-NULL, a |
|---|
| 2756 | | - * ref-counted fence pointer is returned here. |
|---|
| 2757 | | - */ |
|---|
| 2758 | | -void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, |
|---|
| 2759 | | - struct vmw_fence_obj **out_fence) |
|---|
| 2760 | | -{ |
|---|
| 2761 | | - struct vmw_resource *res = ctx->res; |
|---|
| 2762 | | - |
|---|
| 2763 | | - if (ctx->buf || out_fence) |
|---|
| 2764 | | - vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, |
|---|
| 2765 | | - out_fence, NULL); |
|---|
| 2766 | | - |
|---|
| 2767 | | - vmw_bo_unreference(&ctx->buf); |
|---|
| 2768 | | - vmw_resource_unreserve(res, false, NULL, 0); |
|---|
| 2769 | | - mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|---|
| 2770 | 2488 | } |
|---|
| 2771 | 2489 | |
|---|
| 2772 | 2490 | /** |
|---|
| .. | .. |
|---|
| 2789 | 2507 | int increment) |
|---|
| 2790 | 2508 | { |
|---|
| 2791 | 2509 | struct vmw_private *dev_priv = res->dev_priv; |
|---|
| 2792 | | - struct drm_vmw_size *size = &vmw_res_to_srf(res)->base_size; |
|---|
| 2510 | + struct drm_vmw_size *size = &vmw_res_to_srf(res)->metadata.base_size; |
|---|
| 2793 | 2511 | struct { |
|---|
| 2794 | 2512 | SVGA3dCmdHeader header; |
|---|
| 2795 | 2513 | SVGA3dCmdUpdateGBImage body; |
|---|
| .. | .. |
|---|
| 2801 | 2519 | if (!clips) |
|---|
| 2802 | 2520 | return 0; |
|---|
| 2803 | 2521 | |
|---|
| 2804 | | - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips); |
|---|
| 2805 | | - if (!cmd) { |
|---|
| 2806 | | - DRM_ERROR("Couldn't reserve fifo space for proxy surface " |
|---|
| 2807 | | - "update.\n"); |
|---|
| 2522 | + cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd) * num_clips); |
|---|
| 2523 | + if (!cmd) |
|---|
| 2808 | 2524 | return -ENOMEM; |
|---|
| 2809 | | - } |
|---|
| 2810 | 2525 | |
|---|
| 2811 | 2526 | for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) { |
|---|
| 2812 | 2527 | box = &cmd->body.box; |
|---|
| .. | .. |
|---|
| 2901 | 2616 | } |
|---|
| 2902 | 2617 | |
|---|
| 2903 | 2618 | /** |
|---|
| 2904 | | - * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer |
|---|
| 2905 | | - * |
|---|
| 2906 | | - * @dev_priv: Pointer to a device private struct. |
|---|
| 2907 | | - * @du: The display unit of the crtc. |
|---|
| 2908 | | - */ |
|---|
| 2909 | | -void vmw_kms_del_active(struct vmw_private *dev_priv, |
|---|
| 2910 | | - struct vmw_display_unit *du) |
|---|
| 2911 | | -{ |
|---|
| 2912 | | - mutex_lock(&dev_priv->global_kms_state_mutex); |
|---|
| 2913 | | - if (du->active_implicit) { |
|---|
| 2914 | | - if (--(dev_priv->num_implicit) == 0) |
|---|
| 2915 | | - dev_priv->implicit_fb = NULL; |
|---|
| 2916 | | - du->active_implicit = false; |
|---|
| 2917 | | - } |
|---|
| 2918 | | - mutex_unlock(&dev_priv->global_kms_state_mutex); |
|---|
| 2919 | | -} |
|---|
| 2920 | | - |
|---|
| 2921 | | -/** |
|---|
| 2922 | | - * vmw_kms_add_active - register a crtc binding to an implicit framebuffer |
|---|
| 2923 | | - * |
|---|
| 2924 | | - * @vmw_priv: Pointer to a device private struct. |
|---|
| 2925 | | - * @du: The display unit of the crtc. |
|---|
| 2926 | | - * @vfb: The implicit framebuffer |
|---|
| 2927 | | - * |
|---|
| 2928 | | - * Registers a binding to an implicit framebuffer. |
|---|
| 2929 | | - */ |
|---|
| 2930 | | -void vmw_kms_add_active(struct vmw_private *dev_priv, |
|---|
| 2931 | | - struct vmw_display_unit *du, |
|---|
| 2932 | | - struct vmw_framebuffer *vfb) |
|---|
| 2933 | | -{ |
|---|
| 2934 | | - mutex_lock(&dev_priv->global_kms_state_mutex); |
|---|
| 2935 | | - WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); |
|---|
| 2936 | | - |
|---|
| 2937 | | - if (!du->active_implicit && du->is_implicit) { |
|---|
| 2938 | | - dev_priv->implicit_fb = vfb; |
|---|
| 2939 | | - du->active_implicit = true; |
|---|
| 2940 | | - dev_priv->num_implicit++; |
|---|
| 2941 | | - } |
|---|
| 2942 | | - mutex_unlock(&dev_priv->global_kms_state_mutex); |
|---|
| 2943 | | -} |
|---|
| 2944 | | - |
|---|
| 2945 | | -/** |
|---|
| 2946 | | - * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc. |
|---|
| 2947 | | - * |
|---|
| 2948 | | - * @dev_priv: Pointer to device-private struct. |
|---|
| 2949 | | - * @crtc: The crtc we want to flip. |
|---|
| 2950 | | - * |
|---|
| 2951 | | - * Returns true or false depending whether it's OK to flip this crtc |
|---|
| 2952 | | - * based on the criterion that we must not have more than one implicit |
|---|
| 2953 | | - * frame-buffer at any one time. |
|---|
| 2954 | | - */ |
|---|
| 2955 | | -bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, |
|---|
| 2956 | | - struct drm_crtc *crtc) |
|---|
| 2957 | | -{ |
|---|
| 2958 | | - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|---|
| 2959 | | - bool ret; |
|---|
| 2960 | | - |
|---|
| 2961 | | - mutex_lock(&dev_priv->global_kms_state_mutex); |
|---|
| 2962 | | - ret = !du->is_implicit || dev_priv->num_implicit == 1; |
|---|
| 2963 | | - mutex_unlock(&dev_priv->global_kms_state_mutex); |
|---|
| 2964 | | - |
|---|
| 2965 | | - return ret; |
|---|
| 2966 | | -} |
|---|
| 2967 | | - |
|---|
| 2968 | | -/** |
|---|
| 2969 | | - * vmw_kms_update_implicit_fb - Update the implicit fb. |
|---|
| 2970 | | - * |
|---|
| 2971 | | - * @dev_priv: Pointer to device-private struct. |
|---|
| 2972 | | - * @crtc: The crtc the new implicit frame-buffer is bound to. |
|---|
| 2973 | | - */ |
|---|
| 2974 | | -void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, |
|---|
| 2975 | | - struct drm_crtc *crtc) |
|---|
| 2976 | | -{ |
|---|
| 2977 | | - struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|---|
| 2978 | | - struct drm_plane *plane = crtc->primary; |
|---|
| 2979 | | - struct vmw_framebuffer *vfb; |
|---|
| 2980 | | - |
|---|
| 2981 | | - mutex_lock(&dev_priv->global_kms_state_mutex); |
|---|
| 2982 | | - |
|---|
| 2983 | | - if (!du->is_implicit) |
|---|
| 2984 | | - goto out_unlock; |
|---|
| 2985 | | - |
|---|
| 2986 | | - vfb = vmw_framebuffer_to_vfb(plane->state->fb); |
|---|
| 2987 | | - WARN_ON_ONCE(dev_priv->num_implicit != 1 && |
|---|
| 2988 | | - dev_priv->implicit_fb != vfb); |
|---|
| 2989 | | - |
|---|
| 2990 | | - dev_priv->implicit_fb = vfb; |
|---|
| 2991 | | -out_unlock: |
|---|
| 2992 | | - mutex_unlock(&dev_priv->global_kms_state_mutex); |
|---|
| 2993 | | -} |
|---|
| 2994 | | - |
|---|
| 2995 | | -/** |
|---|
| 2996 | 2619 | * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement |
|---|
| 2997 | 2620 | * property. |
|---|
| 2998 | 2621 | * |
|---|
| 2999 | 2622 | * @dev_priv: Pointer to a device private struct. |
|---|
| 3000 | | - * @immutable: Whether the property is immutable. |
|---|
| 3001 | 2623 | * |
|---|
| 3002 | 2624 | * Sets up the implicit placement property unless it's already set up. |
|---|
| 3003 | 2625 | */ |
|---|
| 3004 | 2626 | void |
|---|
| 3005 | | -vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, |
|---|
| 3006 | | - bool immutable) |
|---|
| 2627 | +vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv) |
|---|
| 3007 | 2628 | { |
|---|
| 3008 | 2629 | if (dev_priv->implicit_placement_property) |
|---|
| 3009 | 2630 | return; |
|---|
| 3010 | 2631 | |
|---|
| 3011 | 2632 | dev_priv->implicit_placement_property = |
|---|
| 3012 | 2633 | drm_property_create_range(dev_priv->dev, |
|---|
| 3013 | | - immutable ? |
|---|
| 3014 | | - DRM_MODE_PROP_IMMUTABLE : 0, |
|---|
| 2634 | + DRM_MODE_PROP_IMMUTABLE, |
|---|
| 3015 | 2635 | "implicit_placement", 0, 1); |
|---|
| 3016 | | - |
|---|
| 3017 | 2636 | } |
|---|
| 3018 | | - |
|---|
| 3019 | | - |
|---|
| 3020 | | -/** |
|---|
| 3021 | | - * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config |
|---|
| 3022 | | - * |
|---|
| 3023 | | - * @set: The configuration to set. |
|---|
| 3024 | | - * |
|---|
| 3025 | | - * The vmwgfx Xorg driver doesn't assign the mode::type member, which |
|---|
| 3026 | | - * when drm_mode_set_crtcinfo is called as part of the configuration setting |
|---|
| 3027 | | - * causes it to return incorrect crtc dimensions causing severe problems in |
|---|
| 3028 | | - * the vmwgfx modesetting. So explicitly clear that member before calling |
|---|
| 3029 | | - * into drm_atomic_helper_set_config. |
|---|
| 3030 | | - */ |
|---|
| 3031 | | -int vmw_kms_set_config(struct drm_mode_set *set, |
|---|
| 3032 | | - struct drm_modeset_acquire_ctx *ctx) |
|---|
| 3033 | | -{ |
|---|
| 3034 | | - if (set && set->mode) |
|---|
| 3035 | | - set->mode->type = 0; |
|---|
| 3036 | | - |
|---|
| 3037 | | - return drm_atomic_helper_set_config(set, ctx); |
|---|
| 3038 | | -} |
|---|
| 3039 | | - |
|---|
| 3040 | 2637 | |
|---|
| 3041 | 2638 | /** |
|---|
| 3042 | 2639 | * vmw_kms_suspend - Save modesetting state and turn modesetting off. |
|---|
| .. | .. |
|---|
| 3094 | 2691 | { |
|---|
| 3095 | 2692 | drm_atomic_helper_shutdown(dev); |
|---|
| 3096 | 2693 | } |
|---|
| 2694 | + |
|---|
| 2695 | +/** |
|---|
| 2696 | + * vmw_du_helper_plane_update - Helper to do plane update on a display unit. |
|---|
| 2697 | + * @update: The closure structure. |
|---|
| 2698 | + * |
|---|
| 2699 | + * Call this helper after setting callbacks in &vmw_du_update_plane to do plane |
|---|
| 2700 | + * update on display unit. |
|---|
| 2701 | + * |
|---|
| 2702 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 2703 | + */ |
|---|
| 2704 | +int vmw_du_helper_plane_update(struct vmw_du_update_plane *update) |
|---|
| 2705 | +{ |
|---|
| 2706 | + struct drm_plane_state *state = update->plane->state; |
|---|
| 2707 | + struct drm_plane_state *old_state = update->old_state; |
|---|
| 2708 | + struct drm_atomic_helper_damage_iter iter; |
|---|
| 2709 | + struct drm_rect clip; |
|---|
| 2710 | + struct drm_rect bb; |
|---|
| 2711 | + DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); |
|---|
| 2712 | + uint32_t reserved_size = 0; |
|---|
| 2713 | + uint32_t submit_size = 0; |
|---|
| 2714 | + uint32_t curr_size = 0; |
|---|
| 2715 | + uint32_t num_hits = 0; |
|---|
| 2716 | + void *cmd_start; |
|---|
| 2717 | + char *cmd_next; |
|---|
| 2718 | + int ret; |
|---|
| 2719 | + |
|---|
| 2720 | + /* |
|---|
| 2721 | + * Iterate in advance to check if really need plane update and find the |
|---|
| 2722 | + * number of clips that actually are in plane src for fifo allocation. |
|---|
| 2723 | + */ |
|---|
| 2724 | + drm_atomic_helper_damage_iter_init(&iter, old_state, state); |
|---|
| 2725 | + drm_atomic_for_each_plane_damage(&iter, &clip) |
|---|
| 2726 | + num_hits++; |
|---|
| 2727 | + |
|---|
| 2728 | + if (num_hits == 0) |
|---|
| 2729 | + return 0; |
|---|
| 2730 | + |
|---|
| 2731 | + if (update->vfb->bo) { |
|---|
| 2732 | + struct vmw_framebuffer_bo *vfbbo = |
|---|
| 2733 | + container_of(update->vfb, typeof(*vfbbo), base); |
|---|
| 2734 | + |
|---|
| 2735 | + ret = vmw_validation_add_bo(&val_ctx, vfbbo->buffer, false, |
|---|
| 2736 | + update->cpu_blit); |
|---|
| 2737 | + } else { |
|---|
| 2738 | + struct vmw_framebuffer_surface *vfbs = |
|---|
| 2739 | + container_of(update->vfb, typeof(*vfbs), base); |
|---|
| 2740 | + |
|---|
| 2741 | + ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res, |
|---|
| 2742 | + 0, VMW_RES_DIRTY_NONE, NULL, |
|---|
| 2743 | + NULL); |
|---|
| 2744 | + } |
|---|
| 2745 | + |
|---|
| 2746 | + if (ret) |
|---|
| 2747 | + return ret; |
|---|
| 2748 | + |
|---|
| 2749 | + ret = vmw_validation_prepare(&val_ctx, update->mutex, update->intr); |
|---|
| 2750 | + if (ret) |
|---|
| 2751 | + goto out_unref; |
|---|
| 2752 | + |
|---|
| 2753 | + reserved_size = update->calc_fifo_size(update, num_hits); |
|---|
| 2754 | + cmd_start = VMW_FIFO_RESERVE(update->dev_priv, reserved_size); |
|---|
| 2755 | + if (!cmd_start) { |
|---|
| 2756 | + ret = -ENOMEM; |
|---|
| 2757 | + goto out_revert; |
|---|
| 2758 | + } |
|---|
| 2759 | + |
|---|
| 2760 | + cmd_next = cmd_start; |
|---|
| 2761 | + |
|---|
| 2762 | + if (update->post_prepare) { |
|---|
| 2763 | + curr_size = update->post_prepare(update, cmd_next); |
|---|
| 2764 | + cmd_next += curr_size; |
|---|
| 2765 | + submit_size += curr_size; |
|---|
| 2766 | + } |
|---|
| 2767 | + |
|---|
| 2768 | + if (update->pre_clip) { |
|---|
| 2769 | + curr_size = update->pre_clip(update, cmd_next, num_hits); |
|---|
| 2770 | + cmd_next += curr_size; |
|---|
| 2771 | + submit_size += curr_size; |
|---|
| 2772 | + } |
|---|
| 2773 | + |
|---|
| 2774 | + bb.x1 = INT_MAX; |
|---|
| 2775 | + bb.y1 = INT_MAX; |
|---|
| 2776 | + bb.x2 = INT_MIN; |
|---|
| 2777 | + bb.y2 = INT_MIN; |
|---|
| 2778 | + |
|---|
| 2779 | + drm_atomic_helper_damage_iter_init(&iter, old_state, state); |
|---|
| 2780 | + drm_atomic_for_each_plane_damage(&iter, &clip) { |
|---|
| 2781 | + uint32_t fb_x = clip.x1; |
|---|
| 2782 | + uint32_t fb_y = clip.y1; |
|---|
| 2783 | + |
|---|
| 2784 | + vmw_du_translate_to_crtc(state, &clip); |
|---|
| 2785 | + if (update->clip) { |
|---|
| 2786 | + curr_size = update->clip(update, cmd_next, &clip, fb_x, |
|---|
| 2787 | + fb_y); |
|---|
| 2788 | + cmd_next += curr_size; |
|---|
| 2789 | + submit_size += curr_size; |
|---|
| 2790 | + } |
|---|
| 2791 | + bb.x1 = min_t(int, bb.x1, clip.x1); |
|---|
| 2792 | + bb.y1 = min_t(int, bb.y1, clip.y1); |
|---|
| 2793 | + bb.x2 = max_t(int, bb.x2, clip.x2); |
|---|
| 2794 | + bb.y2 = max_t(int, bb.y2, clip.y2); |
|---|
| 2795 | + } |
|---|
| 2796 | + |
|---|
| 2797 | + curr_size = update->post_clip(update, cmd_next, &bb); |
|---|
| 2798 | + submit_size += curr_size; |
|---|
| 2799 | + |
|---|
| 2800 | + if (reserved_size < submit_size) |
|---|
| 2801 | + submit_size = 0; |
|---|
| 2802 | + |
|---|
| 2803 | + vmw_fifo_commit(update->dev_priv, submit_size); |
|---|
| 2804 | + |
|---|
| 2805 | + vmw_kms_helper_validation_finish(update->dev_priv, NULL, &val_ctx, |
|---|
| 2806 | + update->out_fence, NULL); |
|---|
| 2807 | + return ret; |
|---|
| 2808 | + |
|---|
| 2809 | +out_revert: |
|---|
| 2810 | + vmw_validation_revert(&val_ctx); |
|---|
| 2811 | + |
|---|
| 2812 | +out_unref: |
|---|
| 2813 | + vmw_validation_unref_lists(&val_ctx); |
|---|
| 2814 | + return ret; |
|---|
| 2815 | +} |
|---|