[17/22] x86: mtrr: Update MTRRs on all CPUs

Message ID 20200521202309.17.Ib8a974f884b75e218eed2a2eff355cbfa1919381@changeid
State New
Headers show
Series
  • x86: Enhance MTRR functionality to support multiple CPUs
Related show

Commit Message

Simon Glass May 22, 2020, 2:23 a.m.
When the boot CPU MTRRs are updated, perform the same update on all other
CPUs so they are kept in sync.

This avoids kernel warnings about mismatched MTRRs.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 arch/x86/cpu/mtrr.c | 57 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

Patch

diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
index 11f3ef08172..a48c9d8232e 100644
--- a/arch/x86/cpu/mtrr.c
+++ b/arch/x86/cpu/mtrr.c
@@ -74,10 +74,61 @@  void mtrr_save_all(struct mtrr_info *info)
 	}
 }
 
+void mtrr_load_all(struct mtrr_info *info)
+{
+	struct mtrr_state state;
+	int i;
+
+	for (i = 0; i < MTRR_COUNT; i++) {
+		mtrr_open(&state, true);
+		wrmsrl(MTRR_PHYS_BASE_MSR(i), info->mtrr[i].base);
+		wrmsrl(MTRR_PHYS_MASK_MSR(i), info->mtrr[i].mask);
+		mtrr_close(&state, true);
+	}
+}
+
+static void save_mtrrs(void *arg)
+{
+	struct mtrr_info *info = arg;
+
+	mtrr_save_all(info);
+}
+
+static void load_mtrrs(void *arg)
+{
+	struct mtrr_info *info = arg;
+
+	mtrr_load_all(info);
+}
+
+/**
+ * mtrr_copy_to_aps() - Copy the MTRRs from the boot CPU to other CPUs
+ *
+ * @return 0 on success, -ve on failure
+ */
+static int mtrr_copy_to_aps(void)
+{
+	struct mtrr_info info;
+	int ret;
+
+	ret = mp_run_on_cpus(MP_SELECT_BSP, save_mtrrs, &info);
+	if (ret == -ENXIO)
+		return 0;
+	else if (ret)
+		return log_msg_ret("bsp", ret);
+
+	ret = mp_run_on_cpus(MP_SELECT_APS, load_mtrrs, &info);
+	if (ret)
+		return log_msg_ret("bsp", ret);
+
+	return 0;
+}
+
 int mtrr_commit(bool do_caches)
 {
 	struct mtrr_request *req = gd->arch.mtrr_req;
 	struct mtrr_state state;
+	int ret;
 	int i;
 
 	debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr,
@@ -99,6 +150,12 @@  int mtrr_commit(bool do_caches)
 	mtrr_close(&state, do_caches);
 	debug("mtrr done\n");
 
+	if (gd->flags & GD_FLG_RELOC) {
+		ret = mtrr_copy_to_aps();
+		if (ret)
+			return log_msg_ret("copy", ret);
+	}
+
 	return 0;
 }