Commit f32898c9 authored by Matt Roper's avatar Matt Roper

drm/i915/xelpg: Add multicast steering

MTL's graphics IP (Xe_LPG) once again changes the multicast register
types and steering details.  Key changes from past platforms:
 * The number of instances of some MCR types (NODE, OAAL2, and GAM) vary
   according to the MTL subplatform and cannot be read from fuse
   registers.  However steering to instance #0 will always provided a
   non-terminated value, so we can lump these all into a single
   "instance0" table.
 * The MCR steering register (and its bitfields) has changed.

Unlike past platforms, we will be explicitly steering all types of MCR
accesses, including those for "SLICE" and "DSS" ranges; we no longer
rely on implicit steering.  On previous platforms, various
hardware/firmware agents that needed to access registers typically had
their own steering control registers, allowing them to perform multicast
steering without clobbering the CPU/kernel steering.  Starting with MTL,
more of these agents now share a single steering register (0xFD4) and it
is no longer safe for us to assume that the value will remain unchanged
from how we initialized it during startup.  There is also a slight
chance of race conditions between the driver and a hardware/firmware
agent, so the hardware provides a semaphore register that can be used to
coordinate access to the steering register.  Support for the semaphore
register will be introduced in a future patch.

v2:
 - Use Xe_LPG terminology instead of "MTL 3D" since it's the IP version
   we're matching on now rather than the platform.
 - Don't combine l3bank and mslice masks into a union.  It's not related
   to the other changes here and we might still need both of them on
   some future platform.
 - Separate debug dumping of steering settings to a separate helper
   function.  (Tvrtko)
 - Update debug dumping to include DSS ranges (and future-proof it so
   that any new ranges added on future platforms will also be dumped).
 - Restore MULTICAST bit at the end of rw_with_mcr_steering_fw() if we
   cleared it.  Also force the MULTICAST bit to true at the beginning of
   multicast writes just to be safe.  (Bala)

Bspec: 67788, 67112
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Balasubramani Vivekanandan <balasubramani.vivekanandan@intel.com>
Signed-off-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Reviewed-by: default avatarBalasubramani Vivekanandan <balasubramani.vivekanandan@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-14-matthew.d.roper@intel.com
parent 58bc2453
...@@ -41,6 +41,7 @@ static const char * const intel_steering_types[] = { ...@@ -41,6 +41,7 @@ static const char * const intel_steering_types[] = {
"MSLICE", "MSLICE",
"LNCF", "LNCF",
"GAM", "GAM",
"DSS",
"INSTANCE 0", "INSTANCE 0",
}; };
...@@ -99,9 +100,40 @@ static const struct intel_mmio_range pvc_instance0_steering_table[] = { ...@@ -99,9 +100,40 @@ static const struct intel_mmio_range pvc_instance0_steering_table[] = {
{}, {},
}; };
static const struct intel_mmio_range xelpg_instance0_steering_table[] = {
{ 0x000B00, 0x000BFF }, /* SQIDI */
{ 0x001000, 0x001FFF }, /* SQIDI */
{ 0x004000, 0x0048FF }, /* GAM */
{ 0x008700, 0x0087FF }, /* SQIDI */
{ 0x00B000, 0x00B0FF }, /* NODE */
{ 0x00C800, 0x00CFFF }, /* GAM */
{ 0x00D880, 0x00D8FF }, /* NODE */
{ 0x00DD00, 0x00DDFF }, /* OAAL2 */
{},
};
static const struct intel_mmio_range xelpg_l3bank_steering_table[] = {
{ 0x00B100, 0x00B3FF },
{},
};
/* DSS steering is used for SLICE ranges as well */
static const struct intel_mmio_range xelpg_dss_steering_table[] = {
{ 0x005200, 0x0052FF }, /* SLICE */
{ 0x005500, 0x007FFF }, /* SLICE */
{ 0x008140, 0x00815F }, /* SLICE (0x8140-0x814F), DSS (0x8150-0x815F) */
{ 0x0094D0, 0x00955F }, /* SLICE (0x94D0-0x951F), DSS (0x9520-0x955F) */
{ 0x009680, 0x0096FF }, /* DSS */
{ 0x00D800, 0x00D87F }, /* SLICE */
{ 0x00DC00, 0x00DCFF }, /* SLICE */
{ 0x00DE80, 0x00E8FF }, /* DSS (0xE000-0xE0FF reserved) */
};
void intel_gt_mcr_init(struct intel_gt *gt) void intel_gt_mcr_init(struct intel_gt *gt)
{ {
struct drm_i915_private *i915 = gt->i915; struct drm_i915_private *i915 = gt->i915;
unsigned long fuse;
int i;
/* /*
* An mslice is unavailable only if both the meml3 for the slice is * An mslice is unavailable only if both the meml3 for the slice is
...@@ -119,7 +151,22 @@ void intel_gt_mcr_init(struct intel_gt *gt) ...@@ -119,7 +151,22 @@ void intel_gt_mcr_init(struct intel_gt *gt)
drm_warn(&i915->drm, "mslice mask all zero!\n"); drm_warn(&i915->drm, "mslice mask all zero!\n");
} }
if (IS_PONTEVECCHIO(i915)) { if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70) &&
gt->type == GT_PRIMARY) {
fuse = REG_FIELD_GET(GT_L3_EXC_MASK,
intel_uncore_read(gt->uncore, XEHP_FUSE4));
/*
* Despite the register field being named "exclude mask" the
* bits actually represent enabled banks (two banks per bit).
*/
for_each_set_bit(i, &fuse, 3)
gt->info.l3bank_mask |= 0x3 << 2 * i;
gt->steering_table[INSTANCE0] = xelpg_instance0_steering_table;
gt->steering_table[L3BANK] = xelpg_l3bank_steering_table;
gt->steering_table[DSS] = xelpg_dss_steering_table;
} else if (IS_PONTEVECCHIO(i915)) {
gt->steering_table[INSTANCE0] = pvc_instance0_steering_table; gt->steering_table[INSTANCE0] = pvc_instance0_steering_table;
} else if (IS_DG2(i915)) { } else if (IS_DG2(i915)) {
gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table; gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table;
...@@ -184,7 +231,19 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, ...@@ -184,7 +231,19 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
lockdep_assert_held(&uncore->lock); lockdep_assert_held(&uncore->lock);
if (GRAPHICS_VER(uncore->i915) >= 11) { if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70)) {
/*
* Always leave the hardware in multicast mode when doing reads
* (see comment about Wa_22013088509 below) and only change it
* to unicast mode when doing writes of a specific instance.
*
* No need to save old steering reg value.
*/
intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR,
REG_FIELD_PREP(MTL_MCR_GROUPID, group) |
REG_FIELD_PREP(MTL_MCR_INSTANCEID, instance) |
(rw_flag == FW_REG_READ) ? GEN11_MCR_MULTICAST : 0);
} else if (GRAPHICS_VER(uncore->i915) >= 11) {
mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK; mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK;
mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance); mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance);
...@@ -202,26 +261,40 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, ...@@ -202,26 +261,40 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
*/ */
if (rw_flag == FW_REG_WRITE) if (rw_flag == FW_REG_WRITE)
mcr_mask |= GEN11_MCR_MULTICAST; mcr_mask |= GEN11_MCR_MULTICAST;
mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
old_mcr = mcr;
mcr &= ~mcr_mask;
mcr |= mcr_ss;
intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
} else { } else {
mcr_mask = GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK; mcr_mask = GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK;
mcr_ss = GEN8_MCR_SLICE(group) | GEN8_MCR_SUBSLICE(instance); mcr_ss = GEN8_MCR_SLICE(group) | GEN8_MCR_SUBSLICE(instance);
}
old_mcr = mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR); mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR);
old_mcr = mcr;
mcr &= ~mcr_mask; mcr &= ~mcr_mask;
mcr |= mcr_ss; mcr |= mcr_ss;
intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr);
}
if (rw_flag == FW_REG_READ) if (rw_flag == FW_REG_READ)
val = intel_uncore_read_fw(uncore, mcr_reg_cast(reg)); val = intel_uncore_read_fw(uncore, mcr_reg_cast(reg));
else else
intel_uncore_write_fw(uncore, mcr_reg_cast(reg), value); intel_uncore_write_fw(uncore, mcr_reg_cast(reg), value);
mcr &= ~mcr_mask; /*
mcr |= old_mcr & mcr_mask; * For pre-MTL platforms, we need to restore the old value of the
* steering control register to ensure that implicit steering continues
intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); * to behave as expected. For MTL and beyond, we need only reinstate
* the 'multicast' bit (and only if we did a write that cleared it).
*/
if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70) && rw_flag == FW_REG_WRITE)
intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
else if (GRAPHICS_VER_FULL(uncore->i915) < IP_VER(12, 70))
intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, old_mcr);
return val; return val;
} }
...@@ -296,6 +369,13 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 val ...@@ -296,6 +369,13 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 val
void intel_gt_mcr_multicast_write(struct intel_gt *gt, void intel_gt_mcr_multicast_write(struct intel_gt *gt,
i915_mcr_reg_t reg, u32 value) i915_mcr_reg_t reg, u32 value)
{ {
/*
* Ensure we have multicast behavior, just in case some non-i915 agent
* left the hardware in unicast mode.
*/
if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value); intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value);
} }
...@@ -312,6 +392,13 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt, ...@@ -312,6 +392,13 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt,
*/ */
void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value) void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value)
{ {
/*
* Ensure we have multicast behavior, just in case some non-i915 agent
* left the hardware in unicast mode.
*/
if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
intel_uncore_write_fw(gt->uncore, mcr_reg_cast(reg), value); intel_uncore_write_fw(gt->uncore, mcr_reg_cast(reg), value);
} }
...@@ -389,6 +476,8 @@ static void get_nonterminated_steering(struct intel_gt *gt, ...@@ -389,6 +476,8 @@ static void get_nonterminated_steering(struct intel_gt *gt,
enum intel_steering_type type, enum intel_steering_type type,
u8 *group, u8 *instance) u8 *group, u8 *instance)
{ {
u32 dss;
switch (type) { switch (type) {
case L3BANK: case L3BANK:
*group = 0; /* unused */ *group = 0; /* unused */
...@@ -412,6 +501,11 @@ static void get_nonterminated_steering(struct intel_gt *gt, ...@@ -412,6 +501,11 @@ static void get_nonterminated_steering(struct intel_gt *gt,
*group = IS_DG2(gt->i915) ? 1 : 0; *group = IS_DG2(gt->i915) ? 1 : 0;
*instance = 0; *instance = 0;
break; break;
case DSS:
dss = intel_sseu_find_first_xehp_dss(&gt->info.sseu, 0, 0);
*group = dss / GEN_DSS_PER_GSLICE;
*instance = dss % GEN_DSS_PER_GSLICE;
break;
case INSTANCE0: case INSTANCE0:
/* /*
* There are a lot of MCR types for which instance (0, 0) * There are a lot of MCR types for which instance (0, 0)
...@@ -544,11 +638,20 @@ static void report_steering_type(struct drm_printer *p, ...@@ -544,11 +638,20 @@ static void report_steering_type(struct drm_printer *p,
void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt, void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt,
bool dump_table) bool dump_table)
{ {
drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n", /*
gt->default_steering.groupid, * Starting with MTL we no longer have default steering;
gt->default_steering.instanceid); * all ranges are explicitly steered.
*/
if (IS_PONTEVECCHIO(gt->i915)) { if (GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70))
drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n",
gt->default_steering.groupid,
gt->default_steering.instanceid);
if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) {
for (int i = 0; i < NUM_STEERING_TYPES; i++)
if (gt->steering_table[i])
report_steering_type(p, gt, i, dump_table);
} else if (IS_PONTEVECCHIO(gt->i915)) {
report_steering_type(p, gt, INSTANCE0, dump_table); report_steering_type(p, gt, INSTANCE0, dump_table);
} else if (HAS_MSLICE_STEERING(gt->i915)) { } else if (HAS_MSLICE_STEERING(gt->i915)) {
report_steering_type(p, gt, MSLICE, dump_table); report_steering_type(p, gt, MSLICE, dump_table);
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#define FORCEWAKE_ACK_GT_MTL _MMIO(0xdfc) #define FORCEWAKE_ACK_GT_MTL _MMIO(0xdfc)
#define MCFG_MCR_SELECTOR _MMIO(0xfd0) #define MCFG_MCR_SELECTOR _MMIO(0xfd0)
#define MTL_MCR_SELECTOR _MMIO(0xfd4)
#define SF_MCR_SELECTOR _MMIO(0xfd8) #define SF_MCR_SELECTOR _MMIO(0xfd8)
#define GEN8_MCR_SELECTOR _MMIO(0xfdc) #define GEN8_MCR_SELECTOR _MMIO(0xfdc)
#define GAM_MCR_SELECTOR _MMIO(0xfe0) #define GAM_MCR_SELECTOR _MMIO(0xfe0)
...@@ -68,6 +69,8 @@ ...@@ -68,6 +69,8 @@
#define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf) #define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf)
#define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24) #define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24)
#define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7) #define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7)
#define MTL_MCR_GROUPID REG_GENMASK(11, 8)
#define MTL_MCR_INSTANCEID REG_GENMASK(3, 0)
#define IPEIR_I965 _MMIO(0x2064) #define IPEIR_I965 _MMIO(0x2064)
#define IPEHR_I965 _MMIO(0x2068) #define IPEHR_I965 _MMIO(0x2068)
...@@ -528,6 +531,8 @@ ...@@ -528,6 +531,8 @@
#define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0) #define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0)
/* Fuse readout registers for GT */ /* Fuse readout registers for GT */
#define XEHP_FUSE4 _MMIO(0x9114)
#define GT_L3_EXC_MASK REG_GENMASK(6, 4)
#define GEN10_MIRROR_FUSE3 _MMIO(0x9118) #define GEN10_MIRROR_FUSE3 _MMIO(0x9118)
#define GEN10_L3BANK_PAIR_COUNT 4 #define GEN10_L3BANK_PAIR_COUNT 4
#define GEN10_L3BANK_MASK 0x0F #define GEN10_L3BANK_MASK 0x0F
......
...@@ -60,6 +60,7 @@ enum intel_steering_type { ...@@ -60,6 +60,7 @@ enum intel_steering_type {
MSLICE, MSLICE,
LNCF, LNCF,
GAM, GAM,
DSS,
/* /*
* On some platforms there are multiple types of MCR registers that * On some platforms there are multiple types of MCR registers that
......
...@@ -1128,18 +1128,23 @@ static void __set_mcr_steering(struct i915_wa_list *wal, ...@@ -1128,18 +1128,23 @@ static void __set_mcr_steering(struct i915_wa_list *wal,
wa_write_clr_set(wal, steering_reg, mcr_mask, mcr); wa_write_clr_set(wal, steering_reg, mcr_mask, mcr);
} }
static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal, static void debug_dump_steering(struct intel_gt *gt)
unsigned int slice, unsigned int subslice)
{ {
struct drm_printer p = drm_debug_printer("MCR Steering:"); struct drm_printer p = drm_debug_printer("MCR Steering:");
if (drm_debug_enabled(DRM_UT_DRIVER))
intel_gt_mcr_report_steering(&p, gt, false);
}
static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal,
unsigned int slice, unsigned int subslice)
{
__set_mcr_steering(wal, GEN8_MCR_SELECTOR, slice, subslice); __set_mcr_steering(wal, GEN8_MCR_SELECTOR, slice, subslice);
gt->default_steering.groupid = slice; gt->default_steering.groupid = slice;
gt->default_steering.instanceid = subslice; gt->default_steering.instanceid = subslice;
if (drm_debug_enabled(DRM_UT_DRIVER)) debug_dump_steering(gt);
intel_gt_mcr_report_steering(&p, gt, false);
} }
static void static void
...@@ -1581,12 +1586,30 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) ...@@ -1581,12 +1586,30 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
} }
static void
xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
{
/* FIXME: Actual workarounds will be added in future patch(es) */
/*
* Unlike older platforms, we no longer setup implicit steering here;
* all MCR accesses are explicitly steered.
*/
debug_dump_steering(gt);
}
static void static void
gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal)
{ {
struct drm_i915_private *i915 = gt->i915; struct drm_i915_private *i915 = gt->i915;
if (IS_PONTEVECCHIO(i915)) /* FIXME: Media GT handling will be added in an upcoming patch */
if (gt->type == GT_MEDIA)
return;
if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70))
xelpg_gt_workarounds_init(gt, wal);
else if (IS_PONTEVECCHIO(i915))
pvc_gt_workarounds_init(gt, wal); pvc_gt_workarounds_init(gt, wal);
else if (IS_DG2(i915)) else if (IS_DG2(i915))
dg2_gt_workarounds_init(gt, wal); dg2_gt_workarounds_init(gt, wal);
......
...@@ -1142,6 +1142,7 @@ static const struct intel_device_info mtl_info = { ...@@ -1142,6 +1142,7 @@ static const struct intel_device_info mtl_info = {
.display.has_modular_fia = 1, .display.has_modular_fia = 1,
.extra_gt_list = xelpmp_extra_gt, .extra_gt_list = xelpmp_extra_gt,
.has_flat_ccs = 0, .has_flat_ccs = 0,
.has_mslice_steering = 0,
.has_snoop = 1, .has_snoop = 1,
.__runtime.memory_regions = REGION_SMEM | REGION_STOLEN_LMEM, .__runtime.memory_regions = REGION_SMEM | REGION_STOLEN_LMEM,
.__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(CCS0), .__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(CCS0),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment