@@ -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,
@@ -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 \
new file mode 100644
@@ -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;
+}
@@ -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 = {
@@ -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,
@@ -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
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.roper@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