Register i915 as a consumer of the cgroup_driver framework and add an ioctl to
allow userspace to set i915-specific parameters associated with cgroups.

Signed-off-by: Matt Roper <matthew.d.ro...@intel.com>
---
 drivers/gpu/drm/i915/Kconfig       |   1 +
 drivers/gpu/drm/i915/Makefile      |   1 +
 drivers/gpu/drm/i915/i915_cgroup.c | 134 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.c    |   7 ++
 drivers/gpu/drm/i915/i915_drv.h    |  24 +++++++
 include/uapi/drm/i915_drm.h        |  12 ++++
 6 files changed, 179 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_cgroup.c

diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index dfd95889f4b7..1c6b53ee76cd 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -23,6 +23,7 @@ config DRM_I915
        select SYNC_FILE
        select IOSF_MBI
        select CRC32
+       select CGROUP_DRIVER if CGROUPS
        help
          Choose this option if you have a system that has "Intel Graphics
          Media Accelerator" or "HD Graphics" integrated graphics,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 3bddd8a06806..5f4a21f1a9df 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -47,6 +47,7 @@ i915-y := i915_drv.o \
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o intel_pipe_crc.o
 i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o
+i915-$(CONFIG_CGROUPS) += i915_cgroup.o
 
 # GEM code
 i915-y += i915_cmd_parser.o \
diff --git a/drivers/gpu/drm/i915/i915_cgroup.c 
b/drivers/gpu/drm/i915/i915_cgroup.c
new file mode 100644
index 000000000000..778af895fc00
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_cgroup.c
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * i915_cgroup.c - Linux cgroups integration for i915
+ *
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/cgroup.h>
+
+#include "i915_drv.h"
+
+struct i915_cgroup_data {
+       struct cgroup_driver_data base;
+};
+
+static inline struct i915_cgroup_data *
+cgrp_to_i915(struct cgroup_driver_data *data)
+{
+       return container_of(data, struct i915_cgroup_data, base);
+}
+
+static struct cgroup_driver_data *
+i915_cgroup_alloc(struct cgroup_driver *drv)
+{
+       struct i915_cgroup_data *data;
+
+       data = kzalloc(sizeof *data, GFP_KERNEL);
+       return &data->base;
+}
+
+static void
+i915_cgroup_free(struct cgroup_driver_data *data)
+{
+       kfree(data);
+}
+
+static struct cgroup_driver_funcs i915_cgroup_funcs = {
+       .alloc_data = i915_cgroup_alloc,
+       .free_data = i915_cgroup_free,
+};
+
+int
+i915_cgroup_init(struct drm_i915_private *dev_priv)
+{
+       dev_priv->i915_cgroups = cgroup_driver_init(&i915_cgroup_funcs);
+       if (IS_ERR(dev_priv->i915_cgroups))
+               return PTR_ERR(dev_priv->i915_cgroups);
+
+       return 0;
+}
+
+void
+i915_cgroup_shutdown(struct drm_i915_private *dev_priv)
+{
+       cgroup_driver_release(dev_priv->i915_cgroups);
+}
+
+/**
+ * i915_cgroup_setparam_ioctl - ioctl to alter i915 settings for a cgroup
+ * @dev: DRM device
+ * @data: data pointer for the ioctl
+ * @file_priv: DRM file handle for the ioctl call
+ *
+ * Allows i915-specific parameters to be set for a Linux cgroup.
+ */
+int
+i915_cgroup_setparam_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_cgroup_param *req = data;
+       struct cgroup *cgrp;
+       struct file *f;
+       struct inode *inode = NULL;
+       int ret;
+
+       if (!dev_priv->i915_cgroups) {
+               DRM_DEBUG_DRIVER("No support for driver-specific cgroup 
data\n");
+               return -EINVAL;
+       }
+
+       /* We don't actually support any flags yet. */
+       if (req->flags) {
+               DRM_DEBUG_DRIVER("Invalid flags\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Make sure the file descriptor really is a cgroup fd and is on the
+        * v2 hierarchy.
+        */
+       cgrp = cgroup_get_from_fd(req->cgroup_fd);
+       if (IS_ERR(cgrp)) {
+               DRM_DEBUG_DRIVER("Invalid cgroup file descriptor\n");
+               return PTR_ERR(cgrp);
+       }
+
+       /*
+        * Access control:  The strategy for using cgroups in a given
+        * environment is generally determined by the system integrator
+        * and/or OS vendor, so the specific policy about who can/can't
+        * manipulate them tends to be domain-specific (and may vary
+        * depending on the location in the cgroup hierarchy).  Rather than
+        * trying to tie permission on this ioctl to a DRM-specific concepts
+        * like DRM master, we'll allow cgroup parameters to be set by any
+        * process that has been granted write access on the cgroup's
+        * virtual file system (i.e., the same permissions that would
+        * generally be needed to update the virtual files provided by
+        * cgroup controllers).
+        */
+       f = fget_raw(req->cgroup_fd);
+       if (WARN_ON(!f))
+               return -EBADF;
+
+       inode = kernfs_get_inode(f->f_path.dentry->d_sb, cgrp->kn);
+       if (inode)
+               ret = inode_permission(inode, MAY_WRITE);
+       else
+               ret = -ENOMEM;
+
+       iput(inode);
+       fput(f);
+
+       if (ret)
+               return ret;
+
+       switch (req->param) {
+       default:
+               DRM_DEBUG_DRIVER("Invalid cgroup parameter %lld\n", req->param);
+               return -EINVAL;
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 1ec12add34b2..5d5e652598fb 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1398,6 +1398,10 @@ int i915_driver_load(struct pci_dev *pdev, const struct 
pci_device_id *ent)
 
        intel_runtime_pm_put(dev_priv);
 
+       ret = i915_cgroup_init(dev_priv);
+       if (ret < 0)
+           goto out_cleanup_hw;
+
        i915_welcome_messages(dev_priv);
 
        return 0;
@@ -1424,6 +1428,8 @@ void i915_driver_unload(struct drm_device *dev)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct pci_dev *pdev = dev_priv->drm.pdev;
 
+       i915_cgroup_shutdown(dev_priv);
+
        i915_driver_unregister(dev_priv);
 
        if (i915_gem_suspend(dev_priv))
@@ -2835,6 +2841,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, 
DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, 
DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, 
i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_CGROUP_SETPARAM, i915_cgroup_setparam_ioctl, 
DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 
 static struct drm_driver driver = {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c676269ed843..60e3ff6a48bb 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2357,6 +2357,9 @@ struct drm_i915_private {
 
        struct i915_pmu pmu;
 
+       /* Linux cgroup integration */
+       struct cgroup_driver *i915_cgroups;
+
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@ -2911,6 +2914,27 @@ intel_ggtt_update_needs_vtd_wa(struct drm_i915_private 
*dev_priv)
 int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
                                int enable_ppgtt);
 
+/* i915_cgroup.c */
+#ifdef CONFIG_CGROUPS
+int i915_cgroup_init(struct drm_i915_private *dev_priv);
+int i915_cgroup_setparam_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file);
+void i915_cgroup_shutdown(struct drm_i915_private *dev_priv);
+#else
+static inline int
+i915_cgroup_init(struct drm_i915_private *dev_priv)
+{
+       return 0;
+}
+static inline void i915_cgroup_shutdown(struct drm_i915_private *dev_priv) {}
+static inline int
+i915_cgroup_setparam_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file)
+{
+       return -EINVAL;
+}
+#endif
+
 /* i915_drv.c */
 void __printf(3, 4)
 __i915_printk(struct drm_i915_private *dev_priv, const char *level,
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 536ee4febd74..fe333ae1f0c6 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_PERF_OPEN             0x36
 #define DRM_I915_PERF_ADD_CONFIG       0x37
 #define DRM_I915_PERF_REMOVE_CONFIG    0x38
+#define DRM_I915_CGROUP_SETPARAM       0x39
 
 #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)
@@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_PERF_OPEN       DRM_IOW(DRM_COMMAND_BASE + 
DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
 #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + 
DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
 #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG      DRM_IOW(DRM_COMMAND_BASE + 
DRM_I915_PERF_REMOVE_CONFIG, __u64)
+#define DRM_IOCTL_I915_CGROUP_SETPARAM         DRM_IOW(DRM_COMMAND_BASE + 
DRM_I915_CGROUP_SETPARAM, struct drm_i915_cgroup_param)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1613,6 +1615,16 @@ struct drm_i915_perf_oa_config {
        __u64 flex_regs_ptr;
 };
 
+/**
+ * Structure to set i915 parameter on a cgroup.
+ */
+struct drm_i915_cgroup_param {
+       __s32 cgroup_fd;
+       __u32 flags;
+       __u64 param;
+       __s64 value;
+};
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.14.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to