summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2009-12-14 21:36:21 +0100
committerJakob Bornecrantz <jakob@vmware.com>2009-12-14 21:36:48 +0100
commitbb9b570e01fa263d3d20a59fb8715df566233f38 (patch)
tree208fe3fde4debd7980c30d81c97b3f7a326d9d09
parentda88394c0195bd3e7102e99cea1f3da72938856d (diff)
vmwgfx: Userspace must now claim a overlay before use
-rw-r--r--vmwgfx_drm.h29
-rw-r--r--vmwgfx_drv.c15
-rw-r--r--vmwgfx_drv.h11
-rw-r--r--vmwgfx_overlay.c55
-rw-r--r--vmwgfx_resource.c185
5 files changed, 291 insertions, 4 deletions
diff --git a/vmwgfx_drm.h b/vmwgfx_drm.h
index e05731b..46f6a31 100644
--- a/vmwgfx_drm.h
+++ b/vmwgfx_drm.h
@@ -46,6 +46,8 @@
#define DRM_VMW_FENCE_WAIT 12
#define DRM_VMW_OVERLAY 13
#define DRM_VMW_CURSOR_BYPASS 14
+#define DRM_VMW_CLAIM_STREAM 15
+#define DRM_VMW_UNREF_STREAM 16
/*************************************************************************/
/**
@@ -537,4 +539,31 @@ struct drm_vmw_cursor_bypass_arg {
int32_t yhot;
};
+/*************************************************************************/
+/**
+ * DRM_VMW_CLAIM_STREAM - Claim a single stream.
+ */
+
+/**
+ * struct drm_vmw_context_arg
+ *
+ * @stream_id: Device unique context ID.
+ *
+ * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl.
+ * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl.
+ */
+
+struct drm_vmw_stream_arg {
+ uint32_t stream_id;
+ uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_STREAM - Unclaim a stream.
+ *
+ * Return a single stream that was claimed by this process. Also makes
+ * sure that the stream has been stopped.
+ */
+
#endif
diff --git a/vmwgfx_drv.c b/vmwgfx_drv.c
index 749cf38..0c756bf 100644
--- a/vmwgfx_drv.c
+++ b/vmwgfx_drv.c
@@ -80,6 +80,12 @@
#define DRM_IOCTL_VMW_CURSOR_BYPASS \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_CURSOR_BYPASS, \
struct drm_vmw_cursor_bypass_arg)
+#define DRM_IOCTL_VMW_CLAIM_STREAM \
+ DRM_IOR(DRM_COMMAND_BASE + DRM_VMW_CLAIM_STREAM, \
+ struct drm_vmw_stream_arg)
+#define DRM_IOCTL_VMW_UNREF_STREAM \
+ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_STREAM, \
+ struct drm_vmw_stream_arg)
/**
* The core DRM version of this macro doesn't account for
@@ -118,7 +124,11 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
VMW_IOCTL_DEF(DRM_IOCTL_VMW_OVERLAY, vmw_overlay_ioctl,
0),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS,
- vmw_kms_cursor_bypass_ioctl, 0)
+ vmw_kms_cursor_bypass_ioctl, 0),
+ VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl,
+ 0),
+ VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl,
+ 0)
};
static struct pci_device_id vmw_pci_id_list[] = {
@@ -205,6 +215,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
rwlock_init(&dev_priv->resource_lock);
idr_init(&dev_priv->context_idr);
idr_init(&dev_priv->surface_idr);
+ idr_init(&dev_priv->stream_idr);
ida_init(&dev_priv->gmr_ida);
mutex_init(&dev_priv->init_mutex);
init_waitqueue_head(&dev_priv->fence_queue);
@@ -363,6 +374,7 @@ out_err0:
ida_destroy(&dev_priv->gmr_ida);
idr_destroy(&dev_priv->surface_idr);
idr_destroy(&dev_priv->context_idr);
+ idr_destroy(&dev_priv->stream_idr);
kfree(dev_priv);
return ret;
}
@@ -398,6 +410,7 @@ static int vmw_driver_unload(struct drm_device *dev)
ida_destroy(&dev_priv->gmr_ida);
idr_destroy(&dev_priv->surface_idr);
idr_destroy(&dev_priv->context_idr);
+ idr_destroy(&dev_priv->stream_idr);
kfree(dev_priv);
diff --git a/vmwgfx_drv.h b/vmwgfx_drv.h
index 20f2118..884c99f 100644
--- a/vmwgfx_drv.h
+++ b/vmwgfx_drv.h
@@ -195,6 +195,7 @@ struct vmw_private {
rwlock_t resource_lock;
struct idr context_idr;
struct idr surface_idr;
+ struct idr stream_idr;
/*
* Block lastclose from racing with firstopen.
@@ -355,6 +356,14 @@ extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
struct vmw_dma_buffer *bo);
+extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int vmw_user_stream_lookup(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t *inout_id,
+ struct vmw_resource **out);
/**
@@ -461,6 +470,8 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
int vmw_overlay_stop_all(struct vmw_private *dev_priv);
int vmw_overlay_resume_all(struct vmw_private *dev_priv);
int vmw_overlay_pause_all(struct vmw_private *dev_priv);
+int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out);
+int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
/**
* Inline helper functions
diff --git a/vmwgfx_overlay.c b/vmwgfx_overlay.c
index 5b146a4..65e6045 100644
--- a/vmwgfx_overlay.c
+++ b/vmwgfx_overlay.c
@@ -38,6 +38,7 @@
struct vmw_stream {
struct vmw_dma_buffer *buf;
+ bool claimed;
bool paused;
struct drm_vmw_overlay_arg saved;
};
@@ -476,14 +477,16 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
struct drm_vmw_overlay_arg *arg =
(struct drm_vmw_overlay_arg *)data;
struct vmw_dma_buffer *buf;
+ struct vmw_resource *res;
int ret;
- if (arg->stream_id > VMW_MAX_NUM_STREAMS)
- return -EINVAL;
-
if (!overlay)
return -ENOSYS;
+ ret = vmw_user_stream_lookup(dev_priv, tfile, &arg->stream_id, &res);
+ if (ret)
+ return ret;
+
mutex_lock(&overlay->mutex);
if (!arg->enabled) {
@@ -501,10 +504,55 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
out_unlock:
mutex_unlock(&overlay->mutex);
+ vmw_resource_unreference(&res);
return ret;
}
+int vmw_overlay_claim(struct vmw_private *dev_priv, uint32_t *out)
+{
+ struct vmw_overlay *overlay = dev_priv->overlay_priv;
+ int i;
+
+ if (!overlay)
+ return -ENOSYS;
+
+ mutex_lock(&overlay->mutex);
+
+ for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
+
+ if (overlay->stream[i].claimed)
+ continue;
+
+ overlay->stream[i].claimed = true;
+ *out = i;
+ mutex_unlock(&overlay->mutex);
+ return 0;
+ }
+
+ mutex_unlock(&overlay->mutex);
+ return -ESRCH;
+}
+
+int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id)
+{
+ struct vmw_overlay *overlay = dev_priv->overlay_priv;
+
+ BUG_ON(stream_id >= VMW_MAX_NUM_STREAMS);
+
+ if (!overlay)
+ return -ENOSYS;
+
+ mutex_lock(&overlay->mutex);
+
+ WARN_ON(!overlay->stream[stream_id].claimed);
+ vmw_overlay_stop(dev_priv, stream_id, false, false);
+ overlay->stream[stream_id].claimed = false;
+
+ mutex_unlock(&overlay->mutex);
+ return 0;
+}
+
int vmw_overlay_init(struct vmw_private *dev_priv)
{
struct vmw_overlay *overlay;
@@ -528,6 +576,7 @@ int vmw_overlay_init(struct vmw_private *dev_priv)
for (i = 0; i < VMW_MAX_NUM_STREAMS; i++) {
overlay->stream[i].buf = NULL;
overlay->stream[i].paused = false;
+ overlay->stream[i].claimed = false;
}
dev_priv->overlay_priv = overlay;
diff --git a/vmwgfx_resource.c b/vmwgfx_resource.c
index 6538c68..038e524 100644
--- a/vmwgfx_resource.c
+++ b/vmwgfx_resource.c
@@ -33,6 +33,7 @@
#define VMW_RES_CONTEXT ttm_driver_type0
#define VMW_RES_SURFACE ttm_driver_type1
+#define VMW_RES_STREAM ttm_driver_type2
struct vmw_user_context {
struct ttm_base_object base;
@@ -54,6 +55,16 @@ struct vmw_bo_user_rep {
uint64_t map_handle;
};
+struct vmw_stream {
+ struct vmw_resource res;
+ uint32_t stream_id;
+};
+
+struct vmw_user_stream {
+ struct ttm_base_object base;
+ struct vmw_stream stream;
+};
+
static inline struct vmw_dma_buffer *
vmw_dma_buffer(struct ttm_buffer_object *bo)
{
@@ -1005,3 +1016,177 @@ int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
*p_id = (uint32_t) id;
return 0;
}
+
+/*
+ * Stream managment
+ */
+
+static void vmw_stream_destroy(struct vmw_resource *res)
+{
+ struct vmw_private *dev_priv = res->dev_priv;
+ struct vmw_stream *stream;
+ int ret;
+
+ DRM_INFO("%s: unref\n", __func__);
+ stream = container_of(res, struct vmw_stream, res);
+
+ ret = vmw_overlay_unref(dev_priv, stream->stream_id);
+ WARN_ON(ret != 0);
+}
+
+static int vmw_stream_init(struct vmw_private *dev_priv,
+ struct vmw_stream *stream,
+ void (*res_free) (struct vmw_resource *res))
+{
+ struct vmw_resource *res = &stream->res;
+ int ret;
+
+ ret = vmw_resource_init(dev_priv, res, &dev_priv->stream_idr,
+ VMW_RES_STREAM, res_free);
+
+ if (unlikely(ret != 0)) {
+ if (res_free == NULL)
+ kfree(stream);
+ else
+ res_free(&stream->res);
+ return ret;
+ }
+
+ ret = vmw_overlay_claim(dev_priv, &stream->stream_id);
+ if (ret) {
+ vmw_resource_unreference(&res);
+ return ret;
+ }
+
+ DRM_INFO("%s: claimed\n", __func__);
+
+ vmw_resource_activate(&stream->res, vmw_stream_destroy);
+ return 0;
+}
+
+/**
+ * User-space context management:
+ */
+
+static void vmw_user_stream_free(struct vmw_resource *res)
+{
+ struct vmw_user_stream *stream =
+ container_of(res, struct vmw_user_stream, stream.res);
+
+ kfree(stream);
+}
+
+/**
+ * This function is called when user space has no more references on the
+ * base object. It releases the base-object's reference on the resource object.
+ */
+
+static void vmw_user_stream_base_release(struct ttm_base_object **p_base)
+{
+ struct ttm_base_object *base = *p_base;
+ struct vmw_user_stream *stream =
+ container_of(base, struct vmw_user_stream, base);
+ struct vmw_resource *res = &stream->stream.res;
+
+ *p_base = NULL;
+ vmw_resource_unreference(&res);
+}
+
+int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_resource *res;
+ struct vmw_user_stream *stream;
+ struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ int ret = 0;
+
+ res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, arg->stream_id);
+ if (unlikely(res == NULL))
+ return -EINVAL;
+
+ if (res->res_free != &vmw_user_stream_free) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ stream = container_of(res, struct vmw_user_stream, stream.res);
+ if (stream->base.tfile != tfile) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ttm_ref_object_base_unref(tfile, stream->base.hash.key, TTM_REF_USAGE);
+out:
+ vmw_resource_unreference(&res);
+ return ret;
+}
+
+int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_user_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
+ struct vmw_resource *res;
+ struct vmw_resource *tmp;
+ struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ int ret;
+
+ if (unlikely(stream == NULL))
+ return -ENOMEM;
+
+ res = &stream->stream.res;
+ stream->base.shareable = false;
+ stream->base.tfile = NULL;
+
+ ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free);
+ if (unlikely(ret != 0))
+ return ret;
+
+ tmp = vmw_resource_reference(res);
+ ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM,
+ &vmw_user_stream_base_release, NULL);
+
+ if (unlikely(ret != 0)) {
+ vmw_resource_unreference(&tmp);
+ goto out_err;
+ }
+
+ arg->stream_id = res->id;
+out_err:
+ vmw_resource_unreference(&res);
+ return ret;
+}
+
+int vmw_user_stream_lookup(struct vmw_private *dev_priv,
+ struct ttm_object_file *tfile,
+ uint32_t *inout_id, struct vmw_resource **out)
+{
+ struct vmw_user_stream *stream;
+ struct vmw_resource *res;
+ int ret;
+
+ res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, *inout_id);
+ if (unlikely(res == NULL))
+ return -EINVAL;
+
+ if (res->res_free != &vmw_user_stream_free) {
+ ret = -EINVAL;
+ goto err_ref;
+ }
+
+ stream = container_of(res, struct vmw_user_stream, stream.res);
+ if (stream->base.tfile != tfile) {
+ ret = -EPERM;
+ goto err_ref;
+ }
+
+ *inout_id = stream->stream.stream_id;
+ *out = res;
+ return 0;
+err_ref:
+ vmw_resource_unreference(&res);
+ return ret;
+}