diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_resource.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 118 |
1 files changed, 81 insertions, 37 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index efe2b74c5eb1..9b5ea2ac7ddf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -352,6 +352,38 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, | |||
352 | /** | 352 | /** |
353 | * Buffer management. | 353 | * Buffer management. |
354 | */ | 354 | */ |
355 | |||
356 | /** | ||
357 | * vmw_dmabuf_acc_size - Calculate the pinned memory usage of buffers | ||
358 | * | ||
359 | * @dev_priv: Pointer to a struct vmw_private identifying the device. | ||
360 | * @size: The requested buffer size. | ||
361 | * @user: Whether this is an ordinary dma buffer or a user dma buffer. | ||
362 | */ | ||
363 | static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size, | ||
364 | bool user) | ||
365 | { | ||
366 | static size_t struct_size, user_struct_size; | ||
367 | size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
368 | size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *)); | ||
369 | |||
370 | if (unlikely(struct_size == 0)) { | ||
371 | size_t backend_size = ttm_round_pot(vmw_tt_size); | ||
372 | |||
373 | struct_size = backend_size + | ||
374 | ttm_round_pot(sizeof(struct vmw_dma_buffer)); | ||
375 | user_struct_size = backend_size + | ||
376 | ttm_round_pot(sizeof(struct vmw_user_dma_buffer)); | ||
377 | } | ||
378 | |||
379 | if (dev_priv->map_mode == vmw_dma_alloc_coherent) | ||
380 | page_array_size += | ||
381 | ttm_round_pot(num_pages * sizeof(dma_addr_t)); | ||
382 | |||
383 | return ((user) ? user_struct_size : struct_size) + | ||
384 | page_array_size; | ||
385 | } | ||
386 | |||
355 | void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) | 387 | void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) |
356 | { | 388 | { |
357 | struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); | 389 | struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); |
@@ -359,6 +391,13 @@ void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) | |||
359 | kfree(vmw_bo); | 391 | kfree(vmw_bo); |
360 | } | 392 | } |
361 | 393 | ||
394 | static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) | ||
395 | { | ||
396 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); | ||
397 | |||
398 | ttm_prime_object_kfree(vmw_user_bo, prime); | ||
399 | } | ||
400 | |||
362 | int vmw_dmabuf_init(struct vmw_private *dev_priv, | 401 | int vmw_dmabuf_init(struct vmw_private *dev_priv, |
363 | struct vmw_dma_buffer *vmw_bo, | 402 | struct vmw_dma_buffer *vmw_bo, |
364 | size_t size, struct ttm_placement *placement, | 403 | size_t size, struct ttm_placement *placement, |
@@ -368,28 +407,23 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, | |||
368 | struct ttm_bo_device *bdev = &dev_priv->bdev; | 407 | struct ttm_bo_device *bdev = &dev_priv->bdev; |
369 | size_t acc_size; | 408 | size_t acc_size; |
370 | int ret; | 409 | int ret; |
410 | bool user = (bo_free == &vmw_user_dmabuf_destroy); | ||
371 | 411 | ||
372 | BUG_ON(!bo_free); | 412 | BUG_ON(!bo_free && (!user && (bo_free != vmw_dmabuf_bo_free))); |
373 | 413 | ||
374 | acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer)); | 414 | acc_size = vmw_dmabuf_acc_size(dev_priv, size, user); |
375 | memset(vmw_bo, 0, sizeof(*vmw_bo)); | 415 | memset(vmw_bo, 0, sizeof(*vmw_bo)); |
376 | 416 | ||
377 | INIT_LIST_HEAD(&vmw_bo->res_list); | 417 | INIT_LIST_HEAD(&vmw_bo->res_list); |
378 | 418 | ||
379 | ret = ttm_bo_init(bdev, &vmw_bo->base, size, | 419 | ret = ttm_bo_init(bdev, &vmw_bo->base, size, |
380 | ttm_bo_type_device, placement, | 420 | (user) ? ttm_bo_type_device : |
421 | ttm_bo_type_kernel, placement, | ||
381 | 0, interruptible, | 422 | 0, interruptible, |
382 | NULL, acc_size, NULL, bo_free); | 423 | NULL, acc_size, NULL, bo_free); |
383 | return ret; | 424 | return ret; |
384 | } | 425 | } |
385 | 426 | ||
386 | static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) | ||
387 | { | ||
388 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); | ||
389 | |||
390 | ttm_prime_object_kfree(vmw_user_bo, prime); | ||
391 | } | ||
392 | |||
393 | static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) | 427 | static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) |
394 | { | 428 | { |
395 | struct vmw_user_dma_buffer *vmw_user_bo; | 429 | struct vmw_user_dma_buffer *vmw_user_bo; |
@@ -781,54 +815,55 @@ err_ref: | |||
781 | } | 815 | } |
782 | 816 | ||
783 | 817 | ||
818 | /** | ||
819 | * vmw_dumb_create - Create a dumb kms buffer | ||
820 | * | ||
821 | * @file_priv: Pointer to a struct drm_file identifying the caller. | ||
822 | * @dev: Pointer to the drm device. | ||
823 | * @args: Pointer to a struct drm_mode_create_dumb structure | ||
824 | * | ||
825 | * This is a driver callback for the core drm create_dumb functionality. | ||
826 | * Note that this is very similar to the vmw_dmabuf_alloc ioctl, except | ||
827 | * that the arguments have a different format. | ||
828 | */ | ||
784 | int vmw_dumb_create(struct drm_file *file_priv, | 829 | int vmw_dumb_create(struct drm_file *file_priv, |
785 | struct drm_device *dev, | 830 | struct drm_device *dev, |
786 | struct drm_mode_create_dumb *args) | 831 | struct drm_mode_create_dumb *args) |
787 | { | 832 | { |
788 | struct vmw_private *dev_priv = vmw_priv(dev); | 833 | struct vmw_private *dev_priv = vmw_priv(dev); |
789 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 834 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
790 | struct vmw_user_dma_buffer *vmw_user_bo; | 835 | struct vmw_dma_buffer *dma_buf; |
791 | struct ttm_buffer_object *tmp; | ||
792 | int ret; | 836 | int ret; |
793 | 837 | ||
794 | args->pitch = args->width * ((args->bpp + 7) / 8); | 838 | args->pitch = args->width * ((args->bpp + 7) / 8); |
795 | args->size = args->pitch * args->height; | 839 | args->size = args->pitch * args->height; |
796 | 840 | ||
797 | vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL); | ||
798 | if (vmw_user_bo == NULL) | ||
799 | return -ENOMEM; | ||
800 | |||
801 | ret = ttm_read_lock(&vmaster->lock, true); | 841 | ret = ttm_read_lock(&vmaster->lock, true); |
802 | if (ret != 0) { | 842 | if (unlikely(ret != 0)) |
803 | kfree(vmw_user_bo); | ||
804 | return ret; | 843 | return ret; |
805 | } | ||
806 | 844 | ||
807 | ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size, | 845 | ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, |
808 | &vmw_vram_sys_placement, true, | 846 | args->size, false, &args->handle, |
809 | &vmw_user_dmabuf_destroy); | 847 | &dma_buf); |
810 | if (ret != 0) | ||
811 | goto out_no_dmabuf; | ||
812 | |||
813 | tmp = ttm_bo_reference(&vmw_user_bo->dma.base); | ||
814 | ret = ttm_prime_object_init(vmw_fpriv(file_priv)->tfile, | ||
815 | args->size, | ||
816 | &vmw_user_bo->prime, | ||
817 | false, | ||
818 | ttm_buffer_type, | ||
819 | &vmw_user_dmabuf_release, NULL); | ||
820 | if (unlikely(ret != 0)) | 848 | if (unlikely(ret != 0)) |
821 | goto out_no_base_object; | 849 | goto out_no_dmabuf; |
822 | |||
823 | args->handle = vmw_user_bo->prime.base.hash.key; | ||
824 | 850 | ||
825 | out_no_base_object: | 851 | vmw_dmabuf_unreference(&dma_buf); |
826 | ttm_bo_unref(&tmp); | ||
827 | out_no_dmabuf: | 852 | out_no_dmabuf: |
828 | ttm_read_unlock(&vmaster->lock); | 853 | ttm_read_unlock(&vmaster->lock); |
829 | return ret; | 854 | return ret; |
830 | } | 855 | } |
831 | 856 | ||
857 | /** | ||
858 | * vmw_dumb_map_offset - Return the address space offset of a dumb buffer | ||
859 | * | ||
860 | * @file_priv: Pointer to a struct drm_file identifying the caller. | ||
861 | * @dev: Pointer to the drm device. | ||
862 | * @handle: Handle identifying the dumb buffer. | ||
863 | * @offset: The address space offset returned. | ||
864 | * | ||
865 | * This is a driver callback for the core drm dumb_map_offset functionality. | ||
866 | */ | ||
832 | int vmw_dumb_map_offset(struct drm_file *file_priv, | 867 | int vmw_dumb_map_offset(struct drm_file *file_priv, |
833 | struct drm_device *dev, uint32_t handle, | 868 | struct drm_device *dev, uint32_t handle, |
834 | uint64_t *offset) | 869 | uint64_t *offset) |
@@ -846,6 +881,15 @@ int vmw_dumb_map_offset(struct drm_file *file_priv, | |||
846 | return 0; | 881 | return 0; |
847 | } | 882 | } |
848 | 883 | ||
884 | /** | ||
885 | * vmw_dumb_destroy - Destroy a dumb boffer | ||
886 | * | ||
887 | * @file_priv: Pointer to a struct drm_file identifying the caller. | ||
888 | * @dev: Pointer to the drm device. | ||
889 | * @handle: Handle identifying the dumb buffer. | ||
890 | * | ||
891 | * This is a driver callback for the core drm dumb_destroy functionality. | ||
892 | */ | ||
849 | int vmw_dumb_destroy(struct drm_file *file_priv, | 893 | int vmw_dumb_destroy(struct drm_file *file_priv, |
850 | struct drm_device *dev, | 894 | struct drm_device *dev, |
851 | uint32_t handle) | 895 | uint32_t handle) |