aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c280
1 files changed, 132 insertions, 148 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index b68d74888ab1..8eec88920851 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -114,7 +114,6 @@ struct vmw_screen_target_display_unit {
114 bool defined; 114 bool defined;
115 115
116 /* For CPU Blit */ 116 /* For CPU Blit */
117 struct ttm_bo_kmap_obj host_map;
118 unsigned int cpp; 117 unsigned int cpp;
119}; 118};
120 119
@@ -492,71 +491,17 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
492{ 491{
493 struct vmw_private *dev_priv = vmw_priv(crtc->dev); 492 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
494 struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); 493 struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
495 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
496 struct drm_vmw_rect vclips;
497 int ret; 494 int ret;
498 495
499 dev_priv = vmw_priv(crtc->dev);
500 stdu = vmw_crtc_to_stdu(crtc);
501
502 if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) 496 if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
503 return -EINVAL; 497 return -EINVAL;
504 498
505 /* 499 ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx);
506 * We're always async, but the helper doesn't know how to set async
507 * so lie to the helper. Also, the helper expects someone
508 * to pick the event up from the crtc state, and if nobody does,
509 * it will free it. Since we handle the event in this function,
510 * don't hand it to the helper.
511 */
512 flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
513 ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx);
514 if (ret) { 500 if (ret) {
515 DRM_ERROR("Page flip error %d.\n", ret); 501 DRM_ERROR("Page flip error %d.\n", ret);
516 return ret; 502 return ret;
517 } 503 }
518 504
519 if (stdu->base.is_implicit)
520 vmw_kms_update_implicit_fb(dev_priv, crtc);
521
522 /*
523 * Now that we've bound a new surface to the screen target,
524 * update the contents.
525 */
526 vclips.x = crtc->x;
527 vclips.y = crtc->y;
528 vclips.w = crtc->mode.hdisplay;
529 vclips.h = crtc->mode.vdisplay;
530
531 if (vfb->dmabuf)
532 ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips,
533 1, 1, true, false);
534 else
535 ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips,
536 NULL, 0, 0, 1, 1, NULL);
537 if (ret) {
538 DRM_ERROR("Page flip update error %d.\n", ret);
539 return ret;
540 }
541
542 if (event) {
543 struct vmw_fence_obj *fence = NULL;
544 struct drm_file *file_priv = event->base.file_priv;
545
546 vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
547 if (!fence)
548 return -ENOMEM;
549
550 ret = vmw_event_fence_action_queue(file_priv, fence,
551 &event->base,
552 &event->event.vbl.tv_sec,
553 &event->event.vbl.tv_usec,
554 true);
555 vmw_fence_obj_unreference(&fence);
556 } else {
557 (void) vmw_fifo_flush(dev_priv, false);
558 }
559
560 return 0; 505 return 0;
561} 506}
562 507
@@ -693,10 +638,9 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
693 container_of(dirty->unit, typeof(*stdu), base); 638 container_of(dirty->unit, typeof(*stdu), base);
694 s32 width, height; 639 s32 width, height;
695 s32 src_pitch, dst_pitch; 640 s32 src_pitch, dst_pitch;
696 u8 *src, *dst; 641 struct ttm_buffer_object *src_bo, *dst_bo;
697 bool not_used; 642 u32 src_offset, dst_offset;
698 struct ttm_bo_kmap_obj guest_map; 643 struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp);
699 int ret;
700 644
701 if (!dirty->num_hits) 645 if (!dirty->num_hits)
702 return; 646 return;
@@ -707,57 +651,38 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
707 if (width == 0 || height == 0) 651 if (width == 0 || height == 0)
708 return; 652 return;
709 653
710 ret = ttm_bo_kmap(&ddirty->buf->base, 0, ddirty->buf->base.num_pages, 654 /* Assume we are blitting from Guest (dmabuf) to Host (display_srf) */
711 &guest_map); 655 dst_pitch = stdu->display_srf->base_size.width * stdu->cpp;
712 if (ret) { 656 dst_bo = &stdu->display_srf->res.backup->base;
713 DRM_ERROR("Failed mapping framebuffer for blit: %d\n", 657 dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp;
714 ret);
715 goto out_cleanup;
716 }
717
718 /* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */
719 src_pitch = stdu->display_srf->base_size.width * stdu->cpp;
720 src = ttm_kmap_obj_virtual(&stdu->host_map, &not_used);
721 src += ddirty->top * src_pitch + ddirty->left * stdu->cpp;
722
723 dst_pitch = ddirty->pitch;
724 dst = ttm_kmap_obj_virtual(&guest_map, &not_used);
725 dst += ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp;
726
727
728 /* Figure out the real direction */
729 if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
730 u8 *tmp;
731 s32 tmp_pitch;
732
733 tmp = src;
734 tmp_pitch = src_pitch;
735 658
736 src = dst; 659 src_pitch = ddirty->pitch;
737 src_pitch = dst_pitch; 660 src_bo = &ddirty->buf->base;
661 src_offset = ddirty->fb_top * src_pitch + ddirty->fb_left * stdu->cpp;
738 662
739 dst = tmp; 663 /* Swap src and dst if the assumption was wrong. */
740 dst_pitch = tmp_pitch; 664 if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) {
665 swap(dst_pitch, src_pitch);
666 swap(dst_bo, src_bo);
667 swap(src_offset, dst_offset);
741 } 668 }
742 669
743 /* CPU Blit */ 670 (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch,
744 while (height-- > 0) { 671 src_bo, src_offset, src_pitch,
745 memcpy(dst, src, width * stdu->cpp); 672 width * stdu->cpp, height, &diff);
746 dst += dst_pitch;
747 src += src_pitch;
748 }
749 673
750 if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { 674 if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM &&
675 drm_rect_visible(&diff.rect)) {
751 struct vmw_private *dev_priv; 676 struct vmw_private *dev_priv;
752 struct vmw_stdu_update *cmd; 677 struct vmw_stdu_update *cmd;
753 struct drm_clip_rect region; 678 struct drm_clip_rect region;
754 int ret; 679 int ret;
755 680
756 /* We are updating the actual surface, not a proxy */ 681 /* We are updating the actual surface, not a proxy */
757 region.x1 = ddirty->left; 682 region.x1 = diff.rect.x1;
758 region.x2 = ddirty->right; 683 region.x2 = diff.rect.x2;
759 region.y1 = ddirty->top; 684 region.y1 = diff.rect.y1;
760 region.y2 = ddirty->bottom; 685 region.y2 = diff.rect.y2;
761 ret = vmw_kms_update_proxy( 686 ret = vmw_kms_update_proxy(
762 (struct vmw_resource *) &stdu->display_srf->res, 687 (struct vmw_resource *) &stdu->display_srf->res,
763 (const struct drm_clip_rect *) &region, 1, 1); 688 (const struct drm_clip_rect *) &region, 1, 1);
@@ -774,13 +699,12 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
774 } 699 }
775 700
776 vmw_stdu_populate_update(cmd, stdu->base.unit, 701 vmw_stdu_populate_update(cmd, stdu->base.unit,
777 ddirty->left, ddirty->right, 702 region.x1, region.x2,
778 ddirty->top, ddirty->bottom); 703 region.y1, region.y2);
779 704
780 vmw_fifo_commit(dev_priv, sizeof(*cmd)); 705 vmw_fifo_commit(dev_priv, sizeof(*cmd));
781 } 706 }
782 707
783 ttm_bo_kunmap(&guest_map);
784out_cleanup: 708out_cleanup:
785 ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; 709 ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX;
786 ddirty->right = ddirty->bottom = S32_MIN; 710 ddirty->right = ddirty->bottom = S32_MIN;
@@ -802,6 +726,7 @@ out_cleanup:
802 * @to_surface: Whether to DMA to the screen target system as opposed to 726 * @to_surface: Whether to DMA to the screen target system as opposed to
803 * from the screen target system. 727 * from the screen target system.
804 * @interruptible: Whether to perform waits interruptible if possible. 728 * @interruptible: Whether to perform waits interruptible if possible.
729 * @crtc: If crtc is passed, perform stdu dma on that crtc only.
805 * 730 *
806 * If DMA-ing till the screen target system, the function will also notify 731 * If DMA-ing till the screen target system, the function will also notify
807 * the screen target system that a bounding box of the cliprects has been 732 * the screen target system that a bounding box of the cliprects has been
@@ -818,15 +743,22 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
818 uint32_t num_clips, 743 uint32_t num_clips,
819 int increment, 744 int increment,
820 bool to_surface, 745 bool to_surface,
821 bool interruptible) 746 bool interruptible,
747 struct drm_crtc *crtc)
822{ 748{
823 struct vmw_dma_buffer *buf = 749 struct vmw_dma_buffer *buf =
824 container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; 750 container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer;
825 struct vmw_stdu_dirty ddirty; 751 struct vmw_stdu_dirty ddirty;
826 int ret; 752 int ret;
753 bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D);
827 754
755 /*
756 * VMs without 3D support don't have the surface DMA command and
757 * we'll be using a CPU blit, and the framebuffer should be moved out
758 * of VRAM.
759 */
828 ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, 760 ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible,
829 false); 761 false, cpu_blit);
830 if (ret) 762 if (ret)
831 return ret; 763 return ret;
832 764
@@ -845,13 +777,15 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
845 if (to_surface) 777 if (to_surface)
846 ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); 778 ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update);
847 779
848 /* 2D VMs cannot use SVGA_3D_CMD_SURFACE_DMA so do CPU blit instead */ 780
849 if (!(dev_priv->capabilities & SVGA_CAP_3D)) { 781 if (cpu_blit) {
850 ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; 782 ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit;
851 ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; 783 ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip;
852 ddirty.base.fifo_reserve_size = 0; 784 ddirty.base.fifo_reserve_size = 0;
853 } 785 }
854 786
787 ddirty.base.crtc = crtc;
788
855 ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, 789 ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips,
856 0, 0, num_clips, increment, &ddirty.base); 790 0, 0, num_clips, increment, &ddirty.base);
857 vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, 791 vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
@@ -963,6 +897,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty)
963 * @out_fence: If non-NULL, will return a ref-counted pointer to a 897 * @out_fence: If non-NULL, will return a ref-counted pointer to a
964 * struct vmw_fence_obj. The returned fence pointer may be NULL in which 898 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
965 * case the device has already synchronized. 899 * case the device has already synchronized.
900 * @crtc: If crtc is passed, perform surface dirty on that crtc only.
966 * 901 *
967 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 902 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
968 * interrupted. 903 * interrupted.
@@ -975,7 +910,8 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
975 s32 dest_x, 910 s32 dest_x,
976 s32 dest_y, 911 s32 dest_y,
977 unsigned num_clips, int inc, 912 unsigned num_clips, int inc,
978 struct vmw_fence_obj **out_fence) 913 struct vmw_fence_obj **out_fence,
914 struct drm_crtc *crtc)
979{ 915{
980 struct vmw_framebuffer_surface *vfbs = 916 struct vmw_framebuffer_surface *vfbs =
981 container_of(framebuffer, typeof(*vfbs), base); 917 container_of(framebuffer, typeof(*vfbs), base);
@@ -1000,6 +936,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
1000 sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + 936 sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) +
1001 sizeof(SVGA3dCopyBox) * num_clips + 937 sizeof(SVGA3dCopyBox) * num_clips +
1002 sizeof(struct vmw_stdu_update); 938 sizeof(struct vmw_stdu_update);
939 sdirty.base.crtc = crtc;
1003 sdirty.sid = srf->id; 940 sdirty.sid = srf->id;
1004 sdirty.left = sdirty.top = S32_MAX; 941 sdirty.left = sdirty.top = S32_MAX;
1005 sdirty.right = sdirty.bottom = S32_MIN; 942 sdirty.right = sdirty.bottom = S32_MIN;
@@ -1118,9 +1055,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
1118{ 1055{
1119 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 1056 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
1120 1057
1121 if (vps->host_map.virtual)
1122 ttm_bo_kunmap(&vps->host_map);
1123
1124 if (vps->surf) 1058 if (vps->surf)
1125 WARN_ON(!vps->pinned); 1059 WARN_ON(!vps->pinned);
1126 1060
@@ -1282,24 +1216,11 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
1282 * so cache these mappings 1216 * so cache these mappings
1283 */ 1217 */
1284 if (vps->content_fb_type == SEPARATE_DMA && 1218 if (vps->content_fb_type == SEPARATE_DMA &&
1285 !(dev_priv->capabilities & SVGA_CAP_3D)) { 1219 !(dev_priv->capabilities & SVGA_CAP_3D))
1286 ret = ttm_bo_kmap(&vps->surf->res.backup->base, 0,
1287 vps->surf->res.backup->base.num_pages,
1288 &vps->host_map);
1289 if (ret) {
1290 DRM_ERROR("Failed to map display buffer to CPU\n");
1291 goto out_srf_unpin;
1292 }
1293
1294 vps->cpp = new_fb->pitches[0] / new_fb->width; 1220 vps->cpp = new_fb->pitches[0] / new_fb->width;
1295 }
1296 1221
1297 return 0; 1222 return 0;
1298 1223
1299out_srf_unpin:
1300 vmw_resource_unpin(&vps->surf->res);
1301 vps->pinned--;
1302
1303out_srf_unref: 1224out_srf_unref:
1304 vmw_surface_unreference(&vps->surf); 1225 vmw_surface_unreference(&vps->surf);
1305 return ret; 1226 return ret;
@@ -1322,41 +1243,104 @@ static void
1322vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, 1243vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1323 struct drm_plane_state *old_state) 1244 struct drm_plane_state *old_state)
1324{ 1245{
1325 struct vmw_private *dev_priv;
1326 struct vmw_screen_target_display_unit *stdu;
1327 struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); 1246 struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
1328 struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; 1247 struct drm_crtc *crtc = plane->state->crtc;
1248 struct vmw_screen_target_display_unit *stdu;
1249 struct drm_pending_vblank_event *event;
1250 struct vmw_private *dev_priv;
1329 int ret; 1251 int ret;
1330 1252
1331 stdu = vmw_crtc_to_stdu(crtc); 1253 /*
1332 dev_priv = vmw_priv(crtc->dev); 1254 * We cannot really fail this function, so if we do, then output an
1255 * error and maintain consistent atomic state.
1256 */
1257 if (crtc && plane->state->fb) {
1258 struct vmw_framebuffer *vfb =
1259 vmw_framebuffer_to_vfb(plane->state->fb);
1260 struct drm_vmw_rect vclips;
1261 stdu = vmw_crtc_to_stdu(crtc);
1262 dev_priv = vmw_priv(crtc->dev);
1263
1264 stdu->display_srf = vps->surf;
1265 stdu->content_fb_type = vps->content_fb_type;
1266 stdu->cpp = vps->cpp;
1267
1268 vclips.x = crtc->x;
1269 vclips.y = crtc->y;
1270 vclips.w = crtc->mode.hdisplay;
1271 vclips.h = crtc->mode.vdisplay;
1272
1273 ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
1274 if (ret)
1275 DRM_ERROR("Failed to bind surface to STDU.\n");
1276
1277 if (vfb->dmabuf)
1278 ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL,
1279 &vclips, 1, 1, true, false,
1280 crtc);
1281 else
1282 ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL,
1283 &vclips, NULL, 0, 0,
1284 1, 1, NULL, crtc);
1285 if (ret)
1286 DRM_ERROR("Failed to update STDU.\n");
1333 1287
1334 stdu->display_srf = vps->surf; 1288 crtc->primary->fb = plane->state->fb;
1335 stdu->content_fb_type = vps->content_fb_type; 1289 } else {
1336 stdu->cpp = vps->cpp; 1290 crtc = old_state->crtc;
1337 memcpy(&stdu->host_map, &vps->host_map, sizeof(vps->host_map)); 1291 stdu = vmw_crtc_to_stdu(crtc);
1292 dev_priv = vmw_priv(crtc->dev);
1338 1293
1339 if (!stdu->defined) 1294 /*
1340 return; 1295 * When disabling a plane, CRTC and FB should always be NULL
1296 * together, otherwise it's an error.
1297 * Here primary plane is being disable so blank the screen
1298 * target display unit, if not already done.
1299 */
1300 if (!stdu->defined)
1301 return;
1341 1302
1342 if (plane->state->fb)
1343 ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
1344 else
1345 ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); 1303 ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
1304 if (ret)
1305 DRM_ERROR("Failed to blank STDU\n");
1306
1307 ret = vmw_stdu_update_st(dev_priv, stdu);
1308 if (ret)
1309 DRM_ERROR("Failed to update STDU.\n");
1310
1311 return;
1312 }
1346 1313
1314 event = crtc->state->event;
1347 /* 1315 /*
1348 * We cannot really fail this function, so if we do, then output an 1316 * In case of failure and other cases, vblank event will be sent in
1349 * error and quit 1317 * vmw_du_crtc_atomic_flush.
1350 */ 1318 */
1351 if (ret) 1319 if (event && (ret == 0)) {
1352 DRM_ERROR("Failed to bind surface to STDU.\n"); 1320 struct vmw_fence_obj *fence = NULL;
1353 else 1321 struct drm_file *file_priv = event->base.file_priv;
1354 crtc->primary->fb = plane->state->fb;
1355 1322
1356 ret = vmw_stdu_update_st(dev_priv, stdu); 1323 vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
1357 1324
1358 if (ret) 1325 /*
1359 DRM_ERROR("Failed to update STDU.\n"); 1326 * If fence is NULL, then already sync.
1327 */
1328 if (fence) {
1329 ret = vmw_event_fence_action_queue(
1330 file_priv, fence, &event->base,
1331 &event->event.vbl.tv_sec,
1332 &event->event.vbl.tv_usec,
1333 true);
1334 if (ret)
1335 DRM_ERROR("Failed to queue event on fence.\n");
1336 else
1337 crtc->state->event = NULL;
1338
1339 vmw_fence_obj_unreference(&fence);
1340 }
1341 } else {
1342 (void) vmw_fifo_flush(dev_priv, false);
1343 }
1360} 1344}
1361 1345
1362 1346