896 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2019 Intel Corporation4 */5 6#include <linux/string_helpers.h>7 8#include "i915_drv.h"9#include "i915_perf_types.h"10#include "intel_engine_regs.h"11#include "intel_gt_regs.h"12#include "intel_sseu.h"13 14void intel_sseu_set_info(struct sseu_dev_info *sseu, u8 max_slices,15 u8 max_subslices, u8 max_eus_per_subslice)16{17 sseu->max_slices = max_slices;18 sseu->max_subslices = max_subslices;19 sseu->max_eus_per_subslice = max_eus_per_subslice;20}21 22unsigned int23intel_sseu_subslice_total(const struct sseu_dev_info *sseu)24{25 unsigned int i, total = 0;26 27 if (sseu->has_xehp_dss)28 return bitmap_weight(sseu->subslice_mask.xehp,29 XEHP_BITMAP_BITS(sseu->subslice_mask));30 31 for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask.hsw); i++)32 total += hweight8(sseu->subslice_mask.hsw[i]);33 34 return total;35}36 37unsigned int38intel_sseu_get_hsw_subslices(const struct sseu_dev_info *sseu, u8 slice)39{40 WARN_ON(sseu->has_xehp_dss);41 if (WARN_ON(slice >= sseu->max_slices))42 return 0;43 44 return sseu->subslice_mask.hsw[slice];45}46 47static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,48 int subslice)49{50 if (sseu->has_xehp_dss) {51 WARN_ON(slice > 0);52 return sseu->eu_mask.xehp[subslice];53 } else {54 return sseu->eu_mask.hsw[slice][subslice];55 }56}57 58static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,59 u16 eu_mask)60{61 GEM_WARN_ON(eu_mask && __fls(eu_mask) >= sseu->max_eus_per_subslice);62 if (sseu->has_xehp_dss) {63 GEM_WARN_ON(slice > 0);64 sseu->eu_mask.xehp[subslice] = eu_mask;65 } else {66 sseu->eu_mask.hsw[slice][subslice] = eu_mask;67 }68}69 70static u16 compute_eu_total(const struct sseu_dev_info *sseu)71{72 int s, ss, total = 0;73 74 for (s = 0; s < sseu->max_slices; s++)75 for (ss = 0; ss < sseu->max_subslices; ss++)76 if (sseu->has_xehp_dss)77 total += hweight16(sseu->eu_mask.xehp[ss]);78 else79 total += hweight16(sseu->eu_mask.hsw[s][ss]);80 81 return total;82}83 84/**85 * intel_sseu_copy_eumask_to_user - Copy EU mask into a userspace buffer86 * @to: Pointer to userspace buffer to copy to87 * @sseu: SSEU structure containing EU mask to copy88 *89 * Copies the EU mask to a userspace buffer in the format expected by90 * the query ioctl's topology queries.91 *92 * Returns the result of the copy_to_user() operation.93 */94int intel_sseu_copy_eumask_to_user(void __user *to,95 const struct sseu_dev_info *sseu)96{97 u8 eu_mask[GEN_SS_MASK_SIZE * GEN_MAX_EU_STRIDE] = {};98 int eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice);99 int len = sseu->max_slices * sseu->max_subslices * eu_stride;100 int s, ss, i;101 102 for (s = 0; s < sseu->max_slices; s++) {103 for (ss = 0; ss < sseu->max_subslices; ss++) {104 int uapi_offset =105 s * sseu->max_subslices * eu_stride +106 ss * eu_stride;107 u16 mask = sseu_get_eus(sseu, s, ss);108 109 for (i = 0; i < eu_stride; i++)110 eu_mask[uapi_offset + i] =111 (mask >> (BITS_PER_BYTE * i)) & 0xff;112 }113 }114 115 return copy_to_user(to, eu_mask, len);116}117 118/**119 * intel_sseu_copy_ssmask_to_user - Copy subslice mask into a userspace buffer120 * @to: Pointer to userspace buffer to copy to121 * @sseu: SSEU structure containing subslice mask to copy122 *123 * Copies the subslice mask to a userspace buffer in the format expected by124 * the query ioctl's topology queries.125 *126 * Returns the result of the copy_to_user() operation.127 */128int intel_sseu_copy_ssmask_to_user(void __user *to,129 const struct sseu_dev_info *sseu)130{131 u8 ss_mask[GEN_SS_MASK_SIZE] = {};132 int ss_stride = GEN_SSEU_STRIDE(sseu->max_subslices);133 int len = sseu->max_slices * ss_stride;134 int s, ss, i;135 136 for (s = 0; s < sseu->max_slices; s++) {137 for (ss = 0; ss < sseu->max_subslices; ss++) {138 i = s * ss_stride * BITS_PER_BYTE + ss;139 140 if (!intel_sseu_has_subslice(sseu, s, ss))141 continue;142 143 ss_mask[i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);144 }145 }146 147 return copy_to_user(to, ss_mask, len);148}149 150static void gen11_compute_sseu_info(struct sseu_dev_info *sseu,151 u32 ss_en, u16 eu_en)152{153 u32 valid_ss_mask = GENMASK(sseu->max_subslices - 1, 0);154 int ss;155 156 sseu->slice_mask |= BIT(0);157 sseu->subslice_mask.hsw[0] = ss_en & valid_ss_mask;158 159 for (ss = 0; ss < sseu->max_subslices; ss++)160 if (intel_sseu_has_subslice(sseu, 0, ss))161 sseu_set_eus(sseu, 0, ss, eu_en);162 163 sseu->eu_per_subslice = hweight16(eu_en);164 sseu->eu_total = compute_eu_total(sseu);165}166 167static void xehp_compute_sseu_info(struct sseu_dev_info *sseu,168 u16 eu_en)169{170 int ss;171 172 sseu->slice_mask |= BIT(0);173 174 bitmap_or(sseu->subslice_mask.xehp,175 sseu->compute_subslice_mask.xehp,176 sseu->geometry_subslice_mask.xehp,177 XEHP_BITMAP_BITS(sseu->subslice_mask));178 179 for (ss = 0; ss < sseu->max_subslices; ss++)180 if (intel_sseu_has_subslice(sseu, 0, ss))181 sseu_set_eus(sseu, 0, ss, eu_en);182 183 sseu->eu_per_subslice = hweight16(eu_en);184 sseu->eu_total = compute_eu_total(sseu);185}186 187static void188xehp_load_dss_mask(struct intel_uncore *uncore,189 intel_sseu_ss_mask_t *ssmask,190 int numregs,191 ...)192{193 va_list argp;194 u32 fuse_val[I915_MAX_SS_FUSE_REGS] = {};195 int i;196 197 if (WARN_ON(numregs > I915_MAX_SS_FUSE_REGS))198 numregs = I915_MAX_SS_FUSE_REGS;199 200 va_start(argp, numregs);201 for (i = 0; i < numregs; i++)202 fuse_val[i] = intel_uncore_read(uncore, va_arg(argp, i915_reg_t));203 va_end(argp);204 205 bitmap_from_arr32(ssmask->xehp, fuse_val, numregs * 32);206}207 208static void xehp_sseu_info_init(struct intel_gt *gt)209{210 struct sseu_dev_info *sseu = >->info.sseu;211 struct intel_uncore *uncore = gt->uncore;212 u16 eu_en = 0;213 u8 eu_en_fuse;214 int num_compute_regs, num_geometry_regs;215 int eu;216 217 num_geometry_regs = 1;218 num_compute_regs = 1;219 220 /*221 * The concept of slice has been removed in Xe_HP. To be compatible222 * with prior generations, assume a single slice across the entire223 * device. Then calculate out the DSS for each workload type within224 * that software slice.225 */226 intel_sseu_set_info(sseu, 1,227 32 * max(num_geometry_regs, num_compute_regs),228 HAS_ONE_EU_PER_FUSE_BIT(gt->i915) ? 8 : 16);229 sseu->has_xehp_dss = 1;230 231 xehp_load_dss_mask(uncore, &sseu->geometry_subslice_mask,232 num_geometry_regs,233 GEN12_GT_GEOMETRY_DSS_ENABLE);234 xehp_load_dss_mask(uncore, &sseu->compute_subslice_mask,235 num_compute_regs,236 GEN12_GT_COMPUTE_DSS_ENABLE,237 XEHPC_GT_COMPUTE_DSS_ENABLE_EXT);238 239 eu_en_fuse = intel_uncore_read(uncore, XEHP_EU_ENABLE) & XEHP_EU_ENA_MASK;240 241 if (HAS_ONE_EU_PER_FUSE_BIT(gt->i915))242 eu_en = eu_en_fuse;243 else244 for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)245 if (eu_en_fuse & BIT(eu))246 eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);247 248 xehp_compute_sseu_info(sseu, eu_en);249}250 251static void gen12_sseu_info_init(struct intel_gt *gt)252{253 struct sseu_dev_info *sseu = >->info.sseu;254 struct intel_uncore *uncore = gt->uncore;255 u32 g_dss_en;256 u16 eu_en = 0;257 u8 eu_en_fuse;258 u8 s_en;259 int eu;260 261 /*262 * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.263 * Instead of splitting these, provide userspace with an array264 * of DSS to more closely represent the hardware resource.265 */266 intel_sseu_set_info(sseu, 1, 6, 16);267 268 /*269 * Although gen12 architecture supported multiple slices, TGL, RKL,270 * DG1, and ADL only had a single slice.271 */272 s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &273 GEN11_GT_S_ENA_MASK;274 drm_WARN_ON(>->i915->drm, s_en != 0x1);275 276 g_dss_en = intel_uncore_read(uncore, GEN12_GT_GEOMETRY_DSS_ENABLE);277 278 /* one bit per pair of EUs */279 eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &280 GEN11_EU_DIS_MASK);281 282 for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)283 if (eu_en_fuse & BIT(eu))284 eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);285 286 gen11_compute_sseu_info(sseu, g_dss_en, eu_en);287 288 /* TGL only supports slice-level power gating */289 sseu->has_slice_pg = 1;290}291 292static void gen11_sseu_info_init(struct intel_gt *gt)293{294 struct sseu_dev_info *sseu = >->info.sseu;295 struct intel_uncore *uncore = gt->uncore;296 u32 ss_en;297 u8 eu_en;298 u8 s_en;299 300 if (IS_JASPERLAKE(gt->i915) || IS_ELKHARTLAKE(gt->i915))301 intel_sseu_set_info(sseu, 1, 4, 8);302 else303 intel_sseu_set_info(sseu, 1, 8, 8);304 305 /*306 * Although gen11 architecture supported multiple slices, ICL and307 * EHL/JSL only had a single slice in practice.308 */309 s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &310 GEN11_GT_S_ENA_MASK;311 drm_WARN_ON(>->i915->drm, s_en != 0x1);312 313 ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);314 315 eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &316 GEN11_EU_DIS_MASK);317 318 gen11_compute_sseu_info(sseu, ss_en, eu_en);319 320 /* ICL has no power gating restrictions. */321 sseu->has_slice_pg = 1;322 sseu->has_subslice_pg = 1;323 sseu->has_eu_pg = 1;324}325 326static void cherryview_sseu_info_init(struct intel_gt *gt)327{328 struct sseu_dev_info *sseu = >->info.sseu;329 u32 fuse;330 331 fuse = intel_uncore_read(gt->uncore, CHV_FUSE_GT);332 333 sseu->slice_mask = BIT(0);334 intel_sseu_set_info(sseu, 1, 2, 8);335 336 if (!(fuse & CHV_FGT_DISABLE_SS0)) {337 u8 disabled_mask =338 ((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>339 CHV_FGT_EU_DIS_SS0_R0_SHIFT) |340 (((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>341 CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);342 343 sseu->subslice_mask.hsw[0] |= BIT(0);344 sseu_set_eus(sseu, 0, 0, ~disabled_mask & 0xFF);345 }346 347 if (!(fuse & CHV_FGT_DISABLE_SS1)) {348 u8 disabled_mask =349 ((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>350 CHV_FGT_EU_DIS_SS1_R0_SHIFT) |351 (((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>352 CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);353 354 sseu->subslice_mask.hsw[0] |= BIT(1);355 sseu_set_eus(sseu, 0, 1, ~disabled_mask & 0xFF);356 }357 358 sseu->eu_total = compute_eu_total(sseu);359 360 /*361 * CHV expected to always have a uniform distribution of EU362 * across subslices.363 */364 sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?365 sseu->eu_total /366 intel_sseu_subslice_total(sseu) :367 0;368 /*369 * CHV supports subslice power gating on devices with more than370 * one subslice, and supports EU power gating on devices with371 * more than one EU pair per subslice.372 */373 sseu->has_slice_pg = 0;374 sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;375 sseu->has_eu_pg = (sseu->eu_per_subslice > 2);376}377 378static void gen9_sseu_info_init(struct intel_gt *gt)379{380 struct drm_i915_private *i915 = gt->i915;381 struct sseu_dev_info *sseu = >->info.sseu;382 struct intel_uncore *uncore = gt->uncore;383 u32 fuse2, eu_disable, subslice_mask;384 const u8 eu_mask = 0xff;385 int s, ss;386 387 fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);388 sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;389 390 /* BXT has a single slice and at most 3 subslices. */391 intel_sseu_set_info(sseu, IS_GEN9_LP(i915) ? 1 : 3,392 IS_GEN9_LP(i915) ? 3 : 4, 8);393 394 /*395 * The subslice disable field is global, i.e. it applies396 * to each of the enabled slices.397 */398 subslice_mask = (1 << sseu->max_subslices) - 1;399 subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>400 GEN9_F2_SS_DIS_SHIFT);401 402 /*403 * Iterate through enabled slices and subslices to404 * count the total enabled EU.405 */406 for (s = 0; s < sseu->max_slices; s++) {407 if (!(sseu->slice_mask & BIT(s)))408 /* skip disabled slice */409 continue;410 411 sseu->subslice_mask.hsw[s] = subslice_mask;412 413 eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));414 for (ss = 0; ss < sseu->max_subslices; ss++) {415 int eu_per_ss;416 u8 eu_disabled_mask;417 418 if (!intel_sseu_has_subslice(sseu, s, ss))419 /* skip disabled subslice */420 continue;421 422 eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;423 424 sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & eu_mask);425 426 eu_per_ss = sseu->max_eus_per_subslice -427 hweight8(eu_disabled_mask);428 429 /*430 * Record which subslice(s) has(have) 7 EUs. we431 * can tune the hash used to spread work among432 * subslices if they are unbalanced.433 */434 if (eu_per_ss == 7)435 sseu->subslice_7eu[s] |= BIT(ss);436 }437 }438 439 sseu->eu_total = compute_eu_total(sseu);440 441 /*442 * SKL is expected to always have a uniform distribution443 * of EU across subslices with the exception that any one444 * EU in any one subslice may be fused off for die445 * recovery. BXT is expected to be perfectly uniform in EU446 * distribution.447 */448 sseu->eu_per_subslice =449 intel_sseu_subslice_total(sseu) ?450 DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :451 0;452 453 /*454 * SKL+ supports slice power gating on devices with more than455 * one slice, and supports EU power gating on devices with456 * more than one EU pair per subslice. BXT+ supports subslice457 * power gating on devices with more than one subslice, and458 * supports EU power gating on devices with more than one EU459 * pair per subslice.460 */461 sseu->has_slice_pg =462 !IS_GEN9_LP(i915) && hweight8(sseu->slice_mask) > 1;463 sseu->has_subslice_pg =464 IS_GEN9_LP(i915) && intel_sseu_subslice_total(sseu) > 1;465 sseu->has_eu_pg = sseu->eu_per_subslice > 2;466 467 if (IS_GEN9_LP(i915)) {468#define IS_SS_DISABLED(ss) (!(sseu->subslice_mask.hsw[0] & BIT(ss)))469 RUNTIME_INFO(i915)->has_pooled_eu = hweight8(sseu->subslice_mask.hsw[0]) == 3;470 471 sseu->min_eu_in_pool = 0;472 if (HAS_POOLED_EU(i915)) {473 if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))474 sseu->min_eu_in_pool = 3;475 else if (IS_SS_DISABLED(1))476 sseu->min_eu_in_pool = 6;477 else478 sseu->min_eu_in_pool = 9;479 }480#undef IS_SS_DISABLED481 }482}483 484static void bdw_sseu_info_init(struct intel_gt *gt)485{486 struct sseu_dev_info *sseu = >->info.sseu;487 struct intel_uncore *uncore = gt->uncore;488 int s, ss;489 u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */490 u32 eu_disable0, eu_disable1, eu_disable2;491 492 fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);493 sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;494 intel_sseu_set_info(sseu, 3, 3, 8);495 496 /*497 * The subslice disable field is global, i.e. it applies498 * to each of the enabled slices.499 */500 subslice_mask = GENMASK(sseu->max_subslices - 1, 0);501 subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>502 GEN8_F2_SS_DIS_SHIFT);503 eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);504 eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);505 eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);506 eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;507 eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |508 ((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<509 (32 - GEN8_EU_DIS0_S1_SHIFT));510 eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |511 ((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<512 (32 - GEN8_EU_DIS1_S2_SHIFT));513 514 /*515 * Iterate through enabled slices and subslices to516 * count the total enabled EU.517 */518 for (s = 0; s < sseu->max_slices; s++) {519 if (!(sseu->slice_mask & BIT(s)))520 /* skip disabled slice */521 continue;522 523 sseu->subslice_mask.hsw[s] = subslice_mask;524 525 for (ss = 0; ss < sseu->max_subslices; ss++) {526 u8 eu_disabled_mask;527 u32 n_disabled;528 529 if (!intel_sseu_has_subslice(sseu, s, ss))530 /* skip disabled subslice */531 continue;532 533 eu_disabled_mask =534 eu_disable[s] >> (ss * sseu->max_eus_per_subslice);535 536 sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & 0xFF);537 538 n_disabled = hweight8(eu_disabled_mask);539 540 /*541 * Record which subslices have 7 EUs.542 */543 if (sseu->max_eus_per_subslice - n_disabled == 7)544 sseu->subslice_7eu[s] |= 1 << ss;545 }546 }547 548 sseu->eu_total = compute_eu_total(sseu);549 550 /*551 * BDW is expected to always have a uniform distribution of EU across552 * subslices with the exception that any one EU in any one subslice may553 * be fused off for die recovery.554 */555 sseu->eu_per_subslice =556 intel_sseu_subslice_total(sseu) ?557 DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :558 0;559 560 /*561 * BDW supports slice power gating on devices with more than562 * one slice.563 */564 sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;565 sseu->has_subslice_pg = 0;566 sseu->has_eu_pg = 0;567}568 569static void hsw_sseu_info_init(struct intel_gt *gt)570{571 struct drm_i915_private *i915 = gt->i915;572 struct sseu_dev_info *sseu = >->info.sseu;573 u32 fuse1;574 u8 subslice_mask = 0;575 int s, ss;576 577 /*578 * There isn't a register to tell us how many slices/subslices. We579 * work off the PCI-ids here.580 */581 switch (INTEL_INFO(i915)->gt) {582 default:583 MISSING_CASE(INTEL_INFO(i915)->gt);584 fallthrough;585 case 1:586 sseu->slice_mask = BIT(0);587 subslice_mask = BIT(0);588 break;589 case 2:590 sseu->slice_mask = BIT(0);591 subslice_mask = BIT(0) | BIT(1);592 break;593 case 3:594 sseu->slice_mask = BIT(0) | BIT(1);595 subslice_mask = BIT(0) | BIT(1);596 break;597 }598 599 fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1);600 switch (REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)) {601 default:602 MISSING_CASE(REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1));603 fallthrough;604 case HSW_F1_EU_DIS_10EUS:605 sseu->eu_per_subslice = 10;606 break;607 case HSW_F1_EU_DIS_8EUS:608 sseu->eu_per_subslice = 8;609 break;610 case HSW_F1_EU_DIS_6EUS:611 sseu->eu_per_subslice = 6;612 break;613 }614 615 intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),616 hweight8(subslice_mask),617 sseu->eu_per_subslice);618 619 for (s = 0; s < sseu->max_slices; s++) {620 sseu->subslice_mask.hsw[s] = subslice_mask;621 622 for (ss = 0; ss < sseu->max_subslices; ss++) {623 sseu_set_eus(sseu, s, ss,624 (1UL << sseu->eu_per_subslice) - 1);625 }626 }627 628 sseu->eu_total = compute_eu_total(sseu);629 630 /* No powergating for you. */631 sseu->has_slice_pg = 0;632 sseu->has_subslice_pg = 0;633 sseu->has_eu_pg = 0;634}635 636void intel_sseu_info_init(struct intel_gt *gt)637{638 struct drm_i915_private *i915 = gt->i915;639 640 if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))641 xehp_sseu_info_init(gt);642 else if (GRAPHICS_VER(i915) >= 12)643 gen12_sseu_info_init(gt);644 else if (GRAPHICS_VER(i915) >= 11)645 gen11_sseu_info_init(gt);646 else if (GRAPHICS_VER(i915) >= 9)647 gen9_sseu_info_init(gt);648 else if (IS_BROADWELL(i915))649 bdw_sseu_info_init(gt);650 else if (IS_CHERRYVIEW(i915))651 cherryview_sseu_info_init(gt);652 else if (IS_HASWELL(i915))653 hsw_sseu_info_init(gt);654}655 656u32 intel_sseu_make_rpcs(struct intel_gt *gt,657 const struct intel_sseu *req_sseu)658{659 struct drm_i915_private *i915 = gt->i915;660 const struct sseu_dev_info *sseu = >->info.sseu;661 bool subslice_pg = sseu->has_subslice_pg;662 u8 slices, subslices;663 u32 rpcs = 0;664 665 /*666 * No explicit RPCS request is needed to ensure full667 * slice/subslice/EU enablement prior to Gen9.668 */669 if (GRAPHICS_VER(i915) < 9)670 return 0;671 672 /*673 * If i915/perf is active, we want a stable powergating configuration674 * on the system. Use the configuration pinned by i915/perf.675 */676 if (gt->perf.group && gt->perf.group[PERF_GROUP_OAG].exclusive_stream)677 req_sseu = >->perf.sseu;678 679 slices = hweight8(req_sseu->slice_mask);680 subslices = hweight8(req_sseu->subslice_mask);681 682 /*683 * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits684 * wide and Icelake has up to eight subslices, specfial programming is685 * needed in order to correctly enable all subslices.686 *687 * According to documentation software must consider the configuration688 * as 2x4x8 and hardware will translate this to 1x8x8.689 *690 * Furthemore, even though SScount is three bits, maximum documented691 * value for it is four. From this some rules/restrictions follow:692 *693 * 1.694 * If enabled subslice count is greater than four, two whole slices must695 * be enabled instead.696 *697 * 2.698 * When more than one slice is enabled, hardware ignores the subslice699 * count altogether.700 *701 * From these restrictions it follows that it is not possible to enable702 * a count of subslices between the SScount maximum of four restriction,703 * and the maximum available number on a particular SKU. Either all704 * subslices are enabled, or a count between one and four on the first705 * slice.706 */707 if (GRAPHICS_VER(i915) == 11 &&708 slices == 1 &&709 subslices > min_t(u8, 4, hweight8(sseu->subslice_mask.hsw[0]) / 2)) {710 GEM_BUG_ON(subslices & 1);711 712 subslice_pg = false;713 slices *= 2;714 }715 716 /*717 * Starting in Gen9, render power gating can leave718 * slice/subslice/EU in a partially enabled state. We719 * must make an explicit request through RPCS for full720 * enablement.721 */722 if (sseu->has_slice_pg) {723 u32 mask, val = slices;724 725 if (GRAPHICS_VER(i915) >= 11) {726 mask = GEN11_RPCS_S_CNT_MASK;727 val <<= GEN11_RPCS_S_CNT_SHIFT;728 } else {729 mask = GEN8_RPCS_S_CNT_MASK;730 val <<= GEN8_RPCS_S_CNT_SHIFT;731 }732 733 GEM_BUG_ON(val & ~mask);734 val &= mask;735 736 rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;737 }738 739 if (subslice_pg) {740 u32 val = subslices;741 742 val <<= GEN8_RPCS_SS_CNT_SHIFT;743 744 GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);745 val &= GEN8_RPCS_SS_CNT_MASK;746 747 rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;748 }749 750 if (sseu->has_eu_pg) {751 u32 val;752 753 val = req_sseu->min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;754 GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);755 val &= GEN8_RPCS_EU_MIN_MASK;756 757 rpcs |= val;758 759 val = req_sseu->max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;760 GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);761 val &= GEN8_RPCS_EU_MAX_MASK;762 763 rpcs |= val;764 765 rpcs |= GEN8_RPCS_ENABLE;766 }767 768 return rpcs;769}770 771void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)772{773 int s;774 775 if (sseu->has_xehp_dss) {776 drm_printf(p, "subslice total: %u\n",777 intel_sseu_subslice_total(sseu));778 drm_printf(p, "geometry dss mask=%*pb\n",779 XEHP_BITMAP_BITS(sseu->geometry_subslice_mask),780 sseu->geometry_subslice_mask.xehp);781 drm_printf(p, "compute dss mask=%*pb\n",782 XEHP_BITMAP_BITS(sseu->compute_subslice_mask),783 sseu->compute_subslice_mask.xehp);784 } else {785 drm_printf(p, "slice total: %u, mask=%04x\n",786 hweight8(sseu->slice_mask), sseu->slice_mask);787 drm_printf(p, "subslice total: %u\n",788 intel_sseu_subslice_total(sseu));789 790 for (s = 0; s < sseu->max_slices; s++) {791 u8 ss_mask = sseu->subslice_mask.hsw[s];792 793 drm_printf(p, "slice%d: %u subslices, mask=%08x\n",794 s, hweight8(ss_mask), ss_mask);795 }796 }797 798 drm_printf(p, "EU total: %u\n", sseu->eu_total);799 drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);800 drm_printf(p, "has slice power gating: %s\n",801 str_yes_no(sseu->has_slice_pg));802 drm_printf(p, "has subslice power gating: %s\n",803 str_yes_no(sseu->has_subslice_pg));804 drm_printf(p, "has EU power gating: %s\n",805 str_yes_no(sseu->has_eu_pg));806}807 808static void sseu_print_hsw_topology(const struct sseu_dev_info *sseu,809 struct drm_printer *p)810{811 int s, ss;812 813 for (s = 0; s < sseu->max_slices; s++) {814 u8 ss_mask = sseu->subslice_mask.hsw[s];815 816 drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",817 s, hweight8(ss_mask), ss_mask);818 819 for (ss = 0; ss < sseu->max_subslices; ss++) {820 u16 enabled_eus = sseu_get_eus(sseu, s, ss);821 822 drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",823 ss, hweight16(enabled_eus), enabled_eus);824 }825 }826}827 828static void sseu_print_xehp_topology(const struct sseu_dev_info *sseu,829 struct drm_printer *p)830{831 int dss;832 833 for (dss = 0; dss < sseu->max_subslices; dss++) {834 u16 enabled_eus = sseu_get_eus(sseu, 0, dss);835 836 drm_printf(p, "DSS_%02d: G:%3s C:%3s, %2u EUs (0x%04hx)\n", dss,837 str_yes_no(test_bit(dss, sseu->geometry_subslice_mask.xehp)),838 str_yes_no(test_bit(dss, sseu->compute_subslice_mask.xehp)),839 hweight16(enabled_eus), enabled_eus);840 }841}842 843void intel_sseu_print_topology(struct drm_i915_private *i915,844 const struct sseu_dev_info *sseu,845 struct drm_printer *p)846{847 if (sseu->max_slices == 0)848 drm_printf(p, "Unavailable\n");849 else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))850 sseu_print_xehp_topology(sseu, p);851 else852 sseu_print_hsw_topology(sseu, p);853}854 855void intel_sseu_print_ss_info(const char *type,856 const struct sseu_dev_info *sseu,857 struct seq_file *m)858{859 int s;860 861 if (sseu->has_xehp_dss) {862 seq_printf(m, " %s Geometry DSS: %u\n", type,863 bitmap_weight(sseu->geometry_subslice_mask.xehp,864 XEHP_BITMAP_BITS(sseu->geometry_subslice_mask)));865 seq_printf(m, " %s Compute DSS: %u\n", type,866 bitmap_weight(sseu->compute_subslice_mask.xehp,867 XEHP_BITMAP_BITS(sseu->compute_subslice_mask)));868 } else {869 for (s = 0; s < fls(sseu->slice_mask); s++)870 seq_printf(m, " %s Slice%i subslices: %u\n", type,871 s, hweight8(sseu->subslice_mask.hsw[s]));872 }873}874 875u16 intel_slicemask_from_xehp_dssmask(intel_sseu_ss_mask_t dss_mask,876 int dss_per_slice)877{878 intel_sseu_ss_mask_t per_slice_mask = {};879 unsigned long slice_mask = 0;880 int i;881 882 WARN_ON(DIV_ROUND_UP(XEHP_BITMAP_BITS(dss_mask), dss_per_slice) >883 8 * sizeof(slice_mask));884 885 bitmap_fill(per_slice_mask.xehp, dss_per_slice);886 for (i = 0; !bitmap_empty(dss_mask.xehp, XEHP_BITMAP_BITS(dss_mask)); i++) {887 if (bitmap_intersects(dss_mask.xehp, per_slice_mask.xehp, dss_per_slice))888 slice_mask |= BIT(i);889 890 bitmap_shift_right(dss_mask.xehp, dss_mask.xehp, dss_per_slice,891 XEHP_BITMAP_BITS(dss_mask));892 }893 894 return slice_mask;895}896