Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/mcr: Try to derive dss_per_grp from hwconfig attributes

When steering MCR register ranges of type "DSS," the group_id and
instance_id values are calculated by dividing the DSS pool according to
the size of a gslice or cslice, depending on the platform. These values
haven't changed much on past platforms, so we've been able to hardcode
the proper divisor so far. However the layout may not be so fixed on
future platforms so the proper, future-proof way to determine this is by
using some of the attributes from the GuC's hwconfig table. The
hwconfig has two attributes reflecting the architectural maximum slice
and subslice counts (i.e., before any fusing is considered) that can be
used for the purposes of calculating MCR steering targets.

If the hwconfig is lacking the necessary values (which should only be
possible on older platforms before these attributes were added), we can
still fall back to the old hardcoded values. Going forward the hwconfig
is expected to always provide the information we need on newer
platforms, and any failure to do so will be considered a bug in the
firmware that will prevent us from switching to the buggy firmware
release.

It's worth noting that over time GuC's hwconfig has provided a couple
different keys with similar-sounding descriptions. For our purposes
here, we only trust the newer key "70" which has supplanted the
similarly-named key "2" that existed on older platforms.

Bspec: 73210
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240815172602.2729146-4-matthew.d.roper@intel.com

+83 -4
+36 -4
drivers/gpu/drm/xe/xe_gt_mcr.c
··· 8 8 #include "regs/xe_gt_regs.h" 9 9 #include "xe_assert.h" 10 10 #include "xe_gt.h" 11 + #include "xe_gt_printk.h" 11 12 #include "xe_gt_topology.h" 12 13 #include "xe_gt_types.h" 14 + #include "xe_guc_hwconfig.h" 13 15 #include "xe_mmio.h" 14 16 #include "xe_sriov.h" 15 17 ··· 299 297 300 298 static unsigned int dss_per_group(struct xe_gt *gt) 301 299 { 300 + struct xe_guc *guc = &gt->uc.guc; 301 + u32 max_slices = 0, max_subslices = 0; 302 + int ret; 303 + 304 + /* 305 + * Try to query the GuC's hwconfig table for the maximum number of 306 + * slices and subslices. These don't reflect the platform's actual 307 + * slice/DSS counts, just the physical layout by which we should 308 + * determine the steering targets. On older platforms with older GuC 309 + * firmware releases it's possible that these attributes may not be 310 + * included in the table, so we can always fall back to the old 311 + * hardcoded layouts. 312 + */ 313 + #define HWCONFIG_ATTR_MAX_SLICES 1 314 + #define HWCONFIG_ATTR_MAX_SUBSLICES 70 315 + 316 + ret = xe_guc_hwconfig_lookup_u32(guc, HWCONFIG_ATTR_MAX_SLICES, 317 + &max_slices); 318 + if (ret < 0 || max_slices == 0) 319 + goto fallback; 320 + 321 + ret = xe_guc_hwconfig_lookup_u32(guc, HWCONFIG_ATTR_MAX_SUBSLICES, 322 + &max_subslices); 323 + if (ret < 0 || max_subslices == 0) 324 + goto fallback; 325 + 326 + return DIV_ROUND_UP(max_subslices, max_slices); 327 + 328 + fallback: 329 + xe_gt_dbg(gt, "GuC hwconfig cannot provide dss/slice; using typical fallback values\n"); 302 330 if (gt_to_xe(gt)->info.platform == XE_PVC) 303 331 return 8; 304 332 else if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1250) ··· 346 314 */ 347 315 void xe_gt_mcr_get_dss_steering(struct xe_gt *gt, unsigned int dss, u16 *group, u16 *instance) 348 316 { 349 - int dss_per_grp = dss_per_group(gt); 350 - 351 317 xe_gt_assert(gt, dss < XE_MAX_DSS_FUSE_BITS); 352 318 353 - *group = dss / dss_per_grp; 354 - *instance = dss % dss_per_grp; 319 + *group = dss / gt->steering_dss_per_grp; 320 + *instance = dss % gt->steering_dss_per_grp; 355 321 } 356 322 357 323 static void init_steering_dss(struct xe_gt *gt) 358 324 { 325 + gt->steering_dss_per_grp = dss_per_group(gt); 326 + 359 327 xe_gt_mcr_get_dss_steering(gt, 360 328 min(xe_dss_mask_group_ffs(gt->fuse_topo.g_dss_mask, 0, 0), 361 329 xe_dss_mask_group_ffs(gt->fuse_topo.c_dss_mask, 0, 0)),
+6
drivers/gpu/drm/xe/xe_gt_types.h
··· 377 377 } steering[NUM_STEERING_TYPES]; 378 378 379 379 /** 380 + * @steering_dss_per_grp: number of DSS per steering group (gslice, 381 + * cslice, etc.). 382 + */ 383 + unsigned int steering_dss_per_grp; 384 + 385 + /** 380 386 * @mcr_lock: protects the MCR_SELECTOR register for the duration 381 387 * of a steered operation 382 388 */
+40
drivers/gpu/drm/xe/xe_guc_hwconfig.c
··· 160 160 161 161 kfree(hwconfig); 162 162 } 163 + 164 + /* 165 + * Lookup a specific 32-bit attribute value in the GuC's hwconfig table. 166 + */ 167 + int xe_guc_hwconfig_lookup_u32(struct xe_guc *guc, u32 attribute, u32 *val) 168 + { 169 + size_t size = xe_guc_hwconfig_size(guc); 170 + u64 num_dw = div_u64(size, sizeof(u32)); 171 + u32 *hwconfig; 172 + bool found = false; 173 + int i = 0; 174 + 175 + if (num_dw == 0) 176 + return -EINVAL; 177 + 178 + hwconfig = kzalloc(size, GFP_KERNEL); 179 + if (!hwconfig) 180 + return -ENOMEM; 181 + 182 + xe_guc_hwconfig_copy(guc, hwconfig); 183 + 184 + /* An entry requires at least three dwords for key, length, value */ 185 + while (i + 3 <= num_dw) { 186 + u32 key = hwconfig[i++]; 187 + u32 len_dw = hwconfig[i++]; 188 + 189 + if (key != attribute) { 190 + i += len_dw; 191 + continue; 192 + } 193 + 194 + *val = hwconfig[i]; 195 + found = true; 196 + break; 197 + } 198 + 199 + kfree(hwconfig); 200 + 201 + return found ? 0 : -ENOENT; 202 + }
+1
drivers/gpu/drm/xe/xe_guc_hwconfig.h
··· 15 15 u32 xe_guc_hwconfig_size(struct xe_guc *guc); 16 16 void xe_guc_hwconfig_copy(struct xe_guc *guc, void *dst); 17 17 void xe_guc_hwconfig_dump(struct xe_guc *guc, struct drm_printer *p); 18 + int xe_guc_hwconfig_lookup_u32(struct xe_guc *guc, u32 attribute, u32 *val); 18 19 19 20 #endif