cpu/x86/mtrr: allow temporary MTRR range during coreboot
Certain platforms have a poorly performing SPI prefetcher so even if accessing MMIO BIOS once the fetch time can be impacted. Payload loading is one example where it can be impacted. Therefore, add the ability for a platform to reconfigure the currently running CPU's variable MTRR settings for the duration of coreboot's execution. The function mtrr_use_temp_range() is added which uses the previous MTRR solution as a basis along with a new range and type to use. A new solution is calculated with the updated settings and the original solution is put back prior to exiting coreboot into the OS or payload. Using this patch on apollolake reduced depthcharge payload loading by 75 ms. BUG=chrome-os-partner:56656,chrome-os-partner:59682 Change-Id: If87ee6f88e0ab0a463eafa35f89a5f7a7ad0fb85 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: https://review.coreboot.org/17371 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Andrey Petrov <andrey.petrov@intel.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
This commit is contained in:
parent
2b3e0cdfc4
commit
2bebd7bc93
|
@ -154,6 +154,24 @@ static int filter_vga_wrcomb(struct device *dev, struct resource *res)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_physical_address_space(const struct memranges *addr_space,
|
||||||
|
const char *identifier)
|
||||||
|
{
|
||||||
|
const struct range_entry *r;
|
||||||
|
|
||||||
|
if (identifier)
|
||||||
|
printk(BIOS_DEBUG, "MTRR: %s Physical address space:\n",
|
||||||
|
identifier);
|
||||||
|
else
|
||||||
|
printk(BIOS_DEBUG, "MTRR: Physical address space:\n");
|
||||||
|
|
||||||
|
memranges_each_entry(r, addr_space)
|
||||||
|
printk(BIOS_DEBUG,
|
||||||
|
"0x%016llx - 0x%016llx size 0x%08llx type %ld\n",
|
||||||
|
range_entry_base(r), range_entry_end(r),
|
||||||
|
range_entry_size(r), range_entry_tag(r));
|
||||||
|
}
|
||||||
|
|
||||||
static struct memranges *get_physical_address_space(void)
|
static struct memranges *get_physical_address_space(void)
|
||||||
{
|
{
|
||||||
static struct memranges *addr_space;
|
static struct memranges *addr_space;
|
||||||
|
@ -163,7 +181,6 @@ static struct memranges *get_physical_address_space(void)
|
||||||
* uncacheable ranges, such as graphics memory, at resource insertion
|
* uncacheable ranges, such as graphics memory, at resource insertion
|
||||||
* time remove uncacheable regions from the cacheable ones. */
|
* time remove uncacheable regions from the cacheable ones. */
|
||||||
if (addr_space == NULL) {
|
if (addr_space == NULL) {
|
||||||
struct range_entry *r;
|
|
||||||
unsigned long mask;
|
unsigned long mask;
|
||||||
unsigned long match;
|
unsigned long match;
|
||||||
|
|
||||||
|
@ -193,12 +210,7 @@ static struct memranges *get_physical_address_space(void)
|
||||||
RANGE_TO_PHYS_ADDR(RANGE_4GB),
|
RANGE_TO_PHYS_ADDR(RANGE_4GB),
|
||||||
MTRR_TYPE_UNCACHEABLE);
|
MTRR_TYPE_UNCACHEABLE);
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "MTRR: Physical address space:\n");
|
print_physical_address_space(addr_space, NULL);
|
||||||
memranges_each_entry(r, addr_space)
|
|
||||||
printk(BIOS_DEBUG,
|
|
||||||
"0x%016llx - 0x%016llx size 0x%08llx type %ld\n",
|
|
||||||
range_entry_base(r), range_entry_end(r),
|
|
||||||
range_entry_size(r), range_entry_tag(r));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr_space;
|
return addr_space;
|
||||||
|
@ -380,11 +392,10 @@ struct var_mtrr_state {
|
||||||
|
|
||||||
static void clear_var_mtrr(int index)
|
static void clear_var_mtrr(int index)
|
||||||
{
|
{
|
||||||
msr_t msr_val;
|
msr_t msr = { .lo = 0, .hi = 0 };
|
||||||
|
|
||||||
msr_val = rdmsr(MTRR_PHYS_MASK(index));
|
wrmsr(MTRR_PHYS_BASE(index), msr);
|
||||||
msr_val.lo &= ~MTRR_PHYS_MASK_VALID;
|
wrmsr(MTRR_PHYS_MASK(index), msr);
|
||||||
wrmsr(MTRR_PHYS_MASK(index), msr_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prep_var_mtrr(struct var_mtrr_state *var_state,
|
static void prep_var_mtrr(struct var_mtrr_state *var_state,
|
||||||
|
@ -817,3 +828,60 @@ void x86_mtrr_check(void)
|
||||||
|
|
||||||
post_code(0x93);
|
post_code(0x93);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool put_back_original_solution;
|
||||||
|
|
||||||
|
void mtrr_use_temp_range(uintptr_t begin, size_t size, int type)
|
||||||
|
{
|
||||||
|
const struct range_entry *r;
|
||||||
|
const struct memranges *orig;
|
||||||
|
struct var_mtrr_solution sol;
|
||||||
|
struct memranges addr_space;
|
||||||
|
const int above4gb = 1; /* Cover above 4GiB by default. */
|
||||||
|
int address_bits;
|
||||||
|
|
||||||
|
/* Make a copy of the original address space and tweak it with the
|
||||||
|
* provided range. */
|
||||||
|
memranges_init_empty(&addr_space, NULL, 0);
|
||||||
|
orig = get_physical_address_space();
|
||||||
|
memranges_each_entry(r, orig) {
|
||||||
|
unsigned long tag = range_entry_tag(r);
|
||||||
|
|
||||||
|
/* Remove any special tags from original solution. */
|
||||||
|
tag &= ~MTRR_RANGE_UC_USE_HOLE;
|
||||||
|
|
||||||
|
/* Remove any write combining MTRRs from the temporary
|
||||||
|
* solution as it just fragments the address space. */
|
||||||
|
if (tag == MTRR_TYPE_WRCOMB)
|
||||||
|
tag = MTRR_TYPE_UNCACHEABLE;
|
||||||
|
|
||||||
|
memranges_insert(&addr_space, range_entry_base(r),
|
||||||
|
range_entry_size(r), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Place new range into the address space. */
|
||||||
|
memranges_insert(&addr_space, begin, size, type);
|
||||||
|
|
||||||
|
print_physical_address_space(&addr_space, "TEMPORARY");
|
||||||
|
|
||||||
|
/* Calculate a new solution with the updated address space. */
|
||||||
|
address_bits = cpu_phys_address_size();
|
||||||
|
memset(&sol, 0, sizeof(sol));
|
||||||
|
sol.mtrr_default_type =
|
||||||
|
calc_var_mtrrs(&addr_space, above4gb, address_bits);
|
||||||
|
prepare_var_mtrrs(&addr_space, sol.mtrr_default_type,
|
||||||
|
above4gb, address_bits, &sol);
|
||||||
|
commit_var_mtrrs(&sol);
|
||||||
|
|
||||||
|
memranges_teardown(&addr_space);
|
||||||
|
put_back_original_solution = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_temp_solution(void *unused)
|
||||||
|
{
|
||||||
|
if (put_back_original_solution)
|
||||||
|
commit_var_mtrrs(&mtrr_global_solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, remove_temp_solution, NULL);
|
||||||
|
BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, remove_temp_solution, NULL);
|
||||||
|
|
|
@ -45,6 +45,9 @@
|
||||||
|
|
||||||
#if !defined (__ASSEMBLER__) && !defined(__PRE_RAM__)
|
#if !defined (__ASSEMBLER__) && !defined(__PRE_RAM__)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The MTRR code has some side effects that the callers should be aware for.
|
* The MTRR code has some side effects that the callers should be aware for.
|
||||||
* 1. The call sequence matters. x86_setup_mtrrs() calls
|
* 1. The call sequence matters. x86_setup_mtrrs() calls
|
||||||
|
@ -77,6 +80,10 @@ void x86_setup_fixed_mtrrs(void);
|
||||||
/* Set up fixed MTRRs but do not enable them. */
|
/* Set up fixed MTRRs but do not enable them. */
|
||||||
void x86_setup_fixed_mtrrs_no_enable(void);
|
void x86_setup_fixed_mtrrs_no_enable(void);
|
||||||
void x86_mtrr_check(void);
|
void x86_mtrr_check(void);
|
||||||
|
|
||||||
|
/* Insert a temporary MTRR range for the duration of coreboot's runtime.
|
||||||
|
* This function needs to be called after the first MTRR solution is derived. */
|
||||||
|
void mtrr_use_temp_range(uintptr_t begin, size_t size, int type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__ASSEMBLER__) && defined(__PRE_RAM__) && !defined(__ROMCC__)
|
#if !defined(__ASSEMBLER__) && defined(__PRE_RAM__) && !defined(__ROMCC__)
|
||||||
|
|
Loading…
Reference in New Issue