@@ -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,140 @@
+/* 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 kref ref;
+};
+
+static inline struct i915_cgroup_data *
+cgrp_ref_to_i915(struct kref *ref)
+{
+ return container_of(ref, struct i915_cgroup_data, ref);
+}
+
+static void
+i915_cgroup_free(struct kref *ref)
+{
+ struct i915_cgroup_data *priv;
+
+ priv = cgrp_ref_to_i915(ref);
+ kfree(priv);
+}
+
+int
+i915_cgroup_init(struct drm_i915_private *dev_priv)
+{
+ int ret = 0;
+
+ dev_priv->cgroup_priv_key = cgroup_priv_getkey(i915_cgroup_free);
+ if (dev_priv->cgroup_priv_key < 0) {
+ DRM_DEBUG_DRIVER("Failed to get a cgroup private data key\n");
+ ret = dev_priv->cgroup_priv_key;
+ }
+
+ mutex_init(&dev_priv->cgroup_lock);
+
+ return ret;
+}
+
+void
+i915_cgroup_shutdown(struct drm_i915_private *dev_priv)
+{
+ cgroup_priv_destroykey(dev_priv->cgroup_priv_key);
+}
+
+/*
+ * Return i915 cgroup private data, creating and registering it if one doesn't
+ * already exist for this cgroup.
+ */
+__maybe_unused
+static struct i915_cgroup_data *
+get_or_create_cgroup_data(struct drm_i915_private *dev_priv,
+ struct cgroup *cgrp)
+{
+ struct kref *ref;
+ struct i915_cgroup_data *priv;
+
+ mutex_lock(&dev_priv->cgroup_lock);
+
+ ref = cgroup_priv_get(cgrp, dev_priv->cgroup_priv_key);
+ if (ref) {
+ priv = cgrp_ref_to_i915(ref);
+ } else {
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ priv = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ kref_init(&priv->ref);
+ cgroup_priv_install(cgrp, dev_priv->cgroup_priv_key,
+ &priv->ref);
+ }
+
+out:
+ mutex_unlock(&dev_priv->cgroup_lock);
+
+ return priv;
+}
+
+/**
+ * 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: For now we grant access via CAP_SYS_RESOURCE _or_
+ * DRM master status.
+ */
+ if (!capable(CAP_SYS_RESOURCE) && !drm_is_current_master(file)) {
+ DRM_DEBUG_DRIVER("Insufficient permissions to adjust i915 cgroup settings\n");
+ goto out;
+ }
+
+ switch (req->param) {
+ default:
+ DRM_DEBUG_DRIVER("Invalid cgroup parameter %lld\n", req->param);
+ ret = -EINVAL;
+ }
+
+out:
+ cgroup_put(cgrp);
+
+ return ret;
+}
@@ -1407,6 +1407,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;
@@ -1433,6 +1437,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))
@@ -2833,6 +2839,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
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_QUERY, i915_query_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 = {
@@ -1738,6 +1738,15 @@ struct drm_i915_private {
struct intel_ppat ppat;
+ /* cgroup private data */
+ int cgroup_priv_key;
+
+ /*
+ * protects against concurrent attempts to create private data for a
+ * cgroup
+ */
+ struct mutex cgroup_lock;
+
/* Kernel Modesetting */
struct intel_crtc *plane_to_crtc_mapping[I915_MAX_PIPES];
@@ -2678,6 +2687,29 @@ 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,
@@ -319,6 +319,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_PERF_ADD_CONFIG 0x37
#define DRM_I915_PERF_REMOVE_CONFIG 0x38
#define DRM_I915_QUERY 0x39
+#define DRM_I915_CGROUP_SETPARAM 0x3a
#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)
@@ -377,6 +378,7 @@ typedef struct _drm_i915_sarea {
#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_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
+#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.
@@ -1717,6 +1719,16 @@ struct drm_i915_query_topology_info {
__u8 data[];
};
+/**
+ * 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 v3: - Another rebase/rewrite for ida-based keys and kref-based storage - Access control no longer follows cgroup filesystem permissions; instead we restrict access to either DRM master or capable(CAP_SYS_RESOURCE). v4: - Fix checkpatch warnings (Intel CI) Signed-off-by: Matt Roper <matthew.d.roper@intel.com> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_cgroup.c | 140 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.c | 8 +++ drivers/gpu/drm/i915/i915_drv.h | 32 +++++++++ include/uapi/drm/i915_drm.h | 12 ++++ 5 files changed, 193 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_cgroup.c