@@ -48,6 +48,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,167 @@
+/* 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_priv base;
+
+ struct list_head node;
+};
+
+static inline struct i915_cgroup_data *
+cgrp_to_i915(struct cgroup_priv *priv)
+{
+ return container_of(priv, struct i915_cgroup_data, base);
+}
+
+static void
+i915_cgroup_free(struct cgroup_priv *priv)
+{
+ struct cgroup *cgrp = priv->cgroup;
+ struct i915_cgroup_data *ipriv;
+
+ WARN_ON(!mutex_is_locked(&cgrp->privdata_mutex));
+
+ ipriv = cgrp_to_i915(priv);
+
+ /*
+ * Remove private data from both cgroup's hashtable and i915's list.
+ * If this function is being called as a result of cgroup removal
+ * (as opposed to an i915 unload), it will have already been removed from
+ * the hashtable, but the hash_del() call here is still safe.
+ */
+ hash_del(&priv->hnode);
+ list_del(&ipriv->node);
+
+ kfree(ipriv);
+}
+
+void
+i915_cgroup_init(struct drm_i915_private *dev_priv)
+{
+ INIT_LIST_HEAD(&dev_priv->cgroup_list);
+}
+
+void
+i915_cgroup_shutdown(struct drm_i915_private *dev_priv)
+{
+ struct i915_cgroup_data *priv, *tmp;
+ struct cgroup *cgrp;
+
+ mutex_lock(&cgroup_mutex);
+
+ list_for_each_entry_safe(priv, tmp, &dev_priv->cgroup_list, node) {
+ cgrp = priv->base.cgroup;
+
+ mutex_lock(&cgrp->privdata_mutex);
+ i915_cgroup_free(&priv->base);
+ mutex_unlock(&cgrp->privdata_mutex);
+ }
+
+ mutex_unlock(&cgroup_mutex);
+}
+
+/*
+ * Return i915 cgroup private data, creating and registering it if one doesn't
+ * already exist for this cgroup.
+ */
+static struct i915_cgroup_data *
+get_or_create_cgroup_data(struct drm_i915_private *dev_priv,
+ struct cgroup *cgrp)
+{
+ struct cgroup_priv *priv;
+ struct i915_cgroup_data *ipriv;
+
+ mutex_lock(&cgrp->privdata_mutex);
+
+ priv = cgroup_priv_lookup(cgrp, dev_priv);
+ if (priv) {
+ ipriv = cgrp_to_i915(priv);
+ } else {
+ ipriv = kzalloc(sizeof *ipriv, GFP_KERNEL);
+ if (!ipriv) {
+ ipriv = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ ipriv->base.key = dev_priv;
+ ipriv->base.free = i915_cgroup_free;
+ list_add(&ipriv->node, &dev_priv->cgroup_list);
+
+ cgroup_priv_install(cgrp, &ipriv->base);
+ }
+
+out:
+ mutex_unlock(&cgrp->privdata_mutex);
+
+ return ipriv;
+}
+
+/**
+ * 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_cgroup_param *req = data;
+ struct cgroup *cgrp;
+ int ret;
+
+ /* 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).
+ */
+ ret = cgroup_permission(req->cgroup_fd, MAY_WRITE);
+ if (ret)
+ goto out;
+
+ switch (req->param) {
+ default:
+ DRM_DEBUG_DRIVER("Invalid cgroup parameter %lld\n", req->param);
+ ret = -EINVAL;
+ }
+
+out:
+ cgroup_put(cgrp);
+
+ return ret;
+}
@@ -1405,6 +1405,8 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
intel_runtime_pm_put(dev_priv);
+ i915_cgroup_init(dev_priv);
+
i915_welcome_messages(dev_priv);
return 0;
@@ -1431,6 +1433,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))
@@ -2832,6 +2836,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 = {
@@ -2006,6 +2006,9 @@ struct drm_i915_private {
struct intel_ppat ppat;
+ /* cgroup private data */
+ struct list_head cgroup_list;
+
/* Kernel Modesetting */
struct intel_crtc *plane_to_crtc_mapping[I915_MAX_PIPES];
@@ -2938,6 +2941,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
+void 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.
@@ -1615,6 +1617,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
Introduce a new DRM_IOCTL_I915_CGROUP_SETPARAM ioctl that will allow userspace to set i915-specific parameters for individual cgroups. i915 cgroup data will be registered and later looked up via the new cgroup_priv infrastructure. v2: - Large rebase/rewrite for new cgroup_priv interface Signed-off-by: Matt Roper <matthew.d.roper@intel.com> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_cgroup.c | 167 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.c | 5 ++ drivers/gpu/drm/i915/i915_drv.h | 24 ++++++ include/uapi/drm/i915_drm.h | 12 +++ 5 files changed, 209 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_cgroup.c