|
@@ -352,6 +352,38 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv,
|
|
|
/**
|
|
|
* Buffer management.
|
|
|
*/
|
|
|
+
|
|
|
+/**
|
|
|
+ * vmw_dmabuf_acc_size - Calculate the pinned memory usage of buffers
|
|
|
+ *
|
|
|
+ * @dev_priv: Pointer to a struct vmw_private identifying the device.
|
|
|
+ * @size: The requested buffer size.
|
|
|
+ * @user: Whether this is an ordinary dma buffer or a user dma buffer.
|
|
|
+ */
|
|
|
+static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size,
|
|
|
+ bool user)
|
|
|
+{
|
|
|
+ static size_t struct_size, user_struct_size;
|
|
|
+ size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
|
|
+ size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *));
|
|
|
+
|
|
|
+ if (unlikely(struct_size == 0)) {
|
|
|
+ size_t backend_size = ttm_round_pot(vmw_tt_size);
|
|
|
+
|
|
|
+ struct_size = backend_size +
|
|
|
+ ttm_round_pot(sizeof(struct vmw_dma_buffer));
|
|
|
+ user_struct_size = backend_size +
|
|
|
+ ttm_round_pot(sizeof(struct vmw_user_dma_buffer));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dev_priv->map_mode == vmw_dma_alloc_coherent)
|
|
|
+ page_array_size +=
|
|
|
+ ttm_round_pot(num_pages * sizeof(dma_addr_t));
|
|
|
+
|
|
|
+ return ((user) ? user_struct_size : struct_size) +
|
|
|
+ page_array_size;
|
|
|
+}
|
|
|
+
|
|
|
void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
|
|
|
{
|
|
|
struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
|
|
@@ -359,6 +391,13 @@ void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
|
|
|
kfree(vmw_bo);
|
|
|
}
|
|
|
|
|
|
+static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
|
|
|
+{
|
|
|
+ struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
|
|
|
+
|
|
|
+ ttm_prime_object_kfree(vmw_user_bo, prime);
|
|
|
+}
|
|
|
+
|
|
|
int vmw_dmabuf_init(struct vmw_private *dev_priv,
|
|
|
struct vmw_dma_buffer *vmw_bo,
|
|
|
size_t size, struct ttm_placement *placement,
|
|
@@ -368,28 +407,23 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
|
|
|
struct ttm_bo_device *bdev = &dev_priv->bdev;
|
|
|
size_t acc_size;
|
|
|
int ret;
|
|
|
+ bool user = (bo_free == &vmw_user_dmabuf_destroy);
|
|
|
|
|
|
- BUG_ON(!bo_free);
|
|
|
+ BUG_ON(!bo_free && (!user && (bo_free != vmw_dmabuf_bo_free)));
|
|
|
|
|
|
- acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer));
|
|
|
+ acc_size = vmw_dmabuf_acc_size(dev_priv, size, user);
|
|
|
memset(vmw_bo, 0, sizeof(*vmw_bo));
|
|
|
|
|
|
INIT_LIST_HEAD(&vmw_bo->res_list);
|
|
|
|
|
|
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
|
|
|
- ttm_bo_type_device, placement,
|
|
|
+ (user) ? ttm_bo_type_device :
|
|
|
+ ttm_bo_type_kernel, placement,
|
|
|
0, interruptible,
|
|
|
NULL, acc_size, NULL, bo_free);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
|
|
|
-{
|
|
|
- struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
|
|
|
-
|
|
|
- ttm_prime_object_kfree(vmw_user_bo, prime);
|
|
|
-}
|
|
|
-
|
|
|
static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
|
|
|
{
|
|
|
struct vmw_user_dma_buffer *vmw_user_bo;
|
|
@@ -781,54 +815,55 @@ err_ref:
|
|
|
}
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * vmw_dumb_create - Create a dumb kms buffer
|
|
|
+ *
|
|
|
+ * @file_priv: Pointer to a struct drm_file identifying the caller.
|
|
|
+ * @dev: Pointer to the drm device.
|
|
|
+ * @args: Pointer to a struct drm_mode_create_dumb structure
|
|
|
+ *
|
|
|
+ * This is a driver callback for the core drm create_dumb functionality.
|
|
|
+ * Note that this is very similar to the vmw_dmabuf_alloc ioctl, except
|
|
|
+ * that the arguments have a different format.
|
|
|
+ */
|
|
|
int vmw_dumb_create(struct drm_file *file_priv,
|
|
|
struct drm_device *dev,
|
|
|
struct drm_mode_create_dumb *args)
|
|
|
{
|
|
|
struct vmw_private *dev_priv = vmw_priv(dev);
|
|
|
struct vmw_master *vmaster = vmw_master(file_priv->master);
|
|
|
- struct vmw_user_dma_buffer *vmw_user_bo;
|
|
|
- struct ttm_buffer_object *tmp;
|
|
|
+ struct vmw_dma_buffer *dma_buf;
|
|
|
int ret;
|
|
|
|
|
|
args->pitch = args->width * ((args->bpp + 7) / 8);
|
|
|
args->size = args->pitch * args->height;
|
|
|
|
|
|
- vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
|
|
|
- if (vmw_user_bo == NULL)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
ret = ttm_read_lock(&vmaster->lock, true);
|
|
|
- if (ret != 0) {
|
|
|
- kfree(vmw_user_bo);
|
|
|
+ if (unlikely(ret != 0))
|
|
|
return ret;
|
|
|
- }
|
|
|
|
|
|
- ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size,
|
|
|
- &vmw_vram_sys_placement, true,
|
|
|
- &vmw_user_dmabuf_destroy);
|
|
|
- if (ret != 0)
|
|
|
- goto out_no_dmabuf;
|
|
|
-
|
|
|
- tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
|
|
|
- ret = ttm_prime_object_init(vmw_fpriv(file_priv)->tfile,
|
|
|
- args->size,
|
|
|
- &vmw_user_bo->prime,
|
|
|
- false,
|
|
|
- ttm_buffer_type,
|
|
|
- &vmw_user_dmabuf_release, NULL);
|
|
|
+ ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile,
|
|
|
+ args->size, false, &args->handle,
|
|
|
+ &dma_buf);
|
|
|
if (unlikely(ret != 0))
|
|
|
- goto out_no_base_object;
|
|
|
-
|
|
|
- args->handle = vmw_user_bo->prime.base.hash.key;
|
|
|
+ goto out_no_dmabuf;
|
|
|
|
|
|
-out_no_base_object:
|
|
|
- ttm_bo_unref(&tmp);
|
|
|
+ vmw_dmabuf_unreference(&dma_buf);
|
|
|
out_no_dmabuf:
|
|
|
ttm_read_unlock(&vmaster->lock);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * vmw_dumb_map_offset - Return the address space offset of a dumb buffer
|
|
|
+ *
|
|
|
+ * @file_priv: Pointer to a struct drm_file identifying the caller.
|
|
|
+ * @dev: Pointer to the drm device.
|
|
|
+ * @handle: Handle identifying the dumb buffer.
|
|
|
+ * @offset: The address space offset returned.
|
|
|
+ *
|
|
|
+ * This is a driver callback for the core drm dumb_map_offset functionality.
|
|
|
+ */
|
|
|
int vmw_dumb_map_offset(struct drm_file *file_priv,
|
|
|
struct drm_device *dev, uint32_t handle,
|
|
|
uint64_t *offset)
|
|
@@ -846,6 +881,15 @@ int vmw_dumb_map_offset(struct drm_file *file_priv,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * vmw_dumb_destroy - Destroy a dumb boffer
|
|
|
+ *
|
|
|
+ * @file_priv: Pointer to a struct drm_file identifying the caller.
|
|
|
+ * @dev: Pointer to the drm device.
|
|
|
+ * @handle: Handle identifying the dumb buffer.
|
|
|
+ *
|
|
|
+ * This is a driver callback for the core drm dumb_destroy functionality.
|
|
|
+ */
|
|
|
int vmw_dumb_destroy(struct drm_file *file_priv,
|
|
|
struct drm_device *dev,
|
|
|
uint32_t handle)
|