diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2010-10-05 06:42:59 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-10-05 21:15:18 -0400 |
commit | d3216a0c3133d8e88ec45c7ecd9f38b421f90c03 (patch) | |
tree | 2657da97b91b2f68febcf289ae0b8a7a1cc667d5 /drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |
parent | fb7ba2114bcd8bb51640c20bc68f89164b29b9ed (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.c | 106 |
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 | ||
474 | int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | 474 | static 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 | ||
662 | int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, | 701 | static 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); |