Since many parts of the DRM subsystem has vendor-specific implementations, we introduce mechanisms for vendor to register their specific resources and control files to the DRM cgroup subsystem. A vendor will register itself with the DRM cgroup subsystem first before registering individual DRM devices to the cgroup subsystem. In addition to the cgroup_subsys_state that is common to all DRM devices, a device-specific state is introduced and it is allocated according to the vendor of the device. Change-Id: I908ee6975ea0585e4c30eafde4599f87094d8c65 Signed-off-by: Kenny Ho <Kenny.Ho@xxxxxxx> --- include/drm/drm_cgroup.h | 39 ++++++++++++++++ include/drm/drmcgrp_vendors.h | 7 +++ include/linux/cgroup_drm.h | 26 +++++++++++ kernel/cgroup/drm.c | 84 +++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 include/drm/drm_cgroup.h create mode 100644 include/drm/drmcgrp_vendors.h diff --git a/include/drm/drm_cgroup.h b/include/drm/drm_cgroup.h new file mode 100644 index 000000000000..26cbea7059a6 --- /dev/null +++ b/include/drm/drm_cgroup.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: MIT + * Copyright 2018 Advanced Micro Devices, Inc. + */ +#ifndef __DRM_CGROUP_H__ +#define __DRM_CGROUP_H__ + +#define DRMCGRP_VENDOR(_x) _x ## _drmcgrp_vendor_id, +enum drmcgrp_vendor_id { +#include <drm/drmcgrp_vendors.h> + DRMCGRP_VENDOR_COUNT, +}; +#undef DRMCGRP_VENDOR + +#define DRMCGRP_VENDOR(_x) extern struct drmcgrp_vendor _x ## _drmcgrp_vendor; +#include <drm/drmcgrp_vendors.h> +#undef DRMCGRP_VENDOR + + + +#ifdef CONFIG_CGROUP_DRM + +extern struct drmcgrp_vendor *drmcgrp_vendors[]; + +int drmcgrp_register_vendor(struct drmcgrp_vendor *vendor, enum drmcgrp_vendor_id id); +int drmcgrp_register_device(struct drm_device *device, enum drmcgrp_vendor_id id); + +#else +static int drmcgrp_register_vendor(struct drmcgrp_vendor *vendor, enum drmcgrp_vendor_id id) +{ + return 0; +} + +static int drmcgrp_register_device(struct drm_device *device, enum drmcgrp_vendor_id id) +{ + return 0; +} + +#endif /* CONFIG_CGROUP_DRM */ +#endif /* __DRM_CGROUP_H__ */ diff --git a/include/drm/drmcgrp_vendors.h b/include/drm/drmcgrp_vendors.h new file mode 100644 index 000000000000..b04d8649851b --- /dev/null +++ b/include/drm/drmcgrp_vendors.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: MIT + * Copyright 2018 Advanced Micro Devices, Inc. + */ +#if IS_ENABLED(CONFIG_CGROUP_DRM) + + +#endif diff --git a/include/linux/cgroup_drm.h b/include/linux/cgroup_drm.h index 79ab38b0f46d..a776662d9593 100644 --- a/include/linux/cgroup_drm.h +++ b/include/linux/cgroup_drm.h @@ -6,10 +6,36 @@ #ifdef CONFIG_CGROUP_DRM +#include <linux/mutex.h> #include <linux/cgroup.h> +#include <drm/drm_file.h> +#include <drm/drm_cgroup.h> + +/* limit defined per the way drm_minor_alloc operates */ +#define MAX_DRM_DEV (64 * DRM_MINOR_RENDER) + +struct drmcgrp_device { + enum drmcgrp_vendor_id vid; + struct drm_device *dev; + struct mutex mutex; +}; + +/* vendor-common resource counting goes here */ +/* this struct should be included in the vendor specific resource */ +struct drmcgrp_device_resource { + struct drmcgrp_device *ddev; +}; + +struct drmcgrp_vendor { + struct cftype *(*get_cftypes)(void); + struct drmcgrp_device_resource *(*alloc_dev_resource)(void); + void (*free_dev_resource)(struct drmcgrp_device_resource *dev_resource); +}; + struct drmcgrp { struct cgroup_subsys_state css; + struct drmcgrp_device_resource *dev_resources[MAX_DRM_DEV]; }; static inline struct drmcgrp *css_drmcgrp(struct cgroup_subsys_state *css) diff --git a/kernel/cgroup/drm.c b/kernel/cgroup/drm.c index d9e194b9aead..f9630cc389bc 100644 --- a/kernel/cgroup/drm.c +++ b/kernel/cgroup/drm.c @@ -1,8 +1,30 @@ // SPDX-License-Identifier: MIT // Copyright 2018 Advanced Micro Devices, Inc. +#include <linux/export.h> #include <linux/slab.h> #include <linux/cgroup.h> +#include <linux/fs.h> +#include <linux/seq_file.h> +#include <linux/mutex.h> #include <linux/cgroup_drm.h> +#include <drm/drm_device.h> +#include <drm/drm_cgroup.h> + +/* generate an array of drm cgroup vendor pointers */ +#define DRMCGRP_VENDOR(_x)[_x ## _drmcgrp_vendor_id] = NULL, +struct drmcgrp_vendor *drmcgrp_vendors[] = { +#include <drm/drmcgrp_vendors.h> +}; +#undef DRMCGRP_VENDOR +EXPORT_SYMBOL(drmcgrp_vendors); + +static DEFINE_MUTEX(drmcgrp_mutex); + +/* indexed by drm_minor for access speed */ +static struct drmcgrp_device *known_drmcgrp_devs[MAX_DRM_DEV]; + +static int max_minor; + static u64 drmcgrp_test_read(struct cgroup_subsys_state *css, struct cftype *cft) @@ -13,6 +35,12 @@ static u64 drmcgrp_test_read(struct cgroup_subsys_state *css, static void drmcgrp_css_free(struct cgroup_subsys_state *css) { struct drmcgrp *drmcgrp = css_drmcgrp(css); + int i; + + for (i = 0; i <= max_minor; i++) { + if (drmcgrp->dev_resources[i] != NULL) + drmcgrp_vendors[known_drmcgrp_devs[i]->vid]->free_dev_resource(drmcgrp->dev_resources[i]); + } kfree(css_drmcgrp(css)); } @@ -21,11 +49,27 @@ static struct cgroup_subsys_state * drmcgrp_css_alloc(struct cgroup_subsys_state *parent_css) { struct drmcgrp *drmcgrp; + int i; drmcgrp = kzalloc(sizeof(struct drmcgrp), GFP_KERNEL); if (!drmcgrp) return ERR_PTR(-ENOMEM); + for (i = 0; i <= max_minor; i++) { + if (known_drmcgrp_devs[i] != NULL) { + struct drmcgrp_device_resource *ddr = + drmcgrp_vendors[known_drmcgrp_devs[i]->vid]->alloc_dev_resource(); + + if (IS_ERR(ddr)) { + drmcgrp_css_free(&drmcgrp->css); + return ERR_PTR(-ENOMEM); + } + + drmcgrp->dev_resources[i] = ddr; + drmcgrp->dev_resources[i]->ddev = known_drmcgrp_devs[i]; + } + } + return &drmcgrp->css; } @@ -44,3 +88,43 @@ struct cgroup_subsys drm_cgrp_subsys = { .legacy_cftypes = files, .dfl_cftypes = files, }; + +int drmcgrp_register_vendor(struct drmcgrp_vendor *vendor, enum drmcgrp_vendor_id id) +{ + int rc = 0; + struct cftype *cfts; + + // TODO: root css created before any registration + if (drmcgrp_vendors[id] == NULL) { + drmcgrp_vendors[id] = vendor; + cfts = vendor->get_cftypes(); + if (cfts != NULL) + rc = cgroup_add_legacy_cftypes(&drm_cgrp_subsys, cfts); + } + return rc; +} +EXPORT_SYMBOL(drmcgrp_register_vendor); + + +int drmcgrp_register_device(struct drm_device *dev, enum drmcgrp_vendor_id id) +{ + struct drmcgrp_device *ddev; + + ddev = kzalloc(sizeof(struct drmcgrp_device), GFP_KERNEL); + if (!ddev) + return -ENOMEM; + + mutex_lock(&drmcgrp_mutex); + + ddev->vid = id; + ddev->dev = dev; + mutex_init(&ddev->mutex); + + known_drmcgrp_devs[dev->primary->index] = ddev; + + max_minor = max(max_minor, dev->primary->index); + + mutex_unlock(&drmcgrp_mutex); + return 0; +} +EXPORT_SYMBOL(drmcgrp_register_device); -- 2.19.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel