x86: mtrr: Add support for writing to MTRRs on any CPU

To enable support for the 'mtrr' command, add a way to perform MTRR
operations on selected CPUs.

This works by setting up a little 'operation' structure and sending it
around the CPUs for action.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
This commit is contained in:
Simon Glass 2020-07-17 08:48:26 -06:00 committed by Bin Meng
parent aa3a4d870e
commit 8dda2baa97
3 changed files with 105 additions and 3 deletions

View file

@ -221,3 +221,84 @@ int mtrr_set_next_var(uint type, uint64_t start, uint64_t size)
return 0;
}
/** enum mtrr_opcode - supported operations for mtrr_do_oper() */
enum mtrr_opcode {
MTRR_OP_SET,
MTRR_OP_SET_VALID,
};
/**
* struct mtrr_oper - An MTRR operation to perform on a CPU
*
* @opcode: Indicates operation to perform
* @reg: MTRR reg number to select (0-7, -1 = all)
* @valid: Valid value to write for MTRR_OP_SET_VALID
* @base: Base value to write for MTRR_OP_SET
* @mask: Mask value to write for MTRR_OP_SET
*/
struct mtrr_oper {
enum mtrr_opcode opcode;
int reg;
bool valid;
u64 base;
u64 mask;
};
static void mtrr_do_oper(void *arg)
{
struct mtrr_oper *oper = arg;
u64 mask;
switch (oper->opcode) {
case MTRR_OP_SET_VALID:
mask = native_read_msr(MTRR_PHYS_MASK_MSR(oper->reg));
if (oper->valid)
mask |= MTRR_PHYS_MASK_VALID;
else
mask &= ~MTRR_PHYS_MASK_VALID;
wrmsrl(MTRR_PHYS_MASK_MSR(oper->reg), mask);
break;
case MTRR_OP_SET:
wrmsrl(MTRR_PHYS_BASE_MSR(oper->reg), oper->base);
wrmsrl(MTRR_PHYS_MASK_MSR(oper->reg), oper->mask);
break;
}
}
static int mtrr_start_op(int cpu_select, struct mtrr_oper *oper)
{
struct mtrr_state state;
int ret;
mtrr_open(&state, true);
ret = mp_run_on_cpus(cpu_select, mtrr_do_oper, oper);
mtrr_close(&state, true);
if (ret)
return log_msg_ret("run", ret);
return 0;
}
int mtrr_set_valid(int cpu_select, int reg, bool valid)
{
struct mtrr_oper oper;
oper.opcode = MTRR_OP_SET_VALID;
oper.reg = reg;
oper.valid = valid;
return mtrr_start_op(cpu_select, &oper);
}
int mtrr_set(int cpu_select, int reg, u64 base, u64 mask)
{
struct mtrr_oper oper;
oper.opcode = MTRR_OP_SET;
oper.reg = reg;
oper.base = base;
oper.mask = mask;
return mtrr_start_op(cpu_select, &oper);
}

View file

@ -159,6 +159,27 @@ int mtrr_set_next_var(uint type, uint64_t base, uint64_t size);
*/
void mtrr_read_all(struct mtrr_info *info);
/**
* mtrr_set_valid() - Set the valid flag for a selected MTRR and CPU(s)
*
* @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...)
* @reg: MTRR register to write (0-7)
* @valid: Valid flag to write
* @return 0 on success, -ve on error
*/
int mtrr_set_valid(int cpu_select, int reg, bool valid);
/**
* mtrr_set() - Set the valid flag for a selected MTRR and CPU(s)
*
* @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...)
* @reg: MTRR register to write (0-7)
* @base: Base address and MTRR_BASE_TYPE_MASK
* @mask: Mask and MTRR_PHYS_MASK_VALID
* @return 0 on success, -ve on error
*/
int mtrr_set(int cpu_select, int reg, u64 base, u64 mask);
#endif
#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)

View file

@ -96,7 +96,7 @@ static int do_mtrr_set(uint reg, int argc, char *const argv[])
return 0;
}
static int mtrr_set_valid(int reg, bool valid)
static int mtrr_set_valid_(int reg, bool valid)
{
struct mtrr_state state;
uint64_t mask;
@ -134,9 +134,9 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_USAGE;
}
if (*cmd == 'e')
return mtrr_set_valid(reg, true);
return mtrr_set_valid_(reg, true);
else if (*cmd == 'd')
return mtrr_set_valid(reg, false);
return mtrr_set_valid_(reg, false);
else if (*cmd == 's')
return do_mtrr_set(reg, argc - 1, argv + 1);
else