aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2010-10-05 06:42:59 -0400
committerDave Airlie <airlied@redhat.com>2010-10-05 21:15:18 -0400
commitd3216a0c3133d8e88ec45c7ecd9f38b421f90c03 (patch)
tree2657da97b91b2f68febcf289ae0b8a7a1cc667d5 /drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
parentfb7ba2114bcd8bb51640c20bc68f89164b29b9ed (diff)
drm/vmwgfx: Really support other depths than 32
Also add some sanity checks. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c106
1 files changed, 85 insertions, 21 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e882ba099f0c..f30223cafadb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -471,16 +471,55 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
471 .create_handle = vmw_framebuffer_create_handle, 471 .create_handle = vmw_framebuffer_create_handle,
472}; 472};
473 473
474int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, 474static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
475 struct vmw_surface *surface, 475 struct vmw_surface *surface,
476 struct vmw_framebuffer **out, 476 struct vmw_framebuffer **out,
477 unsigned width, unsigned height) 477 const struct drm_mode_fb_cmd
478 *mode_cmd)
478 479
479{ 480{
480 struct drm_device *dev = dev_priv->dev; 481 struct drm_device *dev = dev_priv->dev;
481 struct vmw_framebuffer_surface *vfbs; 482 struct vmw_framebuffer_surface *vfbs;
483 enum SVGA3dSurfaceFormat format;
482 int ret; 484 int ret;
483 485
486 /*
487 * Sanity checks.
488 */
489
490 if (unlikely(surface->mip_levels[0] != 1 ||
491 surface->num_sizes != 1 ||
492 surface->sizes[0].width < mode_cmd->width ||
493 surface->sizes[0].height < mode_cmd->height ||
494 surface->sizes[0].depth != 1)) {
495 DRM_ERROR("Incompatible surface dimensions "
496 "for requested mode.\n");
497 return -EINVAL;
498 }
499
500 switch (mode_cmd->depth) {
501 case 32:
502 format = SVGA3D_A8R8G8B8;
503 break;
504 case 24:
505 format = SVGA3D_X8R8G8B8;
506 break;
507 case 16:
508 format = SVGA3D_R5G6B5;
509 break;
510 case 15:
511 format = SVGA3D_A1R5G5B5;
512 break;
513 default:
514 DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
515 return -EINVAL;
516 }
517
518 if (unlikely(format != surface->format)) {
519 DRM_ERROR("Invalid surface format for requested mode.\n");
520 return -EINVAL;
521 }
522
484 vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL); 523 vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
485 if (!vfbs) { 524 if (!vfbs) {
486 ret = -ENOMEM; 525 ret = -ENOMEM;
@@ -498,11 +537,11 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
498 } 537 }
499 538
500 /* XXX get the first 3 from the surface info */ 539 /* XXX get the first 3 from the surface info */
501 vfbs->base.base.bits_per_pixel = 32; 540 vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
502 vfbs->base.base.pitch = width * 32 / 4; 541 vfbs->base.base.pitch = mode_cmd->pitch;
503 vfbs->base.base.depth = 24; 542 vfbs->base.base.depth = mode_cmd->depth;
504 vfbs->base.base.width = width; 543 vfbs->base.base.width = mode_cmd->width;
505 vfbs->base.base.height = height; 544 vfbs->base.base.height = mode_cmd->height;
506 vfbs->base.pin = &vmw_surface_dmabuf_pin; 545 vfbs->base.pin = &vmw_surface_dmabuf_pin;
507 vfbs->base.unpin = &vmw_surface_dmabuf_unpin; 546 vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
508 vfbs->surface = surface; 547 vfbs->surface = surface;
@@ -659,16 +698,25 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb)
659 return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer); 698 return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
660} 699}
661 700
662int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, 701static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
663 struct vmw_dma_buffer *dmabuf, 702 struct vmw_dma_buffer *dmabuf,
664 struct vmw_framebuffer **out, 703 struct vmw_framebuffer **out,
665 unsigned width, unsigned height) 704 const struct drm_mode_fb_cmd
705 *mode_cmd)
666 706
667{ 707{
668 struct drm_device *dev = dev_priv->dev; 708 struct drm_device *dev = dev_priv->dev;
669 struct vmw_framebuffer_dmabuf *vfbd; 709 struct vmw_framebuffer_dmabuf *vfbd;
710 unsigned int requested_size;
670 int ret; 711 int ret;
671 712
713 requested_size = mode_cmd->height * mode_cmd->pitch;
714 if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) {
715 DRM_ERROR("Screen buffer object size is too small "
716 "for requested mode.\n");
717 return -EINVAL;
718 }
719
672 vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL); 720 vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
673 if (!vfbd) { 721 if (!vfbd) {
674 ret = -ENOMEM; 722 ret = -ENOMEM;
@@ -685,12 +733,11 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
685 goto out_err3; 733 goto out_err3;
686 } 734 }
687 735
688 /* XXX get the first 3 from the surface info */ 736 vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
689 vfbd->base.base.bits_per_pixel = 32; 737 vfbd->base.base.pitch = mode_cmd->pitch;
690 vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8; 738 vfbd->base.base.depth = mode_cmd->depth;
691 vfbd->base.base.depth = 24; 739 vfbd->base.base.width = mode_cmd->width;
692 vfbd->base.base.width = width; 740 vfbd->base.base.height = mode_cmd->height;
693 vfbd->base.base.height = height;
694 vfbd->base.pin = vmw_framebuffer_dmabuf_pin; 741 vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
695 vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; 742 vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
696 vfbd->buffer = dmabuf; 743 vfbd->buffer = dmabuf;
@@ -719,8 +766,25 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
719 struct vmw_framebuffer *vfb = NULL; 766 struct vmw_framebuffer *vfb = NULL;
720 struct vmw_surface *surface = NULL; 767 struct vmw_surface *surface = NULL;
721 struct vmw_dma_buffer *bo = NULL; 768 struct vmw_dma_buffer *bo = NULL;
769 unsigned int required_size;
722 int ret; 770 int ret;
723 771
772 /**
773 * This code should be conditioned on Screen Objects not being used.
774 * If screen objects are used, we can allocate a GMR to hold the
775 * requested framebuffer.
776 */
777
778 required_size = mode_cmd->pitch * mode_cmd->height;
779 if (unlikely(required_size > dev_priv->vram_size)) {
780 DRM_ERROR("VRAM size is too small for requested mode.\n");
781 return NULL;
782 }
783
784 /**
785 * End conditioned code.
786 */
787
724 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, 788 ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
725 mode_cmd->handle, &surface); 789 mode_cmd->handle, &surface);
726 if (ret) 790 if (ret)
@@ -730,7 +794,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
730 goto err_not_scanout; 794 goto err_not_scanout;
731 795
732 ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, 796 ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
733 mode_cmd->width, mode_cmd->height); 797 mode_cmd);
734 798
735 /* vmw_user_surface_lookup takes one ref so does new_fb */ 799 /* vmw_user_surface_lookup takes one ref so does new_fb */
736 vmw_surface_unreference(&surface); 800 vmw_surface_unreference(&surface);
@@ -751,7 +815,7 @@ try_dmabuf:
751 } 815 }
752 816
753 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, 817 ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
754 mode_cmd->width, mode_cmd->height); 818 mode_cmd);
755 819
756 /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ 820 /* vmw_user_dmabuf_lookup takes one ref so does new_fb */
757 vmw_dmabuf_unreference(&bo); 821 vmw_dmabuf_unreference(&bo);