From patchwork Fri May 22 02:23:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 246209 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Thu, 21 May 2020 20:23:22 -0600 Subject: [PATCH 18/22] x86: mtrr: Add support for writing to MTRRs on any CPU In-Reply-To: <20200522022326.238388-1-sjg@chromium.org> References: <20200522022326.238388-1-sjg@chromium.org> Message-ID: <20200521202309.18.I79f1122b437ee390b87d4446bbcfc51dd581d908@changeid> 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 --- arch/x86/cpu/mtrr.c | 81 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 21 ++++++++++ 2 files changed, 102 insertions(+) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index a48c9d8232e..25f317d4298 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 476d6f8a9cf..6c50a67e1fe 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_save_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)