aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSinclair Yeh <syeh@vmware.com>2017-03-23 17:29:22 -0400
committerSinclair Yeh <syeh@vmware.com>2017-03-31 18:21:12 -0400
commit904bb5e5817f5c5b42e6e3775699c728fd420284 (patch)
tree57628b2490c84b9ef8c2f25cd5d926aff9e73e68
parentaa74f0687cfe998e59b20d6454f45e8aa4403c45 (diff)
drm/vmwgfx: Switch over to internal atomic API for STDU
Switch over to using internal atomic API for mode set. This removes the legacy set_config API, replacing it with drm_atomic_helper_set_config(). The DRM helper will use various vmwgfx-specific atomic functions to set a mode. DRIVER_ATOMIC capability flag is not yet set, so the user mode will still use the legacy mode set IOCTL. v2: * Avoid a clash between page-flip pinning and setcrtc pinning, modify the page-flip code to use the page-flip helper and the atomic callbacks. To enable this, we will need to add a wrapper around atomic_commit. * Add vmw_kms_set_config() to work around vmwgfx xorg driver bug Signed-off-by: Sinclair Yeh <syeh@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c20
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c325
3 files changed, 51 insertions, 295 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 1071e1075da8..fe226e723287 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -2885,3 +2885,23 @@ vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv,
2885 "implicit_placement", 0, 1); 2885 "implicit_placement", 0, 1);
2886 2886
2887} 2887}
2888
2889
2890/**
2891 * vmw_kms_set_config - Wrapper around drm_atomic_helper_set_config
2892 *
2893 * @set: The configuration to set.
2894 *
2895 * The vmwgfx Xorg driver doesn't assign the mode::type member, which
2896 * when drm_mode_set_crtcinfo is called as part of the configuration setting
2897 * causes it to return incorrect crtc dimensions causing severe problems in
2898 * the vmwgfx modesetting. So explicitly clear that member before calling
2899 * into drm_atomic_helper_set_config.
2900 */
2901int vmw_kms_set_config(struct drm_mode_set *set)
2902{
2903 if (set && set->mode)
2904 set->mode->type = 0;
2905
2906 return drm_atomic_helper_set_config(set);
2907}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index de6a0b64bb4b..7689f477b726 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -449,5 +449,6 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
449 bool to_surface, 449 bool to_surface,
450 bool interruptible); 450 bool interruptible);
451 451
452int vmw_kms_set_config(struct drm_mode_set *set);
452 453
453#endif 454#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index 76ca5fa1e3bf..b7999eb4f5fc 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -104,8 +104,7 @@ struct vmw_stdu_surface_copy {
104 */ 104 */
105struct vmw_screen_target_display_unit { 105struct vmw_screen_target_display_unit {
106 struct vmw_display_unit base; 106 struct vmw_display_unit base;
107 107 const struct vmw_surface *display_srf;
108 struct vmw_surface *display_srf;
109 enum stdu_content_type content_fb_type; 108 enum stdu_content_type content_fb_type;
110 109
111 bool defined; 110 bool defined;
@@ -118,32 +117,6 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);
118 117
119 118
120/****************************************************************************** 119/******************************************************************************
121 * Screen Target Display Unit helper Functions
122 *****************************************************************************/
123
124/**
125 * vmw_stdu_unpin_display - unpins the resource associated with display surface
126 *
127 * @stdu: contains the display surface
128 *
129 * If the display surface was privatedly allocated by
130 * vmw_surface_gb_priv_define() and not registered as a framebuffer, then it
131 * won't be automatically cleaned up when all the framebuffers are freed. As
132 * such, we have to explicitly call vmw_resource_unreference() to get it freed.
133 */
134static void vmw_stdu_unpin_display(struct vmw_screen_target_display_unit *stdu)
135{
136 if (stdu->display_srf) {
137 struct vmw_resource *res = &stdu->display_srf->res;
138
139 vmw_resource_unpin(res);
140 vmw_surface_unreference(&stdu->display_srf);
141 }
142}
143
144
145
146/******************************************************************************
147 * Screen Target Display Unit CRTC Functions 120 * Screen Target Display Unit CRTC Functions
148 *****************************************************************************/ 121 *****************************************************************************/
149 122
@@ -228,7 +201,7 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv,
228 */ 201 */
229static int vmw_stdu_bind_st(struct vmw_private *dev_priv, 202static int vmw_stdu_bind_st(struct vmw_private *dev_priv,
230 struct vmw_screen_target_display_unit *stdu, 203 struct vmw_screen_target_display_unit *stdu,
231 struct vmw_resource *res) 204 const struct vmw_resource *res)
232{ 205{
233 SVGA3dSurfaceImageId image; 206 SVGA3dSurfaceImageId image;
234 207
@@ -377,129 +350,6 @@ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv,
377 return ret; 350 return ret;
378} 351}
379 352
380/**
381 * vmw_stdu_bind_fb - Bind an fb to a defined screen target
382 *
383 * @dev_priv: Pointer to a device private struct.
384 * @crtc: The crtc holding the screen target.
385 * @mode: The mode currently used by the screen target. Must be non-NULL.
386 * @new_fb: The new framebuffer to bind. Must be non-NULL.
387 *
388 * RETURNS:
389 * 0 on success, error code on failure.
390 */
391static int vmw_stdu_bind_fb(struct vmw_private *dev_priv,
392 struct drm_crtc *crtc,
393 struct drm_display_mode *mode,
394 struct drm_framebuffer *new_fb)
395{
396 struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
397 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
398 struct vmw_surface *new_display_srf = NULL;
399 enum stdu_content_type new_content_type;
400 struct vmw_framebuffer_surface *new_vfbs;
401 int ret;
402
403 WARN_ON_ONCE(!stdu->defined);
404
405 new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
406
407 if (new_vfbs && new_vfbs->surface->base_size.width == mode->hdisplay &&
408 new_vfbs->surface->base_size.height == mode->vdisplay)
409 new_content_type = SAME_AS_DISPLAY;
410 else if (vfb->dmabuf)
411 new_content_type = SEPARATE_DMA;
412 else
413 new_content_type = SEPARATE_SURFACE;
414
415 if (new_content_type != SAME_AS_DISPLAY &&
416 !stdu->display_srf) {
417 struct vmw_surface content_srf;
418 struct drm_vmw_size display_base_size = {0};
419
420 display_base_size.width = mode->hdisplay;
421 display_base_size.height = mode->vdisplay;
422 display_base_size.depth = 1;
423
424 /*
425 * If content buffer is a DMA buf, then we have to construct
426 * surface info
427 */
428 if (new_content_type == SEPARATE_DMA) {
429
430 switch (new_fb->format->cpp[0] * 8) {
431 case 32:
432 content_srf.format = SVGA3D_X8R8G8B8;
433 break;
434
435 case 16:
436 content_srf.format = SVGA3D_R5G6B5;
437 break;
438
439 case 8:
440 content_srf.format = SVGA3D_P8;
441 break;
442
443 default:
444 DRM_ERROR("Invalid format\n");
445 return -EINVAL;
446 }
447
448 content_srf.flags = 0;
449 content_srf.mip_levels[0] = 1;
450 content_srf.multisample_count = 0;
451 } else {
452 content_srf = *new_vfbs->surface;
453 }
454
455
456 ret = vmw_surface_gb_priv_define(crtc->dev,
457 0, /* because kernel visible only */
458 content_srf.flags,
459 content_srf.format,
460 true, /* a scanout buffer */
461 content_srf.mip_levels[0],
462 content_srf.multisample_count,
463 0,
464 display_base_size,
465 &new_display_srf);
466 if (unlikely(ret != 0)) {
467 DRM_ERROR("Could not allocate screen target surface.\n");
468 return ret;
469 }
470 } else if (new_content_type == SAME_AS_DISPLAY) {
471 new_display_srf = vmw_surface_reference(new_vfbs->surface);
472 }
473
474 if (new_display_srf) {
475 /* Pin new surface before flipping */
476 ret = vmw_resource_pin(&new_display_srf->res, false);
477 if (ret)
478 goto out_srf_unref;
479
480 ret = vmw_stdu_bind_st(dev_priv, stdu, &new_display_srf->res);
481 if (ret)
482 goto out_srf_unpin;
483
484 /* Unpin and unreference old surface */
485 vmw_stdu_unpin_display(stdu);
486
487 /* Transfer the reference */
488 stdu->display_srf = new_display_srf;
489 new_display_srf = NULL;
490 }
491
492 crtc->primary->fb = new_fb;
493 stdu->content_fb_type = new_content_type;
494 return 0;
495
496out_srf_unpin:
497 vmw_resource_unpin(&new_display_srf->res);
498out_srf_unref:
499 vmw_surface_unreference(&new_display_srf);
500 return ret;
501}
502
503 353
504/** 354/**
505 * vmw_stdu_crtc_mode_set_nofb - Updates screen target size 355 * vmw_stdu_crtc_mode_set_nofb - Updates screen target size
@@ -601,136 +451,6 @@ static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc)
601} 451}
602 452
603/** 453/**
604 * vmw_stdu_crtc_set_config - Sets a mode
605 *
606 * @set: mode parameters
607 *
608 * This function is the device-specific portion of the DRM CRTC mode set.
609 * For the SVGA device, we do this by defining a Screen Target, binding a
610 * GB Surface to that target, and finally update the screen target.
611 *
612 * RETURNS:
613 * 0 on success, error code otherwise
614 */
615static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
616{
617 struct vmw_private *dev_priv;
618 struct vmw_framebuffer *vfb;
619 struct vmw_screen_target_display_unit *stdu;
620 struct drm_display_mode *mode;
621 struct drm_framebuffer *new_fb;
622 struct drm_crtc *crtc;
623 struct drm_encoder *encoder;
624 struct drm_connector *connector;
625 bool turning_off;
626 int ret;
627
628
629 if (!set || !set->crtc)
630 return -EINVAL;
631
632 crtc = set->crtc;
633 stdu = vmw_crtc_to_stdu(crtc);
634 mode = set->mode;
635 new_fb = set->fb;
636 dev_priv = vmw_priv(crtc->dev);
637 turning_off = set->num_connectors == 0 || !mode || !new_fb;
638 vfb = (new_fb) ? vmw_framebuffer_to_vfb(new_fb) : NULL;
639
640 if (set->num_connectors > 1) {
641 DRM_ERROR("Too many connectors\n");
642 return -EINVAL;
643 }
644
645 if (set->num_connectors == 1 &&
646 set->connectors[0] != &stdu->base.connector) {
647 DRM_ERROR("Connectors don't match %p %p\n",
648 set->connectors[0], &stdu->base.connector);
649 return -EINVAL;
650 }
651
652 if (!turning_off && (set->x + mode->hdisplay > new_fb->width ||
653 set->y + mode->vdisplay > new_fb->height)) {
654 DRM_ERROR("Set outside of framebuffer\n");
655 return -EINVAL;
656 }
657
658 /* Only one active implicit frame-buffer at a time. */
659 mutex_lock(&dev_priv->global_kms_state_mutex);
660 if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb &&
661 !(dev_priv->num_implicit == 1 && stdu->base.active_implicit)
662 && dev_priv->implicit_fb != vfb) {
663 mutex_unlock(&dev_priv->global_kms_state_mutex);
664 DRM_ERROR("Multiple implicit framebuffers not supported.\n");
665 return -EINVAL;
666 }
667 mutex_unlock(&dev_priv->global_kms_state_mutex);
668
669 /* Since they always map one to one these are safe */
670 connector = &stdu->base.connector;
671 encoder = &stdu->base.encoder;
672
673 if (stdu->defined) {
674 ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
675 if (ret)
676 return ret;
677
678 vmw_stdu_unpin_display(stdu);
679 (void) vmw_stdu_update_st(dev_priv, stdu);
680 vmw_kms_del_active(dev_priv, &stdu->base);
681
682 ret = vmw_stdu_destroy_st(dev_priv, stdu);
683 if (ret)
684 return ret;
685
686 crtc->primary->fb = NULL;
687 crtc->enabled = false;
688 encoder->crtc = NULL;
689 connector->encoder = NULL;
690 stdu->content_fb_type = SAME_AS_DISPLAY;
691 crtc->x = set->x;
692 crtc->y = set->y;
693 }
694
695 if (turning_off)
696 return 0;
697
698 /*
699 * Steps to displaying a surface, assume surface is already
700 * bound:
701 * 1. define a screen target
702 * 2. bind a fb to the screen target
703 * 3. update that screen target (this is done later by
704 * vmw_kms_stdu_do_surface_dirty_or_present)
705 */
706 /*
707 * Note on error handling: We can't really restore the crtc to
708 * it's original state on error, but we at least update the
709 * current state to what's submitted to hardware to enable
710 * future recovery.
711 */
712 vmw_svga_enable(dev_priv);
713 ret = vmw_stdu_define_st(dev_priv, stdu, mode, set->x, set->y);
714 if (ret)
715 return ret;
716
717 crtc->x = set->x;
718 crtc->y = set->y;
719 crtc->mode = *mode;
720
721 ret = vmw_stdu_bind_fb(dev_priv, crtc, mode, new_fb);
722 if (ret)
723 return ret;
724
725 vmw_kms_add_active(dev_priv, &stdu->base, vfb);
726 crtc->enabled = true;
727 connector->encoder = encoder;
728 encoder->crtc = crtc;
729
730 return 0;
731}
732
733/**
734 * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target 454 * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target
735 * 455 *
736 * @crtc: CRTC to attach FB to 456 * @crtc: CRTC to attach FB to
@@ -756,9 +476,9 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
756 476
757{ 477{
758 struct vmw_private *dev_priv = vmw_priv(crtc->dev); 478 struct vmw_private *dev_priv = vmw_priv(crtc->dev);
759 struct vmw_screen_target_display_unit *stdu; 479 struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
760 struct drm_vmw_rect vclips;
761 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); 480 struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
481 struct drm_vmw_rect vclips;
762 int ret; 482 int ret;
763 483
764 dev_priv = vmw_priv(crtc->dev); 484 dev_priv = vmw_priv(crtc->dev);
@@ -767,25 +487,42 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
767 if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) 487 if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
768 return -EINVAL; 488 return -EINVAL;
769 489
770 ret = vmw_stdu_bind_fb(dev_priv, crtc, &crtc->mode, new_fb); 490 /*
771 if (ret) 491 * We're always async, but the helper doesn't know how to set async
492 * so lie to the helper. Also, the helper expects someone
493 * to pick the event up from the crtc state, and if nobody does,
494 * it will free it. Since we handle the event in this function,
495 * don't hand it to the helper.
496 */
497 flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
498 ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags);
499 if (ret) {
500 DRM_ERROR("Page flip error %d.\n", ret);
772 return ret; 501 return ret;
502 }
773 503
774 if (stdu->base.is_implicit) 504 if (stdu->base.is_implicit)
775 vmw_kms_update_implicit_fb(dev_priv, crtc); 505 vmw_kms_update_implicit_fb(dev_priv, crtc);
776 506
507 /*
508 * Now that we've bound a new surface to the screen target,
509 * update the contents.
510 */
777 vclips.x = crtc->x; 511 vclips.x = crtc->x;
778 vclips.y = crtc->y; 512 vclips.y = crtc->y;
779 vclips.w = crtc->mode.hdisplay; 513 vclips.w = crtc->mode.hdisplay;
780 vclips.h = crtc->mode.vdisplay; 514 vclips.h = crtc->mode.vdisplay;
515
781 if (vfb->dmabuf) 516 if (vfb->dmabuf)
782 ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, 517 ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips,
783 1, 1, true, false); 518 1, 1, true, false);
784 else 519 else
785 ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips, 520 ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips,
786 NULL, 0, 0, 1, 1, NULL); 521 NULL, 0, 0, 1, 1, NULL);
787 if (ret) 522 if (ret) {
523 DRM_ERROR("Page flip update error %d.\n", ret);
788 return ret; 524 return ret;
525 }
789 526
790 if (event) { 527 if (event) {
791 struct vmw_fence_obj *fence = NULL; 528 struct vmw_fence_obj *fence = NULL;
@@ -802,7 +539,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
802 true); 539 true);
803 vmw_fence_obj_unreference(&fence); 540 vmw_fence_obj_unreference(&fence);
804 } else { 541 } else {
805 vmw_fifo_flush(dev_priv, false); 542 (void) vmw_fifo_flush(dev_priv, false);
806 } 543 }
807 544
808 return 0; 545 return 0;
@@ -1123,7 +860,7 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
1123 .reset = vmw_du_crtc_reset, 860 .reset = vmw_du_crtc_reset,
1124 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 861 .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
1125 .atomic_destroy_state = vmw_du_crtc_destroy_state, 862 .atomic_destroy_state = vmw_du_crtc_destroy_state,
1126 .set_config = vmw_stdu_crtc_set_config, 863 .set_config = vmw_kms_set_config,
1127 .page_flip = vmw_stdu_crtc_page_flip, 864 .page_flip = vmw_stdu_crtc_page_flip,
1128}; 865};
1129 866
@@ -1425,8 +1162,8 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1425 1162
1426 1163
1427static const struct drm_plane_funcs vmw_stdu_plane_funcs = { 1164static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
1428 .update_plane = drm_primary_helper_update, 1165 .update_plane = drm_atomic_helper_update_plane,
1429 .disable_plane = drm_primary_helper_disable, 1166 .disable_plane = drm_atomic_helper_disable_plane,
1430 .destroy = vmw_du_primary_plane_destroy, 1167 .destroy = vmw_du_primary_plane_destroy,
1431 .reset = vmw_du_plane_reset, 1168 .reset = vmw_du_plane_reset,
1432 .atomic_duplicate_state = vmw_du_plane_duplicate_state, 1169 .atomic_duplicate_state = vmw_du_plane_duplicate_state,
@@ -1434,8 +1171,8 @@ static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
1434}; 1171};
1435 1172
1436static const struct drm_plane_funcs vmw_stdu_cursor_funcs = { 1173static const struct drm_plane_funcs vmw_stdu_cursor_funcs = {
1437 .update_plane = vmw_du_cursor_plane_update, 1174 .update_plane = drm_atomic_helper_update_plane,
1438 .disable_plane = vmw_du_cursor_plane_disable, 1175 .disable_plane = drm_atomic_helper_disable_plane,
1439 .destroy = vmw_du_cursor_plane_destroy, 1176 .destroy = vmw_du_cursor_plane_destroy,
1440 .reset = vmw_du_plane_reset, 1177 .reset = vmw_du_plane_reset,
1441 .atomic_duplicate_state = vmw_du_plane_duplicate_state, 1178 .atomic_duplicate_state = vmw_du_plane_duplicate_state,
@@ -1625,8 +1362,6 @@ err_free:
1625 */ 1362 */
1626static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu) 1363static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu)
1627{ 1364{
1628 vmw_stdu_unpin_display(stdu);
1629
1630 vmw_du_cleanup(&stdu->base); 1365 vmw_du_cleanup(&stdu->base);
1631 kfree(stdu); 1366 kfree(stdu);
1632} 1367}