^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Intel Transactional Synchronization Extensions (TSX) control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2019 Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/cpufeature.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/cmdline.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "cpu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #undef pr_fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define pr_fmt(fmt) "tsx: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) enum tsx_ctrl_states tsx_ctrl_state __ro_after_init = TSX_CTRL_NOT_SUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) void tsx_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u64 tsx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) rdmsrl(MSR_IA32_TSX_CTRL, tsx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Force all transactions to immediately abort */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) tsx |= TSX_CTRL_RTM_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Ensure TSX support is not enumerated in CPUID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * This is visible to userspace and will ensure they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * do not waste resources trying TSX transactions that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * will always abort.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) tsx |= TSX_CTRL_CPUID_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) wrmsrl(MSR_IA32_TSX_CTRL, tsx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) void tsx_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u64 tsx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) rdmsrl(MSR_IA32_TSX_CTRL, tsx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* Enable the RTM feature in the cpu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) tsx &= ~TSX_CTRL_RTM_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Ensure TSX support is enumerated in CPUID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * This is visible to userspace and will ensure they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * can enumerate and use the TSX feature.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) tsx &= ~TSX_CTRL_CPUID_CLEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) wrmsrl(MSR_IA32_TSX_CTRL, tsx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static bool __init tsx_ctrl_is_supported(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u64 ia32_cap = x86_read_arch_cap_msr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * tsx= cmdline requests will do nothing on CPUs without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * MSR_IA32_TSX_CTRL support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (boot_cpu_has_bug(X86_BUG_TAA))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return TSX_CTRL_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return TSX_CTRL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) void __init tsx_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) char arg[5] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (!tsx_ctrl_is_supported())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (ret >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (!strcmp(arg, "on")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) tsx_ctrl_state = TSX_CTRL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) } else if (!strcmp(arg, "off")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) tsx_ctrl_state = TSX_CTRL_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) } else if (!strcmp(arg, "auto")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) tsx_ctrl_state = x86_get_tsx_auto_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) tsx_ctrl_state = TSX_CTRL_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) pr_err("invalid option, defaulting to off\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* tsx= not provided */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_AUTO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) tsx_ctrl_state = x86_get_tsx_auto_mode();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) else if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_OFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) tsx_ctrl_state = TSX_CTRL_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) tsx_ctrl_state = TSX_CTRL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (tsx_ctrl_state == TSX_CTRL_DISABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) tsx_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * tsx_disable() will change the state of the RTM and HLE CPUID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * bits. Clear them here since they are now expected to be not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) setup_clear_cpu_cap(X86_FEATURE_RTM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) setup_clear_cpu_cap(X86_FEATURE_HLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) } else if (tsx_ctrl_state == TSX_CTRL_ENABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * HW defaults TSX to be enabled at bootup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * We may still need the TSX enable support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * during init for special cases like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * kexec after TSX is disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) tsx_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * tsx_enable() will change the state of the RTM and HLE CPUID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * bits. Force them here since they are now expected to be set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) setup_force_cpu_cap(X86_FEATURE_RTM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) setup_force_cpu_cap(X86_FEATURE_HLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }