[PATCH v3 20/25] x86: mtrr: Add support for writing to MTRRs on any CPU
Simon Glass
sjg at chromium.org
Mon Jul 6 05:37:36 CEST 2020
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 at chromium.org>
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner at br-automation.com>
---
(no changes since v2)
Changes in v2:
- Keep things building by temporarily renaming the function in cmd/
arch/x86/cpu/mtrr.c | 81 +++++++++++++++++++++++++++++++++++++
arch/x86/include/asm/mtrr.h | 21 ++++++++++
cmd/x86/mtrr.c | 6 +--
3 files changed, 105 insertions(+), 3 deletions(-)
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
index 5c567551e5..2468d88a80 100644
--- a/arch/x86/cpu/mtrr.c
+++ b/arch/x86/cpu/mtrr.c
@@ -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);
+}
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index e1f1a44643..48db1dd82f 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -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)
diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c
index f357f58767..46ef6a2830 100644
--- a/cmd/x86/mtrr.c
+++ b/cmd/x86/mtrr.c
@@ -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
--
2.27.0.212.ge8ba1cc988-goog
More information about the U-Boot
mailing list