diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2009-12-22 10:53:41 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-22 19:06:24 -0500 |
commit | 7a73ba7469cbea631050094fd14f73acebb97cf9 (patch) | |
tree | 2c1bc2b28a395578967343e14a3a4b90c66e55f5 /drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |
parent | 3d3a5b3290043618e8409f3fb68a63de6156fdd4 (diff) |
drm/vmwgfx: Use TTM handles instead of SIDs as user-space surface handles.
Improve the command verifier to catch all occurences of surface handles,
and translate to SIDs.
This way DMA buffers and 3D surfaces share a common handle space,
which makes it possible for the kms code to differentiate.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_resource.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 149 |
1 files changed, 70 insertions, 79 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index a1ceed0c8e07..c012d5927f65 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -488,28 +488,44 @@ static void vmw_user_surface_free(struct vmw_resource *res) | |||
488 | kfree(user_srf); | 488 | kfree(user_srf); |
489 | } | 489 | } |
490 | 490 | ||
491 | int vmw_user_surface_lookup(struct vmw_private *dev_priv, | 491 | int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, |
492 | struct ttm_object_file *tfile, | 492 | struct ttm_object_file *tfile, |
493 | int sid, struct vmw_surface **out) | 493 | uint32_t handle, struct vmw_surface **out) |
494 | { | 494 | { |
495 | struct vmw_resource *res; | 495 | struct vmw_resource *res; |
496 | struct vmw_surface *srf; | 496 | struct vmw_surface *srf; |
497 | struct vmw_user_surface *user_srf; | 497 | struct vmw_user_surface *user_srf; |
498 | struct ttm_base_object *base; | ||
499 | int ret = -EINVAL; | ||
498 | 500 | ||
499 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, sid); | 501 | base = ttm_base_object_lookup(tfile, handle); |
500 | if (unlikely(res == NULL)) | 502 | if (unlikely(base == NULL)) |
501 | return -EINVAL; | 503 | return -EINVAL; |
502 | 504 | ||
503 | if (res->res_free != &vmw_user_surface_free) | 505 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
504 | return -EINVAL; | 506 | goto out_bad_resource; |
505 | 507 | ||
506 | srf = container_of(res, struct vmw_surface, res); | 508 | user_srf = container_of(base, struct vmw_user_surface, base); |
507 | user_srf = container_of(srf, struct vmw_user_surface, srf); | 509 | srf = &user_srf->srf; |
508 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) | 510 | res = &srf->res; |
509 | return -EPERM; | 511 | |
512 | read_lock(&dev_priv->resource_lock); | ||
513 | |||
514 | if (!res->avail || res->res_free != &vmw_user_surface_free) { | ||
515 | read_unlock(&dev_priv->resource_lock); | ||
516 | goto out_bad_resource; | ||
517 | } | ||
518 | |||
519 | kref_get(&res->kref); | ||
520 | read_unlock(&dev_priv->resource_lock); | ||
510 | 521 | ||
511 | *out = srf; | 522 | *out = srf; |
512 | return 0; | 523 | ret = 0; |
524 | |||
525 | out_bad_resource: | ||
526 | ttm_base_object_unref(&base); | ||
527 | |||
528 | return ret; | ||
513 | } | 529 | } |
514 | 530 | ||
515 | static void vmw_user_surface_base_release(struct ttm_base_object **p_base) | 531 | static void vmw_user_surface_base_release(struct ttm_base_object **p_base) |
@@ -526,35 +542,10 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) | |||
526 | int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, | 542 | int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, |
527 | struct drm_file *file_priv) | 543 | struct drm_file *file_priv) |
528 | { | 544 | { |
529 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
530 | struct vmw_resource *res; | ||
531 | struct vmw_surface *srf; | ||
532 | struct vmw_user_surface *user_srf; | ||
533 | struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; | 545 | struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; |
534 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 546 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
535 | int ret = 0; | ||
536 | |||
537 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, arg->sid); | ||
538 | if (unlikely(res == NULL)) | ||
539 | return -EINVAL; | ||
540 | |||
541 | if (res->res_free != &vmw_user_surface_free) { | ||
542 | ret = -EINVAL; | ||
543 | goto out; | ||
544 | } | ||
545 | 547 | ||
546 | srf = container_of(res, struct vmw_surface, res); | 548 | return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE); |
547 | user_srf = container_of(srf, struct vmw_user_surface, srf); | ||
548 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) { | ||
549 | ret = -EPERM; | ||
550 | goto out; | ||
551 | } | ||
552 | |||
553 | ttm_ref_object_base_unref(tfile, user_srf->base.hash.key, | ||
554 | TTM_REF_USAGE); | ||
555 | out: | ||
556 | vmw_resource_unreference(&res); | ||
557 | return ret; | ||
558 | } | 549 | } |
559 | 550 | ||
560 | int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | 551 | int vmw_surface_define_ioctl(struct drm_device *dev, void *data, |
@@ -649,7 +640,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, | |||
649 | } | 640 | } |
650 | srf->snooper.crtc = NULL; | 641 | srf->snooper.crtc = NULL; |
651 | 642 | ||
652 | rep->sid = res->id; | 643 | rep->sid = user_srf->base.hash.key; |
644 | if (rep->sid == SVGA3D_INVALID_ID) | ||
645 | DRM_ERROR("Created bad Surface ID.\n"); | ||
646 | |||
653 | vmw_resource_unreference(&res); | 647 | vmw_resource_unreference(&res); |
654 | return 0; | 648 | return 0; |
655 | out_err1: | 649 | out_err1: |
@@ -662,39 +656,33 @@ out_err0: | |||
662 | int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | 656 | int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, |
663 | struct drm_file *file_priv) | 657 | struct drm_file *file_priv) |
664 | { | 658 | { |
665 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
666 | union drm_vmw_surface_reference_arg *arg = | 659 | union drm_vmw_surface_reference_arg *arg = |
667 | (union drm_vmw_surface_reference_arg *)data; | 660 | (union drm_vmw_surface_reference_arg *)data; |
668 | struct drm_vmw_surface_arg *req = &arg->req; | 661 | struct drm_vmw_surface_arg *req = &arg->req; |
669 | struct drm_vmw_surface_create_req *rep = &arg->rep; | 662 | struct drm_vmw_surface_create_req *rep = &arg->rep; |
670 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; | 663 | struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; |
671 | struct vmw_resource *res; | ||
672 | struct vmw_surface *srf; | 664 | struct vmw_surface *srf; |
673 | struct vmw_user_surface *user_srf; | 665 | struct vmw_user_surface *user_srf; |
674 | struct drm_vmw_size __user *user_sizes; | 666 | struct drm_vmw_size __user *user_sizes; |
675 | int ret; | 667 | struct ttm_base_object *base; |
668 | int ret = -EINVAL; | ||
676 | 669 | ||
677 | res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, req->sid); | 670 | base = ttm_base_object_lookup(tfile, req->sid); |
678 | if (unlikely(res == NULL)) | 671 | if (unlikely(base == NULL)) { |
672 | DRM_ERROR("Could not find surface to reference.\n"); | ||
679 | return -EINVAL; | 673 | return -EINVAL; |
680 | |||
681 | if (res->res_free != &vmw_user_surface_free) { | ||
682 | ret = -EINVAL; | ||
683 | goto out; | ||
684 | } | 674 | } |
685 | 675 | ||
686 | srf = container_of(res, struct vmw_surface, res); | 676 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
687 | user_srf = container_of(srf, struct vmw_user_surface, srf); | 677 | goto out_bad_resource; |
688 | if (user_srf->base.tfile != tfile && !user_srf->base.shareable) { | 678 | |
689 | DRM_ERROR("Tried to reference none shareable surface\n"); | 679 | user_srf = container_of(base, struct vmw_user_surface, base); |
690 | ret = -EPERM; | 680 | srf = &user_srf->srf; |
691 | goto out; | ||
692 | } | ||
693 | 681 | ||
694 | ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL); | 682 | ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL); |
695 | if (unlikely(ret != 0)) { | 683 | if (unlikely(ret != 0)) { |
696 | DRM_ERROR("Could not add a reference to a surface.\n"); | 684 | DRM_ERROR("Could not add a reference to a surface.\n"); |
697 | goto out; | 685 | goto out_no_reference; |
698 | } | 686 | } |
699 | 687 | ||
700 | rep->flags = srf->flags; | 688 | rep->flags = srf->flags; |
@@ -706,40 +694,43 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, | |||
706 | if (user_sizes) | 694 | if (user_sizes) |
707 | ret = copy_to_user(user_sizes, srf->sizes, | 695 | ret = copy_to_user(user_sizes, srf->sizes, |
708 | srf->num_sizes * sizeof(*srf->sizes)); | 696 | srf->num_sizes * sizeof(*srf->sizes)); |
709 | if (unlikely(ret != 0)) { | 697 | if (unlikely(ret != 0)) |
710 | DRM_ERROR("copy_to_user failed %p %u\n", | 698 | DRM_ERROR("copy_to_user failed %p %u\n", |
711 | user_sizes, srf->num_sizes); | 699 | user_sizes, srf->num_sizes); |
712 | /** | 700 | out_bad_resource: |
713 | * FIXME: Unreference surface here? | 701 | out_no_reference: |
714 | */ | 702 | ttm_base_object_unref(&base); |
715 | goto out; | 703 | |
716 | } | ||
717 | out: | ||
718 | vmw_resource_unreference(&res); | ||
719 | return ret; | 704 | return ret; |
720 | } | 705 | } |
721 | 706 | ||
722 | int vmw_surface_check(struct vmw_private *dev_priv, | 707 | int vmw_surface_check(struct vmw_private *dev_priv, |
723 | struct ttm_object_file *tfile, | 708 | struct ttm_object_file *tfile, |
724 | int id) | 709 | uint32_t handle, int *id) |
725 | { | 710 | { |
726 | struct vmw_resource *res; | 711 | struct ttm_base_object *base; |
727 | int ret = 0; | 712 | struct vmw_user_surface *user_srf; |
728 | 713 | ||
729 | read_lock(&dev_priv->resource_lock); | 714 | int ret = -EPERM; |
730 | res = idr_find(&dev_priv->surface_idr, id); | ||
731 | if (res && res->avail) { | ||
732 | struct vmw_surface *srf = | ||
733 | container_of(res, struct vmw_surface, res); | ||
734 | struct vmw_user_surface *usrf = | ||
735 | container_of(srf, struct vmw_user_surface, srf); | ||
736 | 715 | ||
737 | if (usrf->base.tfile != tfile && !usrf->base.shareable) | 716 | base = ttm_base_object_lookup(tfile, handle); |
738 | ret = -EPERM; | 717 | if (unlikely(base == NULL)) |
739 | } else | 718 | return -EINVAL; |
740 | ret = -EINVAL; | 719 | |
741 | read_unlock(&dev_priv->resource_lock); | 720 | if (unlikely(base->object_type != VMW_RES_SURFACE)) |
721 | goto out_bad_surface; | ||
742 | 722 | ||
723 | user_srf = container_of(base, struct vmw_user_surface, base); | ||
724 | *id = user_srf->srf.res.id; | ||
725 | ret = 0; | ||
726 | |||
727 | out_bad_surface: | ||
728 | /** | ||
729 | * FIXME: May deadlock here when called from the | ||
730 | * command parsing code. | ||
731 | */ | ||
732 | |||
733 | ttm_base_object_unref(&base); | ||
743 | return ret; | 734 | return ret; |
744 | } | 735 | } |
745 | 736 | ||