0001
0002
0003
0004
0005
0006 #include "i915_drv.h"
0007
0008 #include "intel_gt_mcr.h"
0009 #include "intel_gt_regs.h"
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #define HAS_MSLICE_STEERING(dev_priv) (INTEL_INFO(dev_priv)->has_mslice_steering)
0038
0039 static const char * const intel_steering_types[] = {
0040 "L3BANK",
0041 "MSLICE",
0042 "LNCF",
0043 "INSTANCE 0",
0044 };
0045
0046 static const struct intel_mmio_range icl_l3bank_steering_table[] = {
0047 { 0x00B100, 0x00B3FF },
0048 {},
0049 };
0050
0051 static const struct intel_mmio_range xehpsdv_mslice_steering_table[] = {
0052 { 0x004000, 0x004AFF },
0053 { 0x00C800, 0x00CFFF },
0054 { 0x00DD00, 0x00DDFF },
0055 { 0x00E900, 0x00FFFF },
0056 {},
0057 };
0058
0059 static const struct intel_mmio_range xehpsdv_lncf_steering_table[] = {
0060 { 0x00B000, 0x00B0FF },
0061 { 0x00D800, 0x00D8FF },
0062 {},
0063 };
0064
0065 static const struct intel_mmio_range dg2_lncf_steering_table[] = {
0066 { 0x00B000, 0x00B0FF },
0067 { 0x00D880, 0x00D8FF },
0068 {},
0069 };
0070
0071
0072
0073
0074
0075
0076 static const struct intel_mmio_range pvc_instance0_steering_table[] = {
0077 { 0x004000, 0x004AFF },
0078 { 0x008800, 0x00887F },
0079 { 0x008A80, 0x008AFF },
0080 { 0x00B000, 0x00B0FF },
0081 { 0x00B100, 0x00B3FF },
0082 { 0x00C800, 0x00CFFF },
0083 { 0x00D800, 0x00D8FF },
0084 { 0x00DD00, 0x00DDFF },
0085 { 0x00E900, 0x00E9FF },
0086 { 0x00EC00, 0x00EEFF },
0087 { 0x00F000, 0x00FFFF },
0088 { 0x024180, 0x0241FF },
0089 {},
0090 };
0091
0092 void intel_gt_mcr_init(struct intel_gt *gt)
0093 {
0094 struct drm_i915_private *i915 = gt->i915;
0095
0096
0097
0098
0099
0100 if (HAS_MSLICE_STEERING(i915)) {
0101 gt->info.mslice_mask =
0102 intel_slicemask_from_xehp_dssmask(gt->info.sseu.subslice_mask,
0103 GEN_DSS_PER_MSLICE);
0104 gt->info.mslice_mask |=
0105 (intel_uncore_read(gt->uncore, GEN10_MIRROR_FUSE3) &
0106 GEN12_MEML3_EN_MASK);
0107
0108 if (!gt->info.mslice_mask)
0109 drm_warn(&i915->drm, "mslice mask all zero!\n");
0110 }
0111
0112 if (IS_PONTEVECCHIO(i915)) {
0113 gt->steering_table[INSTANCE0] = pvc_instance0_steering_table;
0114 } else if (IS_DG2(i915)) {
0115 gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table;
0116 gt->steering_table[LNCF] = dg2_lncf_steering_table;
0117 } else if (IS_XEHPSDV(i915)) {
0118 gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table;
0119 gt->steering_table[LNCF] = xehpsdv_lncf_steering_table;
0120 } else if (GRAPHICS_VER(i915) >= 11 &&
0121 GRAPHICS_VER_FULL(i915) < IP_VER(12, 50)) {
0122 gt->steering_table[L3BANK] = icl_l3bank_steering_table;
0123 gt->info.l3bank_mask =
0124 ~intel_uncore_read(gt->uncore, GEN10_MIRROR_FUSE3) &
0125 GEN10_L3BANK_MASK;
0126 if (!gt->info.l3bank_mask)
0127 drm_warn(&i915->drm, "L3 bank mask is all zero!\n");
0128 } else if (GRAPHICS_VER(i915) >= 11) {
0129
0130
0131
0132
0133 MISSING_CASE(INTEL_INFO(i915)->platform);
0134 }
0135 }
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
0151 i915_reg_t reg, u8 rw_flag,
0152 int group, int instance, u32 value)
0153 {
0154 u32 mcr_mask, mcr_ss, mcr, old_mcr, val = 0;
0155
0156 lockdep_assert_held(&uncore->lock);
0157
0158 if (GRAPHICS_VER(uncore->i915) >= 11) {
0159 mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK;
0160 mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance);
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 if (rw_flag == FW_REG_WRITE)
0175 mcr_mask |= GEN11_MCR_MULTICAST;
0176 } else {
0177 mcr_mask = GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK;
0178 mcr_ss = GEN8_MCR_SLICE(group) | GEN8_MCR_SUBSLICE(instance);
0179 }
0180
0181 old_mcr = mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
0182
0183 mcr &= ~mcr_mask;
0184 mcr |= mcr_ss;
0185 intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
0186
0187 if (rw_flag == FW_REG_READ)
0188 val = intel_uncore_read_fw(uncore, reg);
0189 else
0190 intel_uncore_write_fw(uncore, reg, value);
0191
0192 mcr &= ~mcr_mask;
0193 mcr |= old_mcr & mcr_mask;
0194
0195 intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
0196
0197 return val;
0198 }
0199
0200 static u32 rw_with_mcr_steering(struct intel_uncore *uncore,
0201 i915_reg_t reg, u8 rw_flag,
0202 int group, int instance,
0203 u32 value)
0204 {
0205 enum forcewake_domains fw_domains;
0206 u32 val;
0207
0208 fw_domains = intel_uncore_forcewake_for_reg(uncore, reg,
0209 rw_flag);
0210 fw_domains |= intel_uncore_forcewake_for_reg(uncore,
0211 GEN8_MCR_SELECTOR,
0212 FW_REG_READ | FW_REG_WRITE);
0213
0214 spin_lock_irq(&uncore->lock);
0215 intel_uncore_forcewake_get__locked(uncore, fw_domains);
0216
0217 val = rw_with_mcr_steering_fw(uncore, reg, rw_flag, group, instance, value);
0218
0219 intel_uncore_forcewake_put__locked(uncore, fw_domains);
0220 spin_unlock_irq(&uncore->lock);
0221
0222 return val;
0223 }
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235 u32 intel_gt_mcr_read(struct intel_gt *gt,
0236 i915_reg_t reg,
0237 int group, int instance)
0238 {
0239 return rw_with_mcr_steering(gt->uncore, reg, FW_REG_READ, group, instance, 0);
0240 }
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253 void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_reg_t reg, u32 value,
0254 int group, int instance)
0255 {
0256 rw_with_mcr_steering(gt->uncore, reg, FW_REG_WRITE, group, instance, value);
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 void intel_gt_mcr_multicast_write(struct intel_gt *gt,
0268 i915_reg_t reg, u32 value)
0269 {
0270 intel_uncore_write(gt->uncore, reg, value);
0271 }
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 value)
0285 {
0286 intel_uncore_write_fw(gt->uncore, reg, value);
0287 }
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303 static bool reg_needs_read_steering(struct intel_gt *gt,
0304 i915_reg_t reg,
0305 enum intel_steering_type type)
0306 {
0307 const u32 offset = i915_mmio_reg_offset(reg);
0308 const struct intel_mmio_range *entry;
0309
0310 if (likely(!gt->steering_table[type]))
0311 return false;
0312
0313 for (entry = gt->steering_table[type]; entry->end; entry++) {
0314 if (offset >= entry->start && offset <= entry->end)
0315 return true;
0316 }
0317
0318 return false;
0319 }
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 static void get_nonterminated_steering(struct intel_gt *gt,
0332 enum intel_steering_type type,
0333 u8 *group, u8 *instance)
0334 {
0335 switch (type) {
0336 case L3BANK:
0337 *group = 0;
0338 *instance = __ffs(gt->info.l3bank_mask);
0339 break;
0340 case MSLICE:
0341 GEM_WARN_ON(!HAS_MSLICE_STEERING(gt->i915));
0342 *group = __ffs(gt->info.mslice_mask);
0343 *instance = 0;
0344 break;
0345 case LNCF:
0346
0347
0348
0349
0350 GEM_WARN_ON(!HAS_MSLICE_STEERING(gt->i915));
0351 *group = __ffs(gt->info.mslice_mask) << 1;
0352 *instance = 0;
0353 break;
0354 case INSTANCE0:
0355
0356
0357
0358
0359 *group = 0;
0360 *instance = 0;
0361 break;
0362 default:
0363 MISSING_CASE(type);
0364 *group = 0;
0365 *instance = 0;
0366 }
0367 }
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt,
0383 i915_reg_t reg,
0384 u8 *group, u8 *instance)
0385 {
0386 int type;
0387
0388 for (type = 0; type < NUM_STEERING_TYPES; type++) {
0389 if (reg_needs_read_steering(gt, reg, type)) {
0390 get_nonterminated_steering(gt, type, group, instance);
0391 return;
0392 }
0393 }
0394
0395 *group = gt->default_steering.groupid;
0396 *instance = gt->default_steering.instanceid;
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg)
0413 {
0414 int type;
0415 u8 group, instance;
0416
0417 for (type = 0; type < NUM_STEERING_TYPES; type++) {
0418 if (reg_needs_read_steering(gt, reg, type)) {
0419 get_nonterminated_steering(gt, type, &group, &instance);
0420 return rw_with_mcr_steering_fw(gt->uncore, reg,
0421 FW_REG_READ,
0422 group, instance, 0);
0423 }
0424 }
0425
0426 return intel_uncore_read_fw(gt->uncore, reg);
0427 }
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439 u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg)
0440 {
0441 int type;
0442 u8 group, instance;
0443
0444 for (type = 0; type < NUM_STEERING_TYPES; type++) {
0445 if (reg_needs_read_steering(gt, reg, type)) {
0446 get_nonterminated_steering(gt, type, &group, &instance);
0447 return rw_with_mcr_steering(gt->uncore, reg,
0448 FW_REG_READ,
0449 group, instance, 0);
0450 }
0451 }
0452
0453 return intel_uncore_read(gt->uncore, reg);
0454 }
0455
0456 static void report_steering_type(struct drm_printer *p,
0457 struct intel_gt *gt,
0458 enum intel_steering_type type,
0459 bool dump_table)
0460 {
0461 const struct intel_mmio_range *entry;
0462 u8 group, instance;
0463
0464 BUILD_BUG_ON(ARRAY_SIZE(intel_steering_types) != NUM_STEERING_TYPES);
0465
0466 if (!gt->steering_table[type]) {
0467 drm_printf(p, "%s steering: uses default steering\n",
0468 intel_steering_types[type]);
0469 return;
0470 }
0471
0472 get_nonterminated_steering(gt, type, &group, &instance);
0473 drm_printf(p, "%s steering: group=0x%x, instance=0x%x\n",
0474 intel_steering_types[type], group, instance);
0475
0476 if (!dump_table)
0477 return;
0478
0479 for (entry = gt->steering_table[type]; entry->end; entry++)
0480 drm_printf(p, "\t0x%06x - 0x%06x\n", entry->start, entry->end);
0481 }
0482
0483 void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt,
0484 bool dump_table)
0485 {
0486 drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n",
0487 gt->default_steering.groupid,
0488 gt->default_steering.instanceid);
0489
0490 if (IS_PONTEVECCHIO(gt->i915)) {
0491 report_steering_type(p, gt, INSTANCE0, dump_table);
0492 } else if (HAS_MSLICE_STEERING(gt->i915)) {
0493 report_steering_type(p, gt, MSLICE, dump_table);
0494 report_steering_type(p, gt, LNCF, dump_table);
0495 }
0496 }
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508 void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss,
0509 unsigned int *group, unsigned int *instance)
0510 {
0511 if (IS_PONTEVECCHIO(gt->i915)) {
0512 *group = dss / GEN_DSS_PER_CSLICE;
0513 *instance = dss % GEN_DSS_PER_CSLICE;
0514 } else if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) {
0515 *group = dss / GEN_DSS_PER_GSLICE;
0516 *instance = dss % GEN_DSS_PER_GSLICE;
0517 } else {
0518 *group = dss / GEN_MAX_SS_PER_HSW_SLICE;
0519 *instance = dss % GEN_MAX_SS_PER_HSW_SLICE;
0520 return;
0521 }
0522 }