<div dir="ltr"><div>Pardon my ignorance but I'm a bit confused by this. What is a "logical GPU"? What are we subdividing? Are we carving up memory? Compute power? Both?</div><div><br></div><div>If it's carving up memory, why aren't we just measuring it in megabytes?</div><div><br></div><div>If it's carving up compute power, what's actually being carved up? Time? Execution units/waves/threads? Even if that's the case, what advantage does it give to have it in terms of a fixed set of lgpus where each cgroup gets to pick a fixed set. Does affinity matter that much? Why not just say how many waves the GPU supports and that they have to be allocated in chunks of 16 waves (pulling a number out of thin air) and let the cgroup specify how many waves it wants.</div><div><br></div><div>Don't get me wrong here. I'm all for the notion of being able to use cgroups to carve up GPU compute resources. However, this sounds to me like the most AMD-specific solution possible. We (Intel) could probably do some sort of carving up as well but we'd likely want to do it with preemption and time-slicing rather than handing out specific EUs.</div><div><br></div><div>--Jason</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Feb 14, 2020 at 9:57 AM Kenny Ho <<a href="mailto:Kenny.Ho@amd.com">Kenny.Ho@amd.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">drm.lgpu<br>
A read-write nested-keyed file which exists on all cgroups.<br>
Each entry is keyed by the DRM device's major:minor.<br>
<br>
lgpu stands for logical GPU, it is an abstraction used to<br>
subdivide a physical DRM device for the purpose of resource<br>
management. This file stores user configuration while the<br>
drm.lgpu.effective reflects the actual allocation after<br>
considering the relationship between the cgroups and their<br>
configurations.<br>
<br>
The lgpu is a discrete quantity that is device specific (i.e.<br>
some DRM devices may have 64 lgpus while others may have 100<br>
lgpus.) The lgpu is a single quantity that can be allocated<br>
in three different ways denoted by the following nested keys.<br>
<br>
===== ==============================================<br>
weight Allocate by proportion in relationship with<br>
active sibling cgroups<br>
count Allocate by amount statically, treat lgpu as<br>
anonymous resources<br>
list Allocate statically, treat lgpu as named<br>
resource<br>
===== ==============================================<br>
<br>
For example:<br>
226:0 weight=100 count=256 list=0-255<br>
226:1 weight=100 count=4 list=0,2,4,6<br>
226:2 weight=100 count=32 list=32-63<br>
226:3 weight=100 count=0 list=<br>
226:4 weight=500 count=0 list=<br>
<br>
lgpu is represented by a bitmap and uses the bitmap_parselist<br>
kernel function so the list key input format is a<br>
comma-separated list of decimal numbers and ranges.<br>
<br>
Consecutively set bits are shown as two hyphen-separated decimal<br>
numbers, the smallest and largest bit numbers set in the range.<br>
Optionally each range can be postfixed to denote that only parts<br>
of it should be set. The range will divided to groups of<br>
specific size.<br>
Syntax: range:used_size/group_size<br>
Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769<br>
<br>
The count key is the hamming weight / hweight of the bitmap.<br>
<br>
Weight, count and list accept the max and default keywords.<br>
<br>
Some DRM devices may only support lgpu as anonymous resources.<br>
In such case, the significance of the position of the set bits<br>
in list will be ignored.<br>
<br>
The weight quantity is only in effect when static allocation<br>
is not used (by setting count=0) for this cgroup. The weight<br>
quantity distributes lgpus that are not statically allocated by<br>
the siblings. For example, given siblings cgroupA, cgroupB and<br>
cgroupC for a DRM device that has 64 lgpus, if cgroupA occupies<br>
0-63, no lgpu is available to be distributed by weight.<br>
Similarly, if cgroupA has list=0-31 and cgroupB has list=16-63,<br>
cgroupC will be starved if it tries to allocate by weight.<br>
<br>
On the other hand, if cgroupA has weight=100 count=0, cgroupB<br>
has list=16-47, and cgroupC has weight=100 count=0, then 32<br>
lgpus are available to be distributed evenly between cgroupA<br>
and cgroupC. In drm.lgpu.effective, cgroupA will have<br>
list=0-15 and cgroupC will have list=48-63.<br>
<br>
This lgpu resource supports the 'allocation' and 'weight'<br>
resource distribution model.<br>
<br>
drm.lgpu.effective<br>
A read-only nested-keyed file which exists on all cgroups.<br>
Each entry is keyed by the DRM device's major:minor.<br>
<br>
lgpu stands for logical GPU, it is an abstraction used to<br>
subdivide a physical DRM device for the purpose of resource<br>
management. This file reflects the actual allocation after<br>
considering the relationship between the cgroups and their<br>
configurations in drm.lgpu.<br>
<br>
Change-Id: Idde0ef9a331fd67bb9c7eb8ef9978439e6452488<br>
Signed-off-by: Kenny Ho <<a href="mailto:Kenny.Ho@amd.com" target="_blank">Kenny.Ho@amd.com</a>><br>
---<br>
Documentation/admin-guide/cgroup-v2.rst | 80 ++++++<br>
include/drm/drm_cgroup.h | 3 +<br>
include/linux/cgroup_drm.h | 22 ++<br>
kernel/cgroup/drm.c | 324 +++++++++++++++++++++++-<br>
4 files changed, 427 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst<br>
index ce5dc027366a..d8a41956e5c7 100644<br>
--- a/Documentation/admin-guide/cgroup-v2.rst<br>
+++ b/Documentation/admin-guide/cgroup-v2.rst<br>
@@ -2120,6 +2120,86 @@ DRM Interface Files<br>
Set largest allocation for /dev/dri/card1 to 4MB<br>
echo "226:1 4m" > drm.buffer.peak.max<br>
<br>
+ drm.lgpu<br>
+ A read-write nested-keyed file which exists on all cgroups.<br>
+ Each entry is keyed by the DRM device's major:minor.<br>
+<br>
+ lgpu stands for logical GPU, it is an abstraction used to<br>
+ subdivide a physical DRM device for the purpose of resource<br>
+ management. This file stores user configuration while the<br>
+ drm.lgpu.effective reflects the actual allocation after<br>
+ considering the relationship between the cgroups and their<br>
+ configurations.<br>
+<br>
+ The lgpu is a discrete quantity that is device specific (i.e.<br>
+ some DRM devices may have 64 lgpus while others may have 100<br>
+ lgpus.) The lgpu is a single quantity that can be allocated<br>
+ in three different ways denoted by the following nested keys.<br>
+<br>
+ ===== ==============================================<br>
+ weight Allocate by proportion in relationship with<br>
+ active sibling cgroups<br>
+ count Allocate by amount statically, treat lgpu as<br>
+ anonymous resources<br>
+ list Allocate statically, treat lgpu as named<br>
+ resource<br>
+ ===== ==============================================<br>
+<br>
+ For example:<br>
+ 226:0 weight=100 count=256 list=0-255<br>
+ 226:1 weight=100 count=4 list=0,2,4,6<br>
+ 226:2 weight=100 count=32 list=32-63<br>
+ 226:3 weight=100 count=0 list=<br>
+ 226:4 weight=500 count=0 list=<br>
+<br>
+ lgpu is represented by a bitmap and uses the bitmap_parselist<br>
+ kernel function so the list key input format is a<br>
+ comma-separated list of decimal numbers and ranges.<br>
+<br>
+ Consecutively set bits are shown as two hyphen-separated decimal<br>
+ numbers, the smallest and largest bit numbers set in the range.<br>
+ Optionally each range can be postfixed to denote that only parts<br>
+ of it should be set. The range will divided to groups of<br>
+ specific size.<br>
+ Syntax: range:used_size/group_size<br>
+ Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769<br>
+<br>
+ The count key is the hamming weight / hweight of the bitmap.<br>
+<br>
+ Weight, count and list accept the max and default keywords.<br>
+<br>
+ Some DRM devices may only support lgpu as anonymous resources.<br>
+ In such case, the significance of the position of the set bits<br>
+ in list will be ignored.<br>
+<br>
+ The weight quantity is only in effect when static allocation<br>
+ is not used (by setting count=0) for this cgroup. The weight<br>
+ quantity distributes lgpus that are not statically allocated by<br>
+ the siblings. For example, given siblings cgroupA, cgroupB and<br>
+ cgroupC for a DRM device that has 64 lgpus, if cgroupA occupies<br>
+ 0-63, no lgpu is available to be distributed by weight.<br>
+ Similarly, if cgroupA has list=0-31 and cgroupB has list=16-63,<br>
+ cgroupC will be starved if it tries to allocate by weight.<br>
+<br>
+ On the other hand, if cgroupA has weight=100 count=0, cgroupB<br>
+ has list=16-47, and cgroupC has weight=100 count=0, then 32<br>
+ lgpus are available to be distributed evenly between cgroupA<br>
+ and cgroupC. In drm.lgpu.effective, cgroupA will have<br>
+ list=0-15 and cgroupC will have list=48-63.<br>
+<br>
+ This lgpu resource supports the 'allocation' and 'weight'<br>
+ resource distribution model.<br>
+<br>
+ drm.lgpu.effective<br>
+ A read-only nested-keyed file which exists on all cgroups.<br>
+ Each entry is keyed by the DRM device's major:minor.<br>
+<br>
+ lgpu stands for logical GPU, it is an abstraction used to<br>
+ subdivide a physical DRM device for the purpose of resource<br>
+ management. This file reflects the actual allocation after<br>
+ considering the relationship between the cgroups and their<br>
+ configurations in drm.lgpu.<br>
+<br>
GEM Buffer Ownership<br>
~~~~~~~~~~~~~~~~~~~~<br>
<br>
diff --git a/include/drm/drm_cgroup.h b/include/drm/drm_cgroup.h<br>
index 2b41d4d22e33..619a110cc748 100644<br>
--- a/include/drm/drm_cgroup.h<br>
+++ b/include/drm/drm_cgroup.h<br>
@@ -17,6 +17,9 @@ struct drmcg_props {<br>
<br>
s64 bo_limits_total_allocated_default;<br>
s64 bo_limits_peak_allocated_default;<br>
+<br>
+ int lgpu_capacity;<br>
+ DECLARE_BITMAP(lgpu_slots, MAX_DRMCG_LGPU_CAPACITY);<br>
};<br>
<br>
void drmcg_bind(struct drm_minor (*(*acq_dm)(unsigned int minor_id)),<br>
diff --git a/include/linux/cgroup_drm.h b/include/linux/cgroup_drm.h<br>
index eae400f3d9b4..bb09704e7f71 100644<br>
--- a/include/linux/cgroup_drm.h<br>
+++ b/include/linux/cgroup_drm.h<br>
@@ -11,10 +11,14 @@<br>
/* limit defined per the way drm_minor_alloc operates */<br>
#define MAX_DRM_DEV (64 * DRM_MINOR_RENDER)<br>
<br>
+#define MAX_DRMCG_LGPU_CAPACITY 256<br>
+<br>
enum drmcg_res_type {<br>
DRMCG_TYPE_BO_TOTAL,<br>
DRMCG_TYPE_BO_PEAK,<br>
DRMCG_TYPE_BO_COUNT,<br>
+ DRMCG_TYPE_LGPU,<br>
+ DRMCG_TYPE_LGPU_EFF,<br>
__DRMCG_TYPE_LAST,<br>
};<br>
<br>
@@ -32,6 +36,24 @@ struct drmcg_device_resource {<br>
s64 bo_limits_peak_allocated;<br>
<br>
s64 bo_stats_count_allocated;<br>
+<br>
+ /**<br>
+ * Logical GPU<br>
+ *<br>
+ * *_cfg are properties configured by users<br>
+ * *_eff are the effective properties being applied to the hardware<br>
+ * *_stg is used to calculate _eff before applying to _eff<br>
+ * after considering the entire hierarchy<br>
+ */<br>
+ DECLARE_BITMAP(lgpu_stg, MAX_DRMCG_LGPU_CAPACITY);<br>
+ /* user configurations */<br>
+ s64 lgpu_weight_cfg;<br>
+ DECLARE_BITMAP(lgpu_cfg, MAX_DRMCG_LGPU_CAPACITY);<br>
+ /* effective lgpu for the cgroup after considering<br>
+ * relationship with other cgroup<br>
+ */<br>
+ s64 lgpu_count_eff;<br>
+ DECLARE_BITMAP(lgpu_eff, MAX_DRMCG_LGPU_CAPACITY);<br>
};<br>
<br>
/**<br>
diff --git a/kernel/cgroup/drm.c b/kernel/cgroup/drm.c<br>
index 5fcbbc13fa1c..a4e88a3704bb 100644<br>
--- a/kernel/cgroup/drm.c<br>
+++ b/kernel/cgroup/drm.c<br>
@@ -9,6 +9,7 @@<br>
#include <linux/seq_file.h><br>
#include <linux/mutex.h><br>
#include <linux/kernel.h><br>
+#include <linux/bitmap.h><br>
#include <linux/cgroup_drm.h><br>
#include <drm/drm_file.h><br>
#include <drm/drm_drv.h><br>
@@ -41,6 +42,10 @@ enum drmcg_file_type {<br>
DRMCG_FTYPE_DEFAULT,<br>
};<br>
<br>
+#define LGPU_LIMITS_NAME_LIST "list"<br>
+#define LGPU_LIMITS_NAME_COUNT "count"<br>
+#define LGPU_LIMITS_NAME_WEIGHT "weight"<br>
+<br>
/**<br>
* drmcg_bind - Bind DRM subsystem to cgroup subsystem<br>
* @acq_dm: function pointer to the drm_minor_acquire function<br>
@@ -98,6 +103,13 @@ static inline int init_drmcg_single(struct drmcg *drmcg, struct drm_device *dev)<br>
ddr->bo_limits_peak_allocated =<br>
dev->drmcg_props.bo_limits_peak_allocated_default;<br>
<br>
+ bitmap_copy(ddr->lgpu_cfg, dev->drmcg_props.lgpu_slots,<br>
+ MAX_DRMCG_LGPU_CAPACITY);<br>
+ bitmap_copy(ddr->lgpu_stg, dev->drmcg_props.lgpu_slots,<br>
+ MAX_DRMCG_LGPU_CAPACITY);<br>
+<br>
+ ddr->lgpu_weight_cfg = CGROUP_WEIGHT_DFL;<br>
+<br>
return 0;<br>
}<br>
<br>
@@ -121,6 +133,120 @@ static inline void drmcg_update_cg_tree(struct drm_device *dev)<br>
mutex_unlock(&cgroup_mutex);<br>
}<br>
<br>
+static void drmcg_calculate_effective_lgpu(struct drm_device *dev,<br>
+ const unsigned long *free_static,<br>
+ const unsigned long *free_weighted,<br>
+ struct drmcg *parent_drmcg)<br>
+{<br>
+ int capacity = dev->drmcg_props.lgpu_capacity;<br>
+ DECLARE_BITMAP(lgpu_unused, MAX_DRMCG_LGPU_CAPACITY);<br>
+ DECLARE_BITMAP(lgpu_by_weight, MAX_DRMCG_LGPU_CAPACITY);<br>
+ struct drmcg_device_resource *parent_ddr;<br>
+ struct drmcg_device_resource *ddr;<br>
+ int minor = dev->primary->index;<br>
+ struct cgroup_subsys_state *pos;<br>
+ struct drmcg *child;<br>
+ s64 weight_sum = 0;<br>
+ s64 unused;<br>
+<br>
+ parent_ddr = parent_drmcg->dev_resources[minor];<br>
+<br>
+ if (bitmap_empty(parent_ddr->lgpu_cfg, capacity))<br>
+ /* no static cfg, use weight for calculating the effective */<br>
+ bitmap_copy(parent_ddr->lgpu_stg, free_weighted, capacity);<br>
+ else<br>
+ /* lgpu statically configured, use the overlap as effective */<br>
+ bitmap_and(parent_ddr->lgpu_stg, free_static,<br>
+ parent_ddr->lgpu_cfg, capacity);<br>
+<br>
+ /* calculate lgpu available for distribution by weight for children */<br>
+ bitmap_copy(lgpu_unused, parent_ddr->lgpu_stg, capacity);<br>
+ css_for_each_child(pos, &parent_drmcg->css) {<br>
+ child = css_to_drmcg(pos);<br>
+ ddr = child->dev_resources[minor];<br>
+<br>
+ if (bitmap_empty(ddr->lgpu_cfg, capacity))<br>
+ /* no static allocation, participate in weight dist */<br>
+ weight_sum += ddr->lgpu_weight_cfg;<br>
+ else<br>
+ /* take out statically allocated lgpu by siblings */<br>
+ bitmap_andnot(lgpu_unused, lgpu_unused, ddr->lgpu_cfg,<br>
+ capacity);<br>
+ }<br>
+<br>
+ unused = bitmap_weight(lgpu_unused, capacity);<br>
+<br>
+ css_for_each_child(pos, &parent_drmcg->css) {<br>
+ child = css_to_drmcg(pos);<br>
+ ddr = child->dev_resources[minor];<br>
+<br>
+ bitmap_zero(lgpu_by_weight, capacity);<br>
+ /* no static allocation, participate in weight distribution */<br>
+ if (bitmap_empty(ddr->lgpu_cfg, capacity)) {<br>
+ int c;<br>
+ int p = 0;<br>
+<br>
+ for (c = ddr->lgpu_weight_cfg * unused / weight_sum;<br>
+ c > 0; c--) {<br>
+ p = find_next_bit(lgpu_unused, capacity, p);<br>
+ if (p < capacity) {<br>
+ clear_bit(p, lgpu_unused);<br>
+ set_bit(p, lgpu_by_weight);<br>
+ }<br>
+ }<br>
+<br>
+ }<br>
+<br>
+ drmcg_calculate_effective_lgpu(dev, parent_ddr->lgpu_stg,<br>
+ lgpu_by_weight, child);<br>
+ }<br>
+}<br>
+<br>
+static void drmcg_apply_effective_lgpu(struct drm_device *dev)<br>
+{<br>
+ int capacity = dev->drmcg_props.lgpu_capacity;<br>
+ int minor = dev->primary->index;<br>
+ struct drmcg_device_resource *ddr;<br>
+ struct cgroup_subsys_state *pos;<br>
+ struct drmcg *drmcg;<br>
+<br>
+ if (root_drmcg == NULL) {<br>
+ WARN_ON(root_drmcg == NULL);<br>
+ return;<br>
+ }<br>
+<br>
+ rcu_read_lock();<br>
+<br>
+ /* process the entire cgroup tree from root to simplify the algorithm */<br>
+ drmcg_calculate_effective_lgpu(dev, dev->drmcg_props.lgpu_slots,<br>
+ dev->drmcg_props.lgpu_slots, root_drmcg);<br>
+<br>
+ /* apply changes to effective only if there is a change */<br>
+ css_for_each_descendant_pre(pos, &root_drmcg->css) {<br>
+ drmcg = css_to_drmcg(pos);<br>
+ ddr = drmcg->dev_resources[minor];<br>
+<br>
+ if (!bitmap_equal(ddr->lgpu_stg, ddr->lgpu_eff, capacity)) {<br>
+ bitmap_copy(ddr->lgpu_eff, ddr->lgpu_stg, capacity);<br>
+ ddr->lgpu_count_eff =<br>
+ bitmap_weight(ddr->lgpu_eff, capacity);<br>
+ }<br>
+ }<br>
+ rcu_read_unlock();<br>
+}<br>
+<br>
+static void drmcg_apply_effective(enum drmcg_res_type type,<br>
+ struct drm_device *dev, struct drmcg *changed_drmcg)<br>
+{<br>
+ switch (type) {<br>
+ case DRMCG_TYPE_LGPU:<br>
+ drmcg_apply_effective_lgpu(dev);<br>
+ break;<br>
+ default:<br>
+ break;<br>
+ }<br>
+}<br>
+<br>
/**<br>
* drmcg_register_dev - register a DRM device for usage in drm cgroup<br>
* @dev: DRM device<br>
@@ -143,7 +269,13 @@ void drmcg_register_dev(struct drm_device *dev)<br>
{<br>
dev->driver->drmcg_custom_init(dev, &dev->drmcg_props);<br>
<br>
+ WARN_ON(dev->drmcg_props.lgpu_capacity !=<br>
+ bitmap_weight(dev->drmcg_props.lgpu_slots,<br>
+ MAX_DRMCG_LGPU_CAPACITY));<br>
+<br>
drmcg_update_cg_tree(dev);<br>
+<br>
+ drmcg_apply_effective(DRMCG_TYPE_LGPU, dev, root_drmcg);<br>
}<br>
mutex_unlock(&drmcg_mutex);<br>
}<br>
@@ -297,7 +429,8 @@ static void drmcg_print_stats(struct drmcg_device_resource *ddr,<br>
}<br>
<br>
static void drmcg_print_limits(struct drmcg_device_resource *ddr,<br>
- struct seq_file *sf, enum drmcg_res_type type)<br>
+ struct seq_file *sf, enum drmcg_res_type type,<br>
+ struct drm_device *dev)<br>
{<br>
if (ddr == NULL) {<br>
seq_puts(sf, "\n");<br>
@@ -311,6 +444,25 @@ static void drmcg_print_limits(struct drmcg_device_resource *ddr,<br>
case DRMCG_TYPE_BO_PEAK:<br>
seq_printf(sf, "%lld\n", ddr->bo_limits_peak_allocated);<br>
break;<br>
+ case DRMCG_TYPE_LGPU:<br>
+ seq_printf(sf, "%s=%lld %s=%d %s=%*pbl\n",<br>
+ LGPU_LIMITS_NAME_WEIGHT,<br>
+ ddr->lgpu_weight_cfg,<br>
+ LGPU_LIMITS_NAME_COUNT,<br>
+ bitmap_weight(ddr->lgpu_cfg,<br>
+ dev->drmcg_props.lgpu_capacity),<br>
+ LGPU_LIMITS_NAME_LIST,<br>
+ dev->drmcg_props.lgpu_capacity,<br>
+ ddr->lgpu_cfg);<br>
+ break;<br>
+ case DRMCG_TYPE_LGPU_EFF:<br>
+ seq_printf(sf, "%s=%lld %s=%*pbl\n",<br>
+ LGPU_LIMITS_NAME_COUNT,<br>
+ ddr->lgpu_count_eff,<br>
+ LGPU_LIMITS_NAME_LIST,<br>
+ dev->drmcg_props.lgpu_capacity,<br>
+ ddr->lgpu_eff);<br>
+ break;<br>
default:<br>
seq_puts(sf, "\n");<br>
break;<br>
@@ -329,6 +481,17 @@ static void drmcg_print_default(struct drmcg_props *props,<br>
seq_printf(sf, "%lld\n",<br>
props->bo_limits_peak_allocated_default);<br>
break;<br>
+ case DRMCG_TYPE_LGPU:<br>
+ seq_printf(sf, "%s=%d %s=%d %s=%*pbl\n",<br>
+ LGPU_LIMITS_NAME_WEIGHT,<br>
+ CGROUP_WEIGHT_DFL,<br>
+ LGPU_LIMITS_NAME_COUNT,<br>
+ bitmap_weight(props->lgpu_slots,<br>
+ props->lgpu_capacity),<br>
+ LGPU_LIMITS_NAME_LIST,<br>
+ props->lgpu_capacity,<br>
+ props->lgpu_slots);<br>
+ break;<br>
default:<br>
seq_puts(sf, "\n");<br>
break;<br>
@@ -358,7 +521,7 @@ static int drmcg_seq_show_fn(int id, void *ptr, void *data)<br>
drmcg_print_stats(ddr, sf, type);<br>
break;<br>
case DRMCG_FTYPE_LIMIT:<br>
- drmcg_print_limits(ddr, sf, type);<br>
+ drmcg_print_limits(ddr, sf, type, minor->dev);<br>
break;<br>
case DRMCG_FTYPE_DEFAULT:<br>
drmcg_print_default(&minor->dev->drmcg_props, sf, type);<br>
@@ -415,6 +578,115 @@ static int drmcg_process_limit_s64_val(char *sval, bool is_mem,<br>
return rc;<br>
}<br>
<br>
+static void drmcg_nested_limit_parse(struct kernfs_open_file *of,<br>
+ struct drm_device *dev, char *attrs)<br>
+{<br>
+ DECLARE_BITMAP(tmp_bitmap, MAX_DRMCG_LGPU_CAPACITY);<br>
+ DECLARE_BITMAP(chk_bitmap, MAX_DRMCG_LGPU_CAPACITY);<br>
+ enum drmcg_res_type type =<br>
+ DRMCG_CTF_PRIV2RESTYPE(of_cft(of)->private);<br>
+ struct drmcg *drmcg = css_to_drmcg(of_css(of));<br>
+ struct drmcg_props *props = &dev->drmcg_props;<br>
+ char *cft_name = of_cft(of)->name;<br>
+ int minor = dev->primary->index;<br>
+ char *nested = strstrip(attrs);<br>
+ struct drmcg_device_resource *ddr =<br>
+ drmcg->dev_resources[minor];<br>
+ char *attr;<br>
+ char sname[256];<br>
+ char sval[256];<br>
+ s64 val;<br>
+ int rc;<br>
+<br>
+ while (nested != NULL) {<br>
+ attr = strsep(&nested, " ");<br>
+<br>
+ if (sscanf(attr, "%255[^=]=%255[^=]", sname, sval) != 2)<br>
+ continue;<br>
+<br>
+ switch (type) {<br>
+ case DRMCG_TYPE_LGPU:<br>
+ if (strncmp(sname, LGPU_LIMITS_NAME_LIST, 256) &&<br>
+ strncmp(sname, LGPU_LIMITS_NAME_COUNT, 256) &&<br>
+ strncmp(sname, LGPU_LIMITS_NAME_WEIGHT, 256))<br>
+ continue;<br>
+<br>
+ if (strncmp(sname, LGPU_LIMITS_NAME_WEIGHT, 256) &&<br>
+ (!strcmp("max", sval) ||<br>
+ !strcmp("default", sval))) {<br>
+ bitmap_copy(ddr->lgpu_cfg, props->lgpu_slots,<br>
+ props->lgpu_capacity);<br>
+<br>
+ continue;<br>
+ }<br>
+<br>
+ if (strncmp(sname, LGPU_LIMITS_NAME_WEIGHT, 256) == 0) {<br>
+ rc = drmcg_process_limit_s64_val(sval,<br>
+ false, CGROUP_WEIGHT_DFL,<br>
+ CGROUP_WEIGHT_MAX, &val);<br>
+<br>
+ if (rc || val < CGROUP_WEIGHT_MIN ||<br>
+ val > CGROUP_WEIGHT_MAX) {<br>
+ drmcg_pr_cft_err(drmcg, rc, cft_name,<br>
+ minor);<br>
+ continue;<br>
+ }<br>
+<br>
+ ddr->lgpu_weight_cfg = val;<br>
+ continue;<br>
+ }<br>
+<br>
+ if (strncmp(sname, LGPU_LIMITS_NAME_COUNT, 256) == 0) {<br>
+ rc = drmcg_process_limit_s64_val(sval,<br>
+ false, props->lgpu_capacity,<br>
+ props->lgpu_capacity, &val);<br>
+<br>
+ if (rc || val < 0) {<br>
+ drmcg_pr_cft_err(drmcg, rc, cft_name,<br>
+ minor);<br>
+ continue;<br>
+ }<br>
+<br>
+ bitmap_zero(tmp_bitmap,<br>
+ MAX_DRMCG_LGPU_CAPACITY);<br>
+ bitmap_set(tmp_bitmap, 0, val);<br>
+ }<br>
+<br>
+ if (strncmp(sname, LGPU_LIMITS_NAME_LIST, 256) == 0) {<br>
+ rc = bitmap_parselist(sval, tmp_bitmap,<br>
+ MAX_DRMCG_LGPU_CAPACITY);<br>
+<br>
+ if (rc) {<br>
+ drmcg_pr_cft_err(drmcg, rc, cft_name,<br>
+ minor);<br>
+ continue;<br>
+ }<br>
+<br>
+ bitmap_andnot(chk_bitmap, tmp_bitmap,<br>
+ props->lgpu_slots,<br>
+ MAX_DRMCG_LGPU_CAPACITY);<br>
+<br>
+ /* user setting does not intersect with<br>
+ * available lgpu */<br>
+ if (!bitmap_empty(chk_bitmap,<br>
+ MAX_DRMCG_LGPU_CAPACITY)) {<br>
+ drmcg_pr_cft_err(drmcg, 0, cft_name,<br>
+ minor);<br>
+ continue;<br>
+ }<br>
+ }<br>
+<br>
+ bitmap_copy(ddr->lgpu_cfg, tmp_bitmap,<br>
+ props->lgpu_capacity);<br>
+<br>
+ break; /* DRMCG_TYPE_LGPU */<br>
+ default:<br>
+ break;<br>
+ } /* switch (type) */<br>
+ }<br>
+}<br>
+<br>
+<br>
/**<br>
* drmcg_limit_write - parse cgroup interface files to obtain user config<br>
*<br>
@@ -499,9 +771,15 @@ static ssize_t drmcg_limit_write(struct kernfs_open_file *of, char *buf,<br>
<br>
ddr->bo_limits_peak_allocated = val;<br>
break;<br>
+ case DRMCG_TYPE_LGPU:<br>
+ drmcg_nested_limit_parse(of, dm->dev, sattr);<br>
+ break;<br>
default:<br>
break;<br>
}<br>
+<br>
+ drmcg_apply_effective(type, dm->dev, drmcg);<br>
+<br>
mutex_unlock(&dm->dev->drmcg_mutex);<br>
<br>
mutex_lock(&drmcg_mutex);<br>
@@ -560,12 +838,51 @@ struct cftype files[] = {<br>
.private = DRMCG_CTF_PRIV(DRMCG_TYPE_BO_COUNT,<br>
DRMCG_FTYPE_STATS),<br>
},<br>
+ {<br>
+ .name = "lgpu",<br>
+ .seq_show = drmcg_seq_show,<br>
+ .write = drmcg_limit_write,<br>
+ .private = DRMCG_CTF_PRIV(DRMCG_TYPE_LGPU,<br>
+ DRMCG_FTYPE_LIMIT),<br>
+ },<br>
+ {<br>
+ .name = "lgpu.default",<br>
+ .seq_show = drmcg_seq_show,<br>
+ .flags = CFTYPE_ONLY_ON_ROOT,<br>
+ .private = DRMCG_CTF_PRIV(DRMCG_TYPE_LGPU,<br>
+ DRMCG_FTYPE_DEFAULT),<br>
+ },<br>
+ {<br>
+ .name = "lgpu.effective",<br>
+ .seq_show = drmcg_seq_show,<br>
+ .private = DRMCG_CTF_PRIV(DRMCG_TYPE_LGPU_EFF,<br>
+ DRMCG_FTYPE_LIMIT),<br>
+ },<br>
{ } /* terminate */<br>
};<br>
<br>
+static int drmcg_online_fn(int id, void *ptr, void *data)<br>
+{<br>
+ struct drm_minor *minor = ptr;<br>
+ struct drmcg *drmcg = data;<br>
+<br>
+ if (minor->type != DRM_MINOR_PRIMARY)<br>
+ return 0;<br>
+<br>
+ drmcg_apply_effective(DRMCG_TYPE_LGPU, minor->dev, drmcg);<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int drmcg_css_online(struct cgroup_subsys_state *css)<br>
+{<br>
+ return drm_minor_for_each(&drmcg_online_fn, css_to_drmcg(css));<br>
+}<br>
+<br>
struct cgroup_subsys drm_cgrp_subsys = {<br>
.css_alloc = drmcg_css_alloc,<br>
.css_free = drmcg_css_free,<br>
+ .css_online = drmcg_css_online,<br>
.early_init = false,<br>
.legacy_cftypes = files,<br>
.dfl_cftypes = files,<br>
@@ -585,6 +902,9 @@ void drmcg_device_early_init(struct drm_device *dev)<br>
dev->drmcg_props.bo_limits_total_allocated_default = S64_MAX;<br>
dev->drmcg_props.bo_limits_peak_allocated_default = S64_MAX;<br>
<br>
+ dev->drmcg_props.lgpu_capacity = MAX_DRMCG_LGPU_CAPACITY;<br>
+ bitmap_fill(dev->drmcg_props.lgpu_slots, MAX_DRMCG_LGPU_CAPACITY);<br>
+<br>
drmcg_update_cg_tree(dev);<br>
}<br>
EXPORT_SYMBOL(drmcg_device_early_init);<br>
-- <br>
2.25.0<br>
<br>
_______________________________________________<br>
dri-devel mailing list<br>
<a href="mailto:dri-devel@lists.freedesktop.org" target="_blank">dri-devel@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/dri-devel" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/dri-devel</a><br>
</blockquote></div>