[PATCH v2 2/6] x86/mm/pat: Add pat_disable() interface

From: Toshi Kani
Date: Wed Mar 16 2016 - 19:55:53 EST

In preparation to fix a regression caused by 'commit 9cd25aac1f44
("x86/mm/pat: Emulate PAT when it is disabled")', PAT needs to
provide an interface that disables the OS to initialize PAT MSR.

PAT MSR initialization must be done on all CPUs with the specific
sequence of operations defined in Intel SDM. This requires MTRR
to be enabled since pat_init() is called as part of MTRR init
from mtrr_rendezvous_handler().

Change pat_disable() as the interface to disable the OS to initialize
PAT MSR, and set PAT table with pat_keep_handoff_state(). This
interface can be called when PAT initialization may not be performed.

This also assures that pat_disable() called from pat_bsp_init()
to set PAT table properly when CPU does not support PAT.

Signed-off-by: Toshi Kani <toshi.kani@xxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxx>
Cc: Luis R. Rodriguez <mcgrof@xxxxxxxx>
Cc: Juergen Gross <jgross@xxxxxxxx>
Cc: Robert Elliott <elliott@xxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: H. Peter Anvin <hpa@xxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
arch/x86/include/asm/pat.h | 1 +
arch/x86/mm/pat.c | 21 ++++++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index ca6c228..016142b 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -5,6 +5,7 @@
#include <asm/pgtable_types.h>

bool pat_enabled(void);
+void pat_disable(const char *reason);
extern void pat_init(void);
void pat_init_cache_modes(u64);

diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index e0a34b0..48d1619 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -40,11 +40,26 @@
static bool boot_cpu_done;

static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
+static void pat_keep_handoff_state(void);

-static inline void pat_disable(const char *reason)
+ * pat_disable() - Disable the OS to initialize PAT MSR
+ *
+ * This function disables the OS to initialize PAT MSR, and calls
+ * pat_keep_handoff_state() to set PAT table to the handoff state.
+ */
+void pat_disable(const char *reason)
+ if (boot_cpu_done) {
+ pr_err("x86/PAT: PAT cannot be disabled after initialization "
+ "(attempting: %s)\n", reason);
+ return;
+ }
__pat_enabled = 0;
pr_info("x86/PAT: %s\n", reason);
+ pat_keep_handoff_state();

static int __init nopat(char *str)
@@ -202,7 +217,7 @@ static void pat_bsp_init(u64 pat)
u64 tmp_pat;

- if (!cpu_has_pat) {
+ if (!boot_cpu_has(X86_FEATURE_PAT)) {
pat_disable("PAT not supported by CPU.");
@@ -220,7 +235,7 @@ static void pat_bsp_init(u64 pat)

static void pat_ap_init(u64 pat)
- if (!cpu_has_pat) {
+ if (!boot_cpu_has(X86_FEATURE_PAT)) {
* If this happens we are on a secondary CPU, but switched to
* PAT on the boot CPU. We have no way to undo PAT.