@@ -33,6 +33,7 @@ i915-y += i915_cmd_parser.o \
i915_gem_stolen.o \
i915_gem_tiling.o \
i915_gem_userptr.o \
+ i915_gem_gvtbuffer.o \
i915_gpu_error.o \
i915_trace_points.o \
intel_lrc.o \
@@ -1351,6 +1351,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_GVTBUFFER, i915_gem_gvtbuffer_ioctl, DRM_RENDER_ALLOW),
};
int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
@@ -3238,6 +3238,9 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+int i915_gem_gvtbuffer_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file);
+
/* i915_gem_evict.c */
int __must_check i915_gem_evict_something(struct drm_device *dev,
struct i915_address_space *vm,
new file mode 100644
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2012 - 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+#include "i915_trace.h"
+#include "intel_drv.h"
+#include <linux/swap.h>
+
+#include "gvt/fb_decoder.h"
+
+static int i915_gem_gvtbuffer_get_pages(struct drm_i915_gem_object *obj)
+{
+ BUG();
+ return -EINVAL;
+}
+
+static void i915_gem_gvtbuffer_put_pages(struct drm_i915_gem_object *obj)
+{
+ /* like stolen memory, this should only be called during free
+ * after clearing pin count.
+ */
+ sg_free_table(obj->pages);
+ kfree(obj->pages);
+}
+
+static const struct drm_i915_gem_object_ops i915_gem_gvtbuffer_ops = {
+ .get_pages = i915_gem_gvtbuffer_get_pages,
+ .put_pages = i915_gem_gvtbuffer_put_pages,
+};
+
+#define GEN8_DECODE_PTE(pte) \
+ ((dma_addr_t)(((((u64)pte) >> 12) & 0x7ffffffULL) << 12))
+
+#define GEN7_DECODE_PTE(pte) \
+ ((dma_addr_t)(((((u64)pte) & 0x7f0) << 28) | (u64)(pte & 0xfffff000)))
+
+static struct sg_table *
+i915_create_sg_pages_for_gvtbuffer(struct drm_device *dev,
+ u32 start, u32 num_pages)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct sg_table *st;
+ struct scatterlist *sg;
+ int i;
+
+ st = kmalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL)
+ return NULL;
+
+ if (sg_alloc_table(st, num_pages, GFP_KERNEL)) {
+ kfree(st);
+ return NULL;
+ }
+
+ if (INTEL_INFO(dev)->gen >= 8) {
+ gen8_pte_t __iomem *gtt_entries =
+ (gen8_pte_t __iomem *)dev_priv->gtt.gsm +
+ (start >> PAGE_SHIFT);
+ for_each_sg(st->sgl, sg, num_pages, i) {
+ sg->offset = 0;
+ sg->length = PAGE_SIZE;
+ sg_dma_address(sg) =
+ GEN8_DECODE_PTE(readq(>t_entries[i]));
+ sg_dma_len(sg) = PAGE_SIZE;
+ }
+ } else {
+ gen6_pte_t __iomem *gtt_entries =
+ (gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+ (start >> PAGE_SHIFT);
+ for_each_sg(st->sgl, sg, num_pages, i) {
+ sg->offset = 0;
+ sg->length = PAGE_SIZE;
+ sg_dma_address(sg) =
+ GEN7_DECODE_PTE(readq(>t_entries[i]));
+ sg_dma_len(sg) = PAGE_SIZE;
+ }
+ }
+
+ return st;
+}
+
+struct drm_i915_gem_object *
+i915_gem_object_create_gvtbuffer(struct drm_device *dev,
+ u32 start, u32 num_pages)
+{
+ struct drm_i915_gem_object *obj;
+ obj = i915_gem_object_alloc(dev);
+ if (obj == NULL)
+ return NULL;
+
+ drm_gem_private_object_init(dev, &obj->base, num_pages << PAGE_SHIFT);
+ i915_gem_object_init(obj, &i915_gem_gvtbuffer_ops);
+
+ obj->pages = i915_create_sg_pages_for_gvtbuffer(dev, start, num_pages);
+ if (obj->pages == NULL) {
+ i915_gem_object_free(obj);
+ return NULL;
+ }
+
+ i915_gem_object_pin_pages(obj);
+ obj->cache_level = I915_CACHE_L3_LLC;
+
+ DRM_DEBUG_DRIVER("GVT_GEM: backing store base = 0x%x pages = 0x%x\n",
+ start, num_pages);
+ return obj;
+}
+
+static int gvt_decode_information(struct drm_device *dev,
+ struct drm_i915_gem_gvtbuffer *args)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 vmid = args->vmid;
+ struct gvt_fb_format fb;
+ struct gvt_primary_plane_format *p;
+ struct gvt_cursor_plane_format *c;
+ struct gvt_pipe_format *pipe;
+
+ if (gvt_decode_fb_format(dev_priv->vgpu.host_private_data, vmid, &fb))
+ return -EINVAL;
+
+ pipe = ((args->pipe_id >= I915_MAX_PIPES) ?
+ NULL : &fb.pipes[args->pipe_id]);
+
+ if (!pipe || !pipe->primary.enabled) {
+ DRM_DEBUG_DRIVER("GVT_GEM: Invalid pipe_id: %d\n",
+ args->pipe_id);
+ return -EINVAL;
+ }
+
+ if ((args->plane_id) == I915_GVT_PLANE_PRIMARY) {
+ p = &pipe->primary;
+ args->enabled = p->enabled;
+ args->x_offset = p->x_offset;
+ args->y_offset = p->y_offset;
+ args->start = p->base;
+ args->width = p->width;
+ args->height = p->height;
+ args->stride = p->stride;
+ args->bpp = p->bpp;
+ args->hw_format = p->hw_format;
+ args->drm_format = p->drm_format;
+ args->tiled = p->tiled;
+ } else if ((args->plane_id) == I915_GVT_PLANE_CURSOR) {
+ c = &pipe->cursor;
+ args->enabled = c->enabled;
+ args->x_offset = c->x_hot;
+ args->y_offset = c->y_hot;
+ args->x_pos = c->x_pos;
+ args->y_pos = c->y_pos;
+ args->start = c->base;
+ args->width = c->width;
+ args->height = c->height;
+ args->stride = c->width * (c->bpp / 8);
+ args->bpp = c->bpp;
+ args->tiled = 0;
+ } else {
+ DRM_DEBUG_DRIVER("GVT_GEM: Invalid plaine_id: %d\n",
+ args->plane_id);
+ return -EINVAL;
+ }
+
+ args->size = (((args->width * args->height * args->bpp) / 8) +
+ (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+ if (args->start & (PAGE_SIZE - 1)) {
+ DRM_DEBUG_DRIVER("GVT_GEM: Not aligned fb start address: "
+ "0x%x\n", args->start);
+ return -EINVAL;
+ }
+
+ if (((args->start >> PAGE_SHIFT) + args->size) >
+ gtt_total_entries(dev_priv->gtt)) {
+ DRM_DEBUG_DRIVER("GVT: Invalid GTT offset or size\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * Creates a new mm object that wraps some user memory.
+ */
+int
+i915_gem_gvtbuffer_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_i915_gem_gvtbuffer *args = data;
+ struct drm_i915_gem_object *obj;
+ u32 handle;
+ int ret;
+
+ if (INTEL_INFO(dev)->gen < 7)
+ return -EPERM;
+#if 0
+ if (!gvt_check_host())
+ return -EPERM;
+#endif
+ ret = gvt_decode_information(dev, args);
+ if (ret)
+ return ret;
+
+ if (args->flags & I915_GVTBUFFER_QUERY_ONLY)
+ return 0;
+
+ obj = i915_gem_object_create_gvtbuffer(dev, args->start, args->size);
+ if (!obj) {
+ DRM_DEBUG_DRIVER("GVT_GEM: Failed to create gem object"
+ " for VM FB!\n");
+ return -EINVAL;
+ }
+
+ obj->tiling_mode = args->tiled ? I915_TILING_X : I915_TILING_NONE;
+ obj->stride = args->tiled ? args->stride : 0;
+
+ ret = drm_gem_handle_create(file, &obj->base, &handle);
+ if (ret) {
+ /* TODO: Double confirm the error handling path */
+ i915_gem_object_free(obj);
+ return ret;
+ }
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference(&obj->base);
+
+ args->handle = handle;
+ return 0;
+}
@@ -230,6 +230,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_GEM_USERPTR 0x33
#define DRM_I915_GEM_CONTEXT_GETPARAM 0x34
#define DRM_I915_GEM_CONTEXT_SETPARAM 0x35
+#define DRM_I915_GEM_GVTBUFFER 0x36
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -283,6 +284,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr)
#define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
#define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
+#define DRM_IOCTL_I915_GEM_GVTBUFFER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GVTBUFFER, struct drm_i915_gem_gvtbuffer)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -1168,4 +1170,40 @@ struct drm_i915_gem_context_param {
__u64 value;
};
+struct drm_i915_gem_gvtbuffer {
+ __u32 vmid;
+ __u32 plane_id;
+#define I915_GVT_PLANE_PRIMARY 1
+#define I915_GVT_PLANE_SPRITE 2
+#define I915_GVT_PLANE_CURSOR 3
+ __u32 pipe_id;
+ __u32 phys_pipe_id;
+ __u8 enabled;
+ __u8 tiled;
+ __u32 bpp;
+ __u32 hw_format;
+ __u32 drm_format;
+ __u32 start;
+ __u32 x_pos;
+ __u32 y_pos;
+ __u32 x_offset;
+ __u32 y_offset;
+ __u32 size;
+ __u32 width;
+ __u32 height;
+ __u32 stride;
+ __u64 user_ptr;
+ __u32 user_size;
+ __u32 flags;
+#define I915_GVTBUFFER_READ_ONLY (1<<0)
+#define I915_GVTBUFFER_QUERY_ONLY (1<<1)
+#define I915_GVTBUFFER_UNSYNCHRONIZED 0x80000000
+ /**
+ * Returned handle for the object.
+ *
+ * Object handles are nonzero.
+ */
+ __u32 handle;
+};
+
#endif /* _UAPI_I915_DRM_H_ */