[PATCH 1/5] drm/i915/sseu: Don't try to store EU mask internally in UAPI format
Matt Roper
matthew.d.roper at intel.com
Tue Apr 26 23:24:16 UTC 2022
Storing the EU mask internally in the same format the I915_QUERY
topology queries use makes the final copy_to_user() a bit simpler, but
makes the rest of the driver's SSEU more complicated. Given that modern
platforms (gen11 and beyond) are architecturally guaranteed to have
equivalent EU masks for every subslice, it also wastes quite a bit of
space since we really only need to store the value for a single subslice
(i.e., one u16).
Let's add a has_common_ss_eumask flag to the SSEU structure to determine
which type of hardware we're working on. For the older pre-gen11
platforms the various subslices can have different EU masks so we need
to store a full-device mask, but each subslice can only have at most
eight EUs, so a simple array of u8[] (without worrying about eu_stride
internally) is sufficient. For gen11 and beyond we can just use an even
simpler u16. Only when it comes time to copy the SSEU information to
userspace for the query ioctl do we need to expand out the internal
representation.
Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
---
drivers/gpu/drm/i915/gt/intel_sseu.c | 69 ++++++++++++++++++++--------
drivers/gpu/drm/i915/gt/intel_sseu.h | 27 ++++++++++-
drivers/gpu/drm/i915/i915_query.c | 8 ++--
3 files changed, 80 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c
index 9881a6790574..922677208e9c 100644
--- a/drivers/gpu/drm/i915/gt/intel_sseu.c
+++ b/drivers/gpu/drm/i915/gt/intel_sseu.c
@@ -91,36 +91,69 @@ static int sseu_eu_idx(const struct sseu_dev_info *sseu, int slice,
static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,
int subslice)
{
- int i, offset = sseu_eu_idx(sseu, slice, subslice);
- u16 eu_mask = 0;
-
- for (i = 0; i < sseu->eu_stride; i++)
- eu_mask |=
- ((u16)sseu->eu_mask[offset + i]) << (i * BITS_PER_BYTE);
+ if (!intel_sseu_has_subslice(sseu, slice, subslice))
+ return 0;
- return eu_mask;
+ if (sseu->has_common_ss_eumask)
+ return sseu->eu_mask_per_ss;
+ else
+ return sseu->dev_eu_mask[slice * sseu->max_subslices + subslice];
}
static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,
- u16 eu_mask)
+ u8 eu_mask)
{
- int i, offset = sseu_eu_idx(sseu, slice, subslice);
+ WARN_ON(sseu->has_common_ss_eumask);
+ WARN_ON(sseu->max_eus_per_subslice > 8);
- for (i = 0; i < sseu->eu_stride; i++)
- sseu->eu_mask[offset + i] =
- (eu_mask >> (BITS_PER_BYTE * i)) & 0xff;
+ sseu->dev_eu_mask[slice * sseu->max_subslices + subslice] = eu_mask;
}
static u16 compute_eu_total(const struct sseu_dev_info *sseu)
{
u16 i, total = 0;
- for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++)
- total += hweight8(sseu->eu_mask[i]);
+ if (sseu->has_common_ss_eumask)
+ return intel_sseu_subslices_per_slice(sseu, 0) *
+ hweight16(sseu->eu_mask_per_ss);
+
+ for (i = 0; i < ARRAY_SIZE(sseu->dev_eu_mask); i++)
+ total += hweight8(sseu->dev_eu_mask[i]);
return total;
}
+/**
+ * intel_sseu_copy_eumask_to_user - Copy EU mask into a userspace buffer
+ * @to: Pointer to userspace buffer to copy to
+ * @sseu: SSEU structure containing EU mask to copy
+ *
+ * Copies the EU mask to a userspace buffer in the format expected by
+ * the query ioctl's topology queries.
+ *
+ * Returns the result of the copy_to_user() operation.
+ */
+int intel_sseu_copy_eumask_to_user(void __user *to,
+ const struct sseu_dev_info *sseu)
+{
+ u8 eu_mask[GEN_SS_MASK_SIZE * GEN_MAX_EU_STRIDE] = {};
+ int len = sseu->max_slices * sseu->max_subslices * sseu->eu_stride;
+ int s, ss, i;
+
+ for (s = 0; s < sseu->max_slices; s++) {
+ for (ss = 0; ss < sseu->max_subslices; ss++) {
+ int offset = sseu_eu_idx(sseu, s, ss);
+ u16 mask = sseu_get_eus(sseu, s, ss);
+
+ for (i = 0; i < sseu->eu_stride; i++)
+ eu_mask[offset + i] =
+ (mask >> (BITS_PER_BYTE * i)) & 0xff;
+ }
+ }
+
+ return copy_to_user(to, eu_mask, len);
+}
+
static u32 get_ss_stride_mask(struct sseu_dev_info *sseu, u8 s, u32 ss_en)
{
u32 ss_mask;
@@ -134,7 +167,7 @@ static u32 get_ss_stride_mask(struct sseu_dev_info *sseu, u8 s, u32 ss_en)
static void gen11_compute_sseu_info(struct sseu_dev_info *sseu, u8 s_en,
u32 g_ss_en, u32 c_ss_en, u16 eu_en)
{
- int s, ss;
+ int s;
/* g_ss_en/c_ss_en represent entire subslice mask across all slices */
GEM_BUG_ON(sseu->max_slices * sseu->max_subslices >
@@ -162,11 +195,9 @@ static void gen11_compute_sseu_info(struct sseu_dev_info *sseu, u8 s_en,
intel_sseu_set_subslices(sseu, s, sseu->subslice_mask,
get_ss_stride_mask(sseu, s,
g_ss_en | c_ss_en));
-
- for (ss = 0; ss < sseu->max_subslices; ss++)
- if (intel_sseu_has_subslice(sseu, s, ss))
- sseu_set_eus(sseu, s, ss, eu_en);
}
+ sseu->has_common_ss_eumask = 1;
+ sseu->eu_mask_per_ss = eu_en;
sseu->eu_per_subslice = hweight16(eu_en);
sseu->eu_total = compute_eu_total(sseu);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.h b/drivers/gpu/drm/i915/gt/intel_sseu.h
index 5c078df4729c..23ab38e5e315 100644
--- a/drivers/gpu/drm/i915/gt/intel_sseu.h
+++ b/drivers/gpu/drm/i915/gt/intel_sseu.h
@@ -57,7 +57,27 @@ struct sseu_dev_info {
u8 subslice_mask[GEN_SS_MASK_SIZE];
u8 geometry_subslice_mask[GEN_SS_MASK_SIZE];
u8 compute_subslice_mask[GEN_SS_MASK_SIZE];
- u8 eu_mask[GEN_SS_MASK_SIZE * GEN_MAX_EU_STRIDE];
+
+ /*
+ * EU masks. Use has_common_ss_eumask to determine which field in
+ * the union to utilize for a given platform.
+ *
+ * On pre-gen11 platforms, each subslice has independent EU fusing, so
+ * we need to maintain the device-wide set of EUs. Since each subslice
+ * has at most 8 EUs, an array of u8's can represent all of the masks.
+ *
+ * For gen11 and beyond, all subslices will always have the same set of
+ * enabled/disabled EUs so we only need to store the EU mask
+ * associated with a single subslice.
+ */
+ union {
+ /* pre-gen11 */
+ u8 dev_eu_mask[GEN_MAX_HSW_SLICES * GEN_MAX_SS_PER_HSW_SLICE];
+
+ /* gen11 and beyond */
+ u16 eu_mask_per_ss;
+ };
+
u16 eu_total;
u8 eu_per_subslice;
u8 min_eu_in_pool;
@@ -66,6 +86,8 @@ struct sseu_dev_info {
u8 has_slice_pg:1;
u8 has_subslice_pg:1;
u8 has_eu_pg:1;
+ /* All subslices have the same set of enabled/disabled EUs? */
+ u8 has_common_ss_eumask:1;
/* Topology fields */
u8 max_slices;
@@ -145,4 +167,7 @@ void intel_sseu_print_topology(struct drm_i915_private *i915,
u16 intel_slicemask_from_dssmask(u64 dss_mask, int dss_per_slice);
+int intel_sseu_copy_eumask_to_user(void __user *to,
+ const struct sseu_dev_info *sseu);
+
#endif /* __INTEL_SSEU_H__ */
diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c
index 7584cec53d5d..16f43bf32a05 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -76,10 +76,10 @@ static int fill_topology_info(const struct sseu_dev_info *sseu,
subslice_mask, subslice_length))
return -EFAULT;
- if (copy_to_user(u64_to_user_ptr(query_item->data_ptr +
- sizeof(topo) +
- slice_length + subslice_length),
- sseu->eu_mask, eu_length))
+ if (intel_sseu_copy_eumask_to_user(u64_to_user_ptr(query_item->data_ptr +
+ sizeof(topo) +
+ slice_length + subslice_length),
+ sseu))
return -EFAULT;
return total_length;
--
2.35.1
More information about the Intel-gfx-trybot
mailing list