struct xe_mocs_info { /* * Size of the spec's suggested MOCS programming table. The list of * table entries from the spec can potentially be smaller than the * number of hardware registers used to program the MOCS table; in such * cases the registers for the remaining indices will be programmed to * match unused_entries_index.
*/ unsignedint table_size; /* Number of MOCS entries supported by the hardware */ unsignedint num_mocs_regs; conststruct xe_mocs_entry *table; conststruct xe_mocs_ops *ops;
u8 uc_index;
u8 wb_index;
u8 unused_entries_index;
};
/* Defines for the tables (GLOB_MOCS_0 - GLOB_MOCS_16) */ #define IG_PAT REG_BIT(8) #define L3_CACHE_POLICY_MASK REG_GENMASK(5, 4) #define L4_CACHE_POLICY_MASK REG_GENMASK(3, 2)
/* (e)LLC caching options */ /* * Note: LE_0_PAGETABLE works only up to Gen11; for newer gens it means * the same as LE_UC
*/ #define LE_0_PAGETABLE LE_CACHEABILITY(0) #define LE_1_UC LE_CACHEABILITY(1) #define LE_2_WT LE_CACHEABILITY(2) #define LE_3_WB LE_CACHEABILITY(3)
/* * MOCS tables * * These are the MOCS tables that are programmed across all the rings. * The control value is programmed to all the rings that support the * MOCS registers. While the l3cc_values are only programmed to the * LNCFCMOCS0 - LNCFCMOCS32 registers. * * These tables are intended to be kept reasonably consistent across * HW platforms, and for ICL+, be identical across OSes. To achieve * that, the list of entries is published as part of bspec. * * Entries not part of the following tables are undefined as far as userspace is * concerned and shouldn't be relied upon. The last few entries are reserved by * the hardware. They should be initialized according to bspec and never used. * * NOTE1: These tables are part of bspec and defined as part of the hardware * interface. It is expected that, for specific hardware platform, existing * entries will remain constant and the table will only be updated by adding new * entries, filling unused positions. * * NOTE2: Reserved and unspecified MOCS indices have been set to L3 WB. These * reserved entries should never be used. They may be changed to low performant * variants with better coherency in the future if more entries are needed.
*/
for (i = 0; i < info->num_mocs_regs; i++) { if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else
reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
for (i = 0; i < info->num_mocs_regs; i++) { if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else
reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
for (i = 0; i < info->num_mocs_regs; i++) { if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else
reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i));
switch (xe->info.platform) { case XE_PANTHERLAKE: case XE_LUNARLAKE: case XE_BATTLEMAGE:
info->ops = &xe2_mocs_ops;
info->table_size = ARRAY_SIZE(xe2_mocs_table);
info->table = xe2_mocs_table;
info->num_mocs_regs = XE2_NUM_MOCS_ENTRIES;
info->uc_index = 3;
info->wb_index = 4;
info->unused_entries_index = 4; break; case XE_PVC:
info->ops = &pvc_mocs_ops;
info->table_size = ARRAY_SIZE(pvc_mocs_desc);
info->table = pvc_mocs_desc;
info->num_mocs_regs = PVC_NUM_MOCS_ENTRIES;
info->uc_index = 1;
info->wb_index = 2;
info->unused_entries_index = 2; break; case XE_METEORLAKE:
info->ops = &mtl_mocs_ops;
info->table_size = ARRAY_SIZE(mtl_mocs_desc);
info->table = mtl_mocs_desc;
info->num_mocs_regs = MTL_NUM_MOCS_ENTRIES;
info->uc_index = 9;
info->unused_entries_index = 1; break; case XE_DG2:
info->ops = &xehp_mocs_ops;
info->table_size = ARRAY_SIZE(dg2_mocs_desc);
info->table = dg2_mocs_desc;
info->uc_index = 1; /* * Last entry is RO on hardware, don't bother with what was * written when checking later
*/
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES - 1;
info->unused_entries_index = 3; break; case XE_DG1:
info->ops = &xelp_mocs_ops;
info->table_size = ARRAY_SIZE(dg1_mocs_desc);
info->table = dg1_mocs_desc;
info->uc_index = 1;
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
info->unused_entries_index = 5; break; case XE_TIGERLAKE: case XE_ROCKETLAKE: case XE_ALDERLAKE_S: case XE_ALDERLAKE_P: case XE_ALDERLAKE_N:
info->ops = &xelp_mocs_ops;
info->table_size = ARRAY_SIZE(gen12_mocs_desc);
info->table = gen12_mocs_desc;
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
info->uc_index = 3;
info->unused_entries_index = 2; break; default:
drm_err(&xe->drm, "Platform that should have a MOCS table does not.\n"); return 0;
}
/* * Index 0 is a reserved/unused table entry on most platforms, but * even on those where it does represent a legitimate MOCS entry, it * never represents the "most cached, least coherent" behavior we want * to populate undefined table rows with. So if unused_entries_index * is still 0 at this point, we'll assume that it was omitted by * mistake in the switch statement above.
*/
xe_assert(xe, info->unused_entries_index != 0);
if (!IS_DGFX(xe) || GRAPHICS_VER(xe) >= 20)
flags |= HAS_GLOBAL_MOCS; if (GRAPHICS_VER(xe) < 20)
flags |= HAS_LNCF_MOCS;
return flags;
}
/* * Get control_value from MOCS entry. If the table entry is not defined, the * settings from unused_entries_index will be returned.
*/ static u32 get_entry_control(conststruct xe_mocs_info *info, unsignedint index)
{ if (index < info->table_size && info->table[index].used) return info->table[index].control_value; return info->table[info->unused_entries_index].control_value;
}
/* * Get l3cc_value from MOCS entry taking into account when it's not used * then if unused_entries_index is not zero then its value will be returned * otherwise I915_MOCS_PTE's value is returned in this case.
*/ static u16 get_entry_l3cc(conststruct xe_mocs_info *info, unsignedint index)
{ if (index < info->table_size && info->table[index].used) return info->table[index].l3cc_value; return info->table[info->unused_entries_index].l3cc_value;
}
/* * MOCS settings are split between "GLOB_MOCS" and/or "LNCFCMOCS" * registers depending on platform. * * These registers should be programmed before GuC initialization * since their values will affect some of the memory transactions * performed by the GuC.
*/
flags = get_mocs_settings(gt_to_xe(gt), &table);
mocs_dbg(gt, "flag:0x%x\n", flags);
if (IS_SRIOV_VF(gt_to_xe(gt))) return;
if (flags & HAS_GLOBAL_MOCS)
__init_mocs_table(gt, &table); if (flags & HAS_LNCF_MOCS)
init_l3cc_table(gt, &table);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.