Adds base i915 perf infrastructure for Gen performance metrics.

This adds a DRM_IOCTL_I915_PERF_OPEN ioctl that takes an array of uint64
properties to configure a stream of metrics and returns a new fd usable
with standard VFS system calls including read() to read typed and sized
records; ioctl() to enable or disable capture and poll() to wait for
data.

A stream is opened something like:

  uint64_t properties[] = {
      /* Single context sampling */
      DRM_I915_PERF_PROP_CTX_HANDLE,        ctx_handle,

      /* Include OA reports in samples */
      DRM_I915_PERF_PROP_SAMPLE_OA,         true,

      /* OA unit configuration */
      DRM_I915_PERF_PROP_OA_METRICS_SET,    metrics_set_id,
      DRM_I915_PERF_PROP_OA_FORMAT,         report_format,
      DRM_I915_PERF_PROP_OA_EXPONENT,       period_exponent,
   };
   struct drm_i915_perf_open_param parm = {
      .flags = I915_PERF_FLAG_FD_CLOEXEC |
               I915_PERF_FLAG_FD_NONBLOCK |
               I915_PERF_FLAG_DISABLED,
      .properties_ptr = (uint64_t)properties,
      .num_properties = sizeof(properties) / 16,
   };
   int fd = drmIoctl(drm_fd, DRM_IOCTL_I915_PERF_OPEN, &param);

Records read all start with a common { type, size } header with
DRM_I915_PERF_RECORD_SAMPLE being of most interest. Sample records
contain an extensible number of fields and it's the
DRM_I915_PERF_PROP_SAMPLE_xyz properties given when opening that
determine what's included in every sample.

No specific streams are supported yet so any attempt to open a stream
will return an error.

Signed-off-by: Robert Bragg <rob...@sixbynine.org>
---
 drivers/gpu/drm/i915/Makefile    |   3 +
 drivers/gpu/drm/i915/i915_dma.c  |   8 +
 drivers/gpu/drm/i915/i915_drv.h  |  92 +++++++++
 drivers/gpu/drm/i915/i915_perf.c | 431 +++++++++++++++++++++++++++++++++++++++
 include/uapi/drm/i915_drm.h      |  67 ++++++
 5 files changed, 601 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_perf.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 723c502..d90d907 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -99,6 +99,9 @@ i915-y += dvo_ch7017.o \
 # virtual gpu code
 i915-y += i915_vgpu.o
 
+# perf code
+i915-y += i915_perf.o
+
 # legacy horrors
 i915-y += i915_dma.o
 
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index f69330c..89cec21 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1074,6 +1074,11 @@ static int i915_driver_init_early(struct 
drm_i915_private *dev_priv,
        if (ret < 0)
                return ret;
 
+       /* Must at least be initialized before trying to pin any context
+        * which i915_perf hooks into.
+        */
+       i915_perf_init(dev);
+
        /* This must be called before any calls to HAS_PCH_* */
        intel_detect_pch(dev);
 
@@ -1460,6 +1465,8 @@ int i915_driver_unload(struct drm_device *dev)
 
        i915_driver_unregister(dev_priv);
 
+       i915_perf_fini(dev);
+
        drm_vblank_cleanup(dev);
 
        intel_modeset_cleanup(dev);
@@ -1611,6 +1618,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_PERF_OPEN, i915_perf_open_ioctl, 
DRM_RENDER_ALLOW),
 };
 
 int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e2abbcc..3d2450f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1712,6 +1712,85 @@ struct intel_wm_config {
        bool sprites_scaled;
 };
 
+struct i915_perf_read_state {
+       int count;
+       ssize_t read;
+       char __user *buf;
+};
+
+struct i915_perf_stream;
+
+struct i915_perf_stream_ops {
+       /* Enables the collection of HW samples, either in response to
+        * I915_PERF_IOCTL_ENABLE or implicitly called when stream is
+        * opened without I915_PERF_FLAG_DISABLED.
+        */
+       void (*enable)(struct i915_perf_stream *stream);
+
+       /* Disables the collection of HW samples, either in response to
+        * I915_PERF_IOCTL_DISABLE or implicitly called before
+        * destroying the stream.
+        */
+       void (*disable)(struct i915_perf_stream *stream);
+
+       /* Return: true if any i915 perf records are ready to read()
+        * for this stream.
+        */
+       bool (*can_read)(struct i915_perf_stream *stream);
+
+       /* Call poll_wait, passing a wait queue that will be woken
+        * once there is something ready to read() for the stream
+        */
+       void (*poll_wait)(struct i915_perf_stream *stream,
+                         struct file *file,
+                         poll_table *wait);
+
+       /* For handling a blocking read, wait until there is something
+        * to ready to read() for the stream. E.g. wait on the same
+        * wait queue that would be passed to poll_wait() until
+        * ->can_read() returns true (if its safe to call ->can_read()
+        * without the i915 perf lock held).
+        */
+       int (*wait_unlocked)(struct i915_perf_stream *stream);
+
+       /* Copy as many buffered i915 perf samples and records for
+        * this stream to userspace as will fit in the given buffer.
+        *
+        * Only write complete records.
+        *
+        * read_state->count is the length of read_state->buf
+        *
+        * Update read_state->read with the number of bytes written.
+        *
+        * Return any error condition that results in a short read
+        * such as -ENOSPC or -EFAULT, even though these may be
+        * squashed to 0 before returning to userspace (if at least
+        * one record was successfully copied, as determined via
+        * the read_state->read length)
+        */
+       int (*read)(struct i915_perf_stream *stream,
+                   struct i915_perf_read_state *read_state);
+
+       /* Cleanup any stream specific resources.
+        *
+        * The stream will always be disabled before this is called.
+        */
+       void (*destroy)(struct i915_perf_stream *stream);
+};
+
+struct i915_perf_stream {
+       struct drm_i915_private *dev_priv;
+
+       struct list_head link;
+
+       u32 sample_flags;
+
+       struct intel_context *ctx;
+       bool enabled;
+
+       struct i915_perf_stream_ops *ops;
+};
+
 struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *objects;
@@ -1990,6 +2069,12 @@ struct drm_i915_private {
 
        struct i915_runtime_pm pm;
 
+       struct {
+               bool initialized;
+               struct mutex lock;
+               struct list_head streams;
+       } perf;
+
        /* Abstract the submission mechanism (legacy ringbuffer or execlists) 
away */
        struct {
                int (*execbuf_submit)(struct i915_execbuffer_params *params,
@@ -3340,6 +3425,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_perf_open_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,
@@ -3456,6 +3544,10 @@ int i915_parse_cmds(struct intel_engine_cs *engine,
                    u32 batch_len,
                    bool is_master);
 
+/* i915_perf.c */
+extern void i915_perf_init(struct drm_device *dev);
+extern void i915_perf_fini(struct drm_device *dev);
+
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
new file mode 100644
index 0000000..affd70f
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright © 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 <linux/anon_inodes.h>
+#include <linux/sizes.h>
+
+#include "i915_drv.h"
+
+struct perf_open_properties {
+       u32 sample_flags;
+
+       u64 single_context:1;
+       u64 ctx_handle;
+};
+
+static ssize_t i915_perf_read_locked(struct i915_perf_stream *stream,
+                                    struct file *file,
+                                    char __user *buf,
+                                    size_t count,
+                                    loff_t *ppos)
+{
+       struct i915_perf_read_state state = { count, 0, buf };
+       int ret = stream->ops->read(stream, &state);
+
+       /* If we've successfully copied any data then reporting that
+        * takes precedence over any internal error status, so the
+        * data isn't lost
+        */
+       return state.read ? state.read : (ret ? ret : -EAGAIN);
+}
+
+static ssize_t i915_perf_read(struct file *file,
+                             char __user *buf,
+                             size_t count,
+                             loff_t *ppos)
+{
+       struct i915_perf_stream *stream = file->private_data;
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       ssize_t ret;
+
+       if (!(file->f_flags & O_NONBLOCK)) {
+               /* Allow false positives from stream->ops->wait_unlocked.
+                */
+               do {
+                       ret = stream->ops->wait_unlocked(stream);
+                       if (ret)
+                               return ret;
+
+                       mutex_lock(&dev_priv->perf.lock);
+                       ret = i915_perf_read_locked(stream, file,
+                                                   buf, count, ppos);
+                       mutex_unlock(&dev_priv->perf.lock);
+               } while (ret == -EAGAIN);
+       } else {
+               mutex_lock(&dev_priv->perf.lock);
+               ret = i915_perf_read_locked(stream, file, buf, count, ppos);
+               mutex_unlock(&dev_priv->perf.lock);
+       }
+
+       return ret;
+}
+
+static unsigned int i915_perf_poll_locked(struct i915_perf_stream *stream,
+                                         struct file *file,
+                                         poll_table *wait)
+{
+       unsigned int streams = 0;
+
+       stream->ops->poll_wait(stream, file, wait);
+
+       if (stream->ops->can_read(stream))
+               streams |= POLLIN;
+
+       return streams;
+}
+
+static unsigned int i915_perf_poll(struct file *file, poll_table *wait)
+{
+       struct i915_perf_stream *stream = file->private_data;
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       int ret;
+
+       mutex_lock(&dev_priv->perf.lock);
+       ret = i915_perf_poll_locked(stream, file, wait);
+       mutex_unlock(&dev_priv->perf.lock);
+
+       return ret;
+}
+
+static void i915_perf_enable_locked(struct i915_perf_stream *stream)
+{
+       if (stream->enabled)
+               return;
+
+       /* Allow stream->ops->enable() to refer to this */
+       stream->enabled = true;
+
+       if (stream->ops->enable)
+               stream->ops->enable(stream);
+}
+
+static void i915_perf_disable_locked(struct i915_perf_stream *stream)
+{
+       if (!stream->enabled)
+               return;
+
+       /* Allow stream->ops->disable() to refer to this */
+       stream->enabled = false;
+
+       if (stream->ops->disable)
+               stream->ops->disable(stream);
+}
+
+static long i915_perf_ioctl_locked(struct i915_perf_stream *stream,
+                                  unsigned int cmd,
+                                  unsigned long arg)
+{
+       switch (cmd) {
+       case I915_PERF_IOCTL_ENABLE:
+               i915_perf_enable_locked(stream);
+               return 0;
+       case I915_PERF_IOCTL_DISABLE:
+               i915_perf_disable_locked(stream);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static long i915_perf_ioctl(struct file *file,
+                           unsigned int cmd,
+                           unsigned long arg)
+{
+       struct i915_perf_stream *stream = file->private_data;
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+       long ret;
+
+       mutex_lock(&dev_priv->perf.lock);
+       ret = i915_perf_ioctl_locked(stream, cmd, arg);
+       mutex_unlock(&dev_priv->perf.lock);
+
+       return ret;
+}
+
+static void i915_perf_destroy_locked(struct i915_perf_stream *stream)
+{
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+
+       if (stream->enabled)
+               i915_perf_disable_locked(stream);
+
+       if (stream->ops->destroy)
+               stream->ops->destroy(stream);
+
+       list_del(&stream->link);
+
+       if (stream->ctx) {
+               mutex_lock(&dev_priv->dev->struct_mutex);
+               i915_gem_context_unreference(stream->ctx);
+               mutex_unlock(&dev_priv->dev->struct_mutex);
+       }
+
+       kfree(stream);
+}
+
+static int i915_perf_release(struct inode *inode, struct file *file)
+{
+       struct i915_perf_stream *stream = file->private_data;
+       struct drm_i915_private *dev_priv = stream->dev_priv;
+
+       mutex_lock(&dev_priv->perf.lock);
+       i915_perf_destroy_locked(stream);
+       mutex_unlock(&dev_priv->perf.lock);
+
+       return 0;
+}
+
+
+static const struct file_operations fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .release        = i915_perf_release,
+       .poll           = i915_perf_poll,
+       .read           = i915_perf_read,
+       .unlocked_ioctl = i915_perf_ioctl,
+};
+
+
+static struct intel_context *
+lookup_context(struct drm_i915_private *dev_priv,
+              struct drm_i915_file_private *file_priv,
+              u32 ctx_user_handle)
+{
+       struct intel_context *ctx;
+       int ret;
+
+       ret = i915_mutex_lock_interruptible(dev_priv->dev);
+       if (ret)
+               return ERR_PTR(ret);
+
+       ctx = i915_gem_context_get(file_priv, ctx_user_handle);
+       if (!IS_ERR(ctx))
+               i915_gem_context_reference(ctx);
+
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+
+       return ctx;
+}
+
+int i915_perf_open_ioctl_locked(struct drm_device *dev,
+                               struct drm_i915_perf_open_param *param,
+                               struct perf_open_properties *props,
+                               struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_context *specific_ctx = NULL;
+       struct i915_perf_stream *stream = NULL;
+       unsigned long f_flags = 0;
+       int stream_fd;
+       int ret = 0;
+
+       if (props->single_context) {
+               u32 ctx_handle = props->ctx_handle;
+               struct drm_i915_file_private *file_priv = file->driver_priv;
+
+               specific_ctx = lookup_context(dev_priv, file_priv, ctx_handle);
+               if (IS_ERR(specific_ctx)) {
+                       ret = PTR_ERR(specific_ctx);
+                       if (ret != -EINTR)
+                               DRM_ERROR("Failed to look up context with ID %u 
for opening perf stream\n",
+                                         ctx_handle);
+                       goto err;
+               }
+       }
+
+       if (!specific_ctx && !capable(CAP_SYS_ADMIN)) {
+               DRM_ERROR("Insufficient privileges to open system-wide i915 
perf stream\n");
+               ret = -EACCES;
+               goto err_ctx;
+       }
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream) {
+               ret = -ENOMEM;
+               goto err_ctx;
+       }
+
+       stream->sample_flags = props->sample_flags;
+       stream->dev_priv = dev_priv;
+       stream->ctx = specific_ctx;
+
+       /*
+        * TODO: support sampling something
+        *
+        * For now this is as far as we can go.
+        */
+       DRM_ERROR("Unsupported i915 perf stream configuration\n");
+       ret = -EINVAL;
+       goto err_alloc;
+
+       list_add(&stream->link, &dev_priv->perf.streams);
+
+       if (param->flags & I915_PERF_FLAG_FD_CLOEXEC)
+               f_flags |= O_CLOEXEC;
+       if (param->flags & I915_PERF_FLAG_FD_NONBLOCK)
+               f_flags |= O_NONBLOCK;
+
+       stream_fd = anon_inode_getfd("[i915_perf]", &fops, stream, f_flags);
+       if (stream_fd < 0) {
+               ret = stream_fd;
+               goto err_open;
+       }
+
+       if (!(param->flags & I915_PERF_FLAG_DISABLED))
+               i915_perf_enable_locked(stream);
+
+       return stream_fd;
+
+err_open:
+       list_del(&stream->link);
+       if (stream->ops->destroy)
+               stream->ops->destroy(stream);
+err_alloc:
+       kfree(stream);
+err_ctx:
+       if (specific_ctx) {
+               mutex_lock(&dev_priv->dev->struct_mutex);
+               i915_gem_context_unreference(specific_ctx);
+               mutex_unlock(&dev_priv->dev->struct_mutex);
+       }
+err:
+       return ret;
+}
+
+/* Note we copy the properties from userspace outside of the i915 perf
+ * mutex to avoid an awkward lockdep with mmap_sem.
+ *
+ * Note this function only validates properties in isolation it doesn't
+ * validate that the combination of properties makes sense or that all
+ * properties necessary for a particular kind of stream have been set.
+ */
+static int read_properties_unlocked(struct drm_i915_private *dev_priv,
+                                   u64 __user *uprops,
+                                   u32 n_props,
+                                   struct perf_open_properties *props)
+{
+       u64 __user *uprop = uprops;
+       int i;
+
+       memset(props, 0, sizeof(struct perf_open_properties));
+
+       if (!n_props) {
+               DRM_ERROR("No i915 perf properties given");
+               return -EINVAL;
+       }
+
+       if (n_props > DRM_I915_PERF_PROP_MAX) {
+               DRM_ERROR("More i915 perf properties specified than exist");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < n_props; i++) {
+               u64 id, value;
+               int ret;
+
+               ret = get_user(id, (u64 __user *)uprop);
+               if (ret)
+                       return ret;
+
+               if (id == 0 || id >= DRM_I915_PERF_PROP_MAX) {
+                       DRM_ERROR("Unknown i915 perf property ID");
+                       return -EINVAL;
+               }
+
+               ret = get_user(value, (u64 __user *)uprop + 1);
+               if (ret)
+                       return ret;
+
+               switch ((enum drm_i915_perf_property_id)id) {
+               case DRM_I915_PERF_PROP_CTX_HANDLE:
+                       props->single_context = 1;
+                       props->ctx_handle = value;
+                       break;
+
+               case DRM_I915_PERF_PROP_MAX:
+                       BUG();
+               }
+
+               uprop += 2;
+       }
+
+       return 0;
+}
+
+int i915_perf_open_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_perf_open_param *param = data;
+       struct perf_open_properties props;
+       u32 known_open_flags = 0;
+       int ret;
+
+       if (!dev_priv->perf.initialized) {
+               DRM_ERROR("i915 perf interface not available for this system");
+               return -ENOTSUPP;
+       }
+
+       known_open_flags = I915_PERF_FLAG_FD_CLOEXEC |
+                          I915_PERF_FLAG_FD_NONBLOCK |
+                          I915_PERF_FLAG_DISABLED;
+       if (param->flags & ~known_open_flags) {
+               DRM_ERROR("Unknown drm_i915_perf_open_param flag\n");
+               return -EINVAL;
+       }
+
+       ret = read_properties_unlocked(dev_priv,
+                                      to_user_ptr(param->properties_ptr),
+                                      param->num_properties,
+                                      &props);
+       if (ret)
+               return ret;
+
+       mutex_lock(&dev_priv->perf.lock);
+       ret = i915_perf_open_ioctl_locked(dev, param, &props, file);
+       mutex_unlock(&dev_priv->perf.lock);
+
+       return ret;
+}
+
+void i915_perf_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       INIT_LIST_HEAD(&dev_priv->perf.streams);
+       mutex_init(&dev_priv->perf.lock);
+
+       dev_priv->perf.initialized = true;
+}
+
+void i915_perf_fini(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+
+       if (!dev_priv->perf.initialized)
+               return;
+
+       /* Currently nothing to clean up */
+
+       dev_priv->perf.initialized = false;
+}
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index a5524cc..962cc96 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -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_PERF_OPEN             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_PERF_OPEN       DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1170,4 +1172,69 @@ struct drm_i915_gem_context_param {
        __u64 value;
 };
 
+enum drm_i915_perf_property_id {
+       /**
+        * Open the stream for a specific context handle (as used with
+        * execbuffer2). A stream opened for a specific context this way
+        * won't typically require root privileges.
+        */
+       DRM_I915_PERF_PROP_CTX_HANDLE = 1,
+
+       DRM_I915_PERF_PROP_MAX /* non-ABI */
+};
+
+struct drm_i915_perf_open_param {
+       __u32 flags;
+#define I915_PERF_FLAG_FD_CLOEXEC      (1<<0)
+#define I915_PERF_FLAG_FD_NONBLOCK     (1<<1)
+#define I915_PERF_FLAG_DISABLED                (1<<2)
+
+       /** The number of u64 (id, value) pairs */
+       __u32 num_properties;
+
+       /**
+        * Pointer to array of u64 (id, value) pairs configuring the stream
+        * to open.
+        */
+       __u64 __user properties_ptr;
+};
+
+#define I915_PERF_IOCTL_ENABLE _IO('i', 0x0)
+#define I915_PERF_IOCTL_DISABLE        _IO('i', 0x1)
+
+/**
+ * Common to all i915 perf records
+ */
+struct drm_i915_perf_record_header {
+       __u32 type;
+       __u16 pad;
+       __u16 size;
+};
+
+enum drm_i915_perf_record_type {
+
+       /**
+        * Samples are the work horse record type whose contents are extensible
+        * and defined when opening an i915 perf stream based on the given
+        * properties.
+        *
+        * Boolean properties following the naming convention
+        * DRM_I915_PERF_SAMPLE_xyz_PROP request the inclusion of 'xyz' data in
+        * every sample.
+        *
+        * The order of these sample properties given by userspace has no
+        * affect on the ordering of data within a sample. The order will be
+        * documented here.
+        *
+        * struct {
+        *     struct drm_i915_perf_record_header header;
+        *
+        *     TODO: itemize extensible sample data here
+        * };
+        */
+       DRM_I915_PERF_RECORD_SAMPLE = 1,
+
+       DRM_I915_PERF_RECORD_MAX /* non-ABI */
+};
+
 #endif /* _UAPI_I915_DRM_H_ */
-- 
2.7.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to