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@xxxxxxxxx> --- 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 -- To unsubscribe from this list: send the line "unsubscribe cgroups" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html