if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
(boot_cpu_data.x86 >= 0x0f))) return;
if (cc_platform_has(CC_ATTR_HOST_SEV_SNP)) return;
rdmsr(MSR_AMD64_SYSCFG, lo, hi); if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
pr_err(FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]" " not cleared by BIOS, clearing this bit\n",
smp_processor_id());
lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
mtrr_wrmsr(MSR_AMD64_SYSCFG, lo, hi);
}
}
/* Get the size of contiguous MTRR range */ static u64 get_mtrr_size(u64 mask)
{
u64 size;
/* Sanity check: the array should NEVER be too small! */ if (cache_map_n == cache_map_size) {
WARN(1, "MTRR cache mode memory map exhausted!\n");
cache_map_n = cache_map_fixed; return0;
}
/* Clear a part of an entry. Return 1 if start of entry is still valid. */ staticint clr_map_range_at(u64 start, u64 end, int idx)
{ int ret = start != cache_map[idx].start;
u64 tmp;
for (i = 0; i < num_var_ranges; i++) {
type = get_var_mtrr_state(i, &start, &size); if (type != MTRR_TYPE_INVALID)
add_map_entry(start, start + size, type);
}
}
/* Build the cache_map containing the cache modes per memory range. */ void __init mtrr_build_map(void)
{
u64 start, end, size; unsignedint i;
u8 type;
/* Add fixed MTRRs, optimize for adjacent entries with same type. */ if (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED) { /* *Startwith64ksizefixedentries,preset1stone(hencethe *loopbelowisstartingwithindex1).
*/
start = 0;
end = size = 0x10000;
type = mtrr_state.fixed_ranges[0];
for (i = 1; i < MTRR_NUM_FIXED_RANGES; i++) { /* 8 64k entries, then 16 16k ones, rest 4k. */ if (i == 8 || i == 24)
size >>= 2;
if (mtrr_state.fixed_ranges[i] != type) {
add_map_entry(start, end, type);
start = end;
type = mtrr_state.fixed_ranges[i];
}
end += size;
}
add_map_entry(start, end, type);
}
/* Mark fixed, they take precedence. */ for (i = 0; i < cache_map_n; i++)
cache_map[i].fixed = 1;
cache_map_fixed = cache_map_n;
map_add_var();
pr_info("MTRR map: %u entries (%u fixed + %u variable; max %u), built from %u variable MTRRs\n",
cache_map_n, cache_map_fixed, cache_map_n - cache_map_fixed,
get_cache_map_size(), num_var_ranges + (mtrr_tom2 != 0));
if (mtrr_debug) { for (i = 0; i < cache_map_n; i++) {
pr_info("%3u: %016llx-%016llx %s\n", i,
cache_map[i].start, cache_map[i].end - 1,
mtrr_attrib_to_str(cache_map[i].type));
}
}
}
/* Copy the cache_map from __initdata memory to dynamically allocated one. */ void __init mtrr_copy_map(void)
{ unsignedint new_size = get_cache_map_size();
if (!mtrr_state.enabled || !new_size) {
cache_map = NULL; return;
}
mutex_lock(&mtrr_mutex);
cache_map = kcalloc(new_size, sizeof(*cache_map), GFP_KERNEL); if (cache_map) {
memmove(cache_map, init_cache_map,
cache_map_n * sizeof(*cache_map));
cache_map_size = new_size;
} else {
mtrr_state.enabled = 0;
pr_err("MTRRs disabled due to allocation failure for lookup map.\n");
}
/* Disable MTRR in order to disable MTRR modifications. */
setup_clear_cpu_cap(X86_FEATURE_MTRR);
if (var) { if (num_var > MTRR_MAX_VAR_RANGES) {
pr_warn("Trying to overwrite MTRR state with %u variable entries\n",
num_var);
num_var = MTRR_MAX_VAR_RANGES;
} for (i = 0; i < num_var; i++)
mtrr_state.var_ranges[i] = var[i];
num_var_ranges = num_var;
}
if (!mtrr_state_set) { /* Uniformity is unknown. */
*uniform = 0; return MTRR_TYPE_UNCACHABLE;
}
*uniform = 1;
if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED)) return MTRR_TYPE_UNCACHABLE;
for (i = 0; i < cache_map_n && start < end; i++) { /* Region after current map entry? -> continue with next one. */ if (start >= cache_map[i].end) continue;
/* Start of region not covered by current map entry? */ if (start < cache_map[i].start) { /* At least some part of region has default type. */
type = type_merge(type, mtrr_state.def_type, uniform); /* End of region not covered, too? -> lookup done. */ if (end <= cache_map[i].start) return type;
}
/* At least part of region covered by map entry. */
type = type_merge(type, cache_map[i].type, uniform);
start = cache_map[i].end;
}
/* End of region past last entry in map? -> use default type. */ if (start < end)
type = type_merge(type, mtrr_state.def_type, uniform);
return type;
}
/* Get the MSR pair relating to a var range */ staticvoid
get_mtrr_var_range(unsignedint index, struct mtrr_var_range *vr)
{
rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
}
/* Fill the MSR pair relating to a var range */ void fill_mtrr_var_range(unsignedint index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi)
{ struct mtrr_var_range *vr;
for (i = 0; i < 2; i++)
rdmsr(MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]); for (i = 0; i < 8; i++)
rdmsr(MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);
}
void mtrr_save_fixed_ranges(void *info)
{ if (mtrr_state.have_fixed)
get_fixed_ranges(mtrr_state.fixed_ranges);
}
for (i = 0; i < 8; ++i, ++types, base += step) { if (last_fixed_end == 0) {
update_fixed_last(base, base + step, *types); continue;
} if (last_fixed_end == base && last_fixed_type == *types) {
last_fixed_end = base + step; continue;
} /* new segments: gap or different type */
print_fixed_last();
update_fixed_last(base, base + step, *types);
}
}
staticvoid __init print_mtrr_state(void)
{ unsignedint i; int high_width;
pr_info("MTRR default type: %s\n",
mtrr_attrib_to_str(mtrr_state.def_type)); if (mtrr_state.have_fixed) {
pr_info("MTRR fixed ranges %s:\n",
str_enabled_disabled(
(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)));
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0); for (i = 0; i < 2; ++i)
print_fixed(0x80000 + i * 0x20000, 0x04000,
mtrr_state.fixed_ranges + (i + 1) * 8); for (i = 0; i < 8; ++i)
print_fixed(0xC0000 + i * 0x08000, 0x01000,
mtrr_state.fixed_ranges + (i + 3) * 8);
for (i = 0; i < num_var_ranges; ++i) { if (mtrr_state.var_ranges[i].mask_lo & MTRR_PHYSMASK_V)
pr_info(" %u base %0*X%05X000 mask %0*X%05X000 %s\n",
i,
high_width,
mtrr_state.var_ranges[i].base_hi,
mtrr_state.var_ranges[i].base_lo >> 12,
high_width,
mtrr_state.var_ranges[i].mask_hi,
mtrr_state.var_ranges[i].mask_lo >> 12,
mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo &
MTRR_PHYSBASE_TYPE)); else
pr_info(" %u disabled\n", i);
} if (mtrr_tom2)
pr_info("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20);
}
/* Grab all of the MTRR state for this CPU into *state */ bool __init get_mtrr_state(void)
{ struct mtrr_var_range *vrs; unsigned lo, dummy; unsignedint i;
vrs = mtrr_state.var_ranges;
rdmsr(MSR_MTRRcap, lo, dummy);
mtrr_state.have_fixed = lo & MTRR_CAP_FIX;
for (i = 0; i < num_var_ranges; i++)
get_mtrr_var_range(i, &vrs[i]); if (mtrr_state.have_fixed)
get_fixed_ranges(mtrr_state.fixed_ranges);
rdmsr(MSR_MTRRdefType, lo, dummy);
mtrr_state.def_type = lo & MTRR_DEF_TYPE_TYPE;
mtrr_state.enabled = (lo & MTRR_DEF_TYPE_ENABLE) >> MTRR_STATE_SHIFT;
if (amd_special_default_mtrr()) { unsigned low, high;
/* Some BIOS's are messed up and don't set all MTRRs the same! */ void __init mtrr_state_warn(void)
{ unsignedlong mask = smp_changes_mask;
if (!mask) return; if (mask & MTRR_CHANGE_MASK_FIXED)
pr_warn("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); if (mask & MTRR_CHANGE_MASK_VARIABLE)
pr_warn("mtrr: your CPUs had inconsistent variable MTRR settings\n"); if (mask & MTRR_CHANGE_MASK_DEFTYPE)
pr_warn("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
pr_info("mtrr: probably your BIOS does not setup all CPUs.\n");
pr_info("mtrr: corrected configuration.\n");
}
/* *Doesn'tattempttopassanerrorouttoMTRRusers *becauseit'squitecomplicatedinsomecasesandprobablynot *worthitbecausethebesterrorhandlingistoignoreit.
*/ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
{ if (wrmsr_safe(msr, a, b) < 0) {
pr_err("MTRR: CPU %u: Writing MSR %x to %x:%x failed\n",
smp_processor_id(), msr, a, b);
}
}
/* Actually set the state */
mask = set_mtrr_state();
/* Use the atomic bitops to update the global mask */ for (count = 0; count < sizeof(mask) * 8; ++count) { if (mask & 0x01)
set_bit(count, &smp_changes_mask);
mask >>= 1;
}
}
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.