Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 CPU feature updates from Thomas Gleixner: "Updates for x86 CPU features: - Support for UMWAIT/UMONITOR, which allows to use MWAIT and MONITOR instructions in user space to save power e.g. in HPC workloads which spin wait on synchronization points. The maximum time a MWAIT can halt in userspace is controlled by the kernel and can be adjusted by the sysadmin. - Speed up the MTRR handling code on CPUs which support cache self-snooping correctly. On those CPUs the wbinvd() invocations can be omitted which speeds up the MTRR setup by a factor of 50. - Support for the new x86 vendor Zhaoxin who develops processors based on the VIA Centaur technology. - Prevent 'cat /proc/cpuinfo' from affecting isolated NOHZ_FULL CPUs by sending IPIs to retrieve the CPU frequency and use the cached values instead. - The addition and late revert of the FSGSBASE support. The revert was required as it turned out that the code still has hard to diagnose issues. Yet another engineering trainwreck... - Small fixes, cleanups, improvements and the usual new Intel CPU family/model addons" * 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits) x86/fsgsbase: Revert FSGSBASE support selftests/x86/fsgsbase: Fix some test case bugs x86/entry/64: Fix and clean up paranoid_exit x86/entry/64: Don't compile ignore_sysret if 32-bit emulation is enabled selftests/x86: Test SYSCALL and SYSENTER manually with TF set x86/mtrr: Skip cache flushes on CPUs with cache self-snooping x86/cpu/intel: Clear cache self-snoop capability in CPUs with known errata Documentation/ABI: Document umwait control sysfs interfaces x86/umwait: Add sysfs interface to control umwait maximum time x86/umwait: Add sysfs interface to control umwait C0.2 state x86/umwait: Initialize umwait control values x86/cpufeatures: Enumerate user wait instructions x86/cpu: Disable frequency requests via aperfmperf IPI for nohz_full CPUs x86/acpi/cstate: Add Zhaoxin processors support for cache flush policy in C3 ACPI, x86: Add Zhaoxin processors support for NONSTOP TSC x86/cpu: Create Zhaoxin processors architecture support file x86/cpu: Split Tremont based Atoms from the rest Documentation/x86/64: Add documentation for GS/FS addressing mode x86/elf: Enumerate kernel FSGSBASE capability in AT_HWCAP2 x86/cpu: Enable FSGSBASE on 64bit by default and add a chicken bit ...
This commit is contained in:
@@ -64,6 +64,21 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
||||
c->x86_stepping >= 0x0e))
|
||||
flags->bm_check = 1;
|
||||
}
|
||||
|
||||
if (c->x86_vendor == X86_VENDOR_ZHAOXIN) {
|
||||
/*
|
||||
* All Zhaoxin CPUs that support C3 share cache.
|
||||
* And caches should not be flushed by software while
|
||||
* entering C3 type state.
|
||||
*/
|
||||
flags->bm_check = 1;
|
||||
/*
|
||||
* On all recent Zhaoxin platforms, ARB_DISABLE is a nop.
|
||||
* So, set bm_control to zero to indicate that ARB_DISABLE
|
||||
* is not required while entering C3 type state.
|
||||
*/
|
||||
flags->bm_control = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
|
||||
|
||||
|
@@ -24,6 +24,7 @@ obj-y += match.o
|
||||
obj-y += bugs.o
|
||||
obj-y += aperfmperf.o
|
||||
obj-y += cpuid-deps.o
|
||||
obj-y += umwait.o
|
||||
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
||||
@@ -38,6 +39,7 @@ obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
|
||||
obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
|
||||
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
|
||||
obj-$(CONFIG_CPU_SUP_ZHAOXIN) += zhaoxin.o
|
||||
|
||||
obj-$(CONFIG_X86_MCE) += mce/
|
||||
obj-$(CONFIG_MTRR) += mtrr/
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
@@ -85,6 +86,9 @@ unsigned int aperfmperf_get_khz(int cpu)
|
||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||
return 0;
|
||||
|
||||
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||
return 0;
|
||||
|
||||
aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
|
||||
return per_cpu(samples.khz, cpu);
|
||||
}
|
||||
@@ -101,9 +105,12 @@ void arch_freq_prepare_all(void)
|
||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||
return;
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
for_each_online_cpu(cpu) {
|
||||
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||
continue;
|
||||
if (!aperfmperf_snapshot_cpu(cpu, now, false))
|
||||
wait = true;
|
||||
}
|
||||
|
||||
if (wait)
|
||||
msleep(APERFMPERF_REFRESH_DELAY_MS);
|
||||
@@ -117,6 +124,9 @@ unsigned int arch_freq_get_on_cpu(int cpu)
|
||||
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
|
||||
return 0;
|
||||
|
||||
if (!housekeeping_cpu(cpu, HK_FLAG_MISC))
|
||||
return 0;
|
||||
|
||||
if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
|
||||
return per_cpu(samples.khz, cpu);
|
||||
|
||||
|
@@ -658,8 +658,7 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
|
||||
if (c->x86 < 0x17) {
|
||||
/* LLC is at the node level. */
|
||||
per_cpu(cpu_llc_id, cpu) = node_id;
|
||||
} else if (c->x86 == 0x17 &&
|
||||
c->x86_model >= 0 && c->x86_model <= 0x1F) {
|
||||
} else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
|
||||
/*
|
||||
* LLC is at the core complex level.
|
||||
* Core complex ID is ApicId[3] for these processors.
|
||||
|
@@ -801,6 +801,30 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
|
||||
}
|
||||
}
|
||||
|
||||
static void init_cqm(struct cpuinfo_x86 *c)
|
||||
{
|
||||
if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
||||
c->x86_cache_max_rmid = -1;
|
||||
c->x86_cache_occ_scale = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* will be overridden if occupancy monitoring exists */
|
||||
c->x86_cache_max_rmid = cpuid_ebx(0xf);
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
||||
cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
c->x86_cache_max_rmid = ecx;
|
||||
c->x86_cache_occ_scale = ebx;
|
||||
}
|
||||
}
|
||||
|
||||
void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
@@ -823,6 +847,12 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
c->x86_capability[CPUID_7_0_EBX] = ebx;
|
||||
c->x86_capability[CPUID_7_ECX] = ecx;
|
||||
c->x86_capability[CPUID_7_EDX] = edx;
|
||||
|
||||
/* Check valid sub-leaf index before accessing it */
|
||||
if (eax >= 1) {
|
||||
cpuid_count(0x00000007, 1, &eax, &ebx, &ecx, &edx);
|
||||
c->x86_capability[CPUID_7_1_EAX] = eax;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extended state features: level 0x0000000d */
|
||||
@@ -832,33 +862,6 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
c->x86_capability[CPUID_D_1_EAX] = eax;
|
||||
}
|
||||
|
||||
/* Additional Intel-defined flags: level 0x0000000F */
|
||||
if (c->cpuid_level >= 0x0000000F) {
|
||||
|
||||
/* QoS sub-leaf, EAX=0Fh, ECX=0 */
|
||||
cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
|
||||
c->x86_capability[CPUID_F_0_EDX] = edx;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
||||
/* will be overridden if occupancy monitoring exists */
|
||||
c->x86_cache_max_rmid = ebx;
|
||||
|
||||
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
||||
cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
|
||||
c->x86_capability[CPUID_F_1_EDX] = edx;
|
||||
|
||||
if ((cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) ||
|
||||
((cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL)) ||
|
||||
(cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)))) {
|
||||
c->x86_cache_max_rmid = ecx;
|
||||
c->x86_cache_occ_scale = ebx;
|
||||
}
|
||||
} else {
|
||||
c->x86_cache_max_rmid = -1;
|
||||
c->x86_cache_occ_scale = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* AMD-defined flags: level 0x80000001 */
|
||||
eax = cpuid_eax(0x80000000);
|
||||
c->extended_cpuid_level = eax;
|
||||
@@ -889,6 +892,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
|
||||
init_scattered_cpuid_features(c);
|
||||
init_speculation_control(c);
|
||||
init_cqm(c);
|
||||
|
||||
/*
|
||||
* Clear/Set all flags overridden by options, after probe.
|
||||
|
@@ -64,6 +64,10 @@ static const struct cpuid_dep cpuid_deps[] = {
|
||||
{ X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
|
||||
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
|
||||
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
|
||||
{ X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC },
|
||||
{ X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC },
|
||||
{ X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC },
|
||||
{ X86_FEATURE_AVX512_BF16, X86_FEATURE_AVX512VL },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@@ -66,6 +66,32 @@ void check_mpx_erratum(struct cpuinfo_x86 *c)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Processors which have self-snooping capability can handle conflicting
|
||||
* memory type across CPUs by snooping its own cache. However, there exists
|
||||
* CPU models in which having conflicting memory types still leads to
|
||||
* unpredictable behavior, machine check errors, or hangs. Clear this
|
||||
* feature to prevent its use on machines with known erratas.
|
||||
*/
|
||||
static void check_memory_type_self_snoop_errata(struct cpuinfo_x86 *c)
|
||||
{
|
||||
switch (c->x86_model) {
|
||||
case INTEL_FAM6_CORE_YONAH:
|
||||
case INTEL_FAM6_CORE2_MEROM:
|
||||
case INTEL_FAM6_CORE2_MEROM_L:
|
||||
case INTEL_FAM6_CORE2_PENRYN:
|
||||
case INTEL_FAM6_CORE2_DUNNINGTON:
|
||||
case INTEL_FAM6_NEHALEM:
|
||||
case INTEL_FAM6_NEHALEM_G:
|
||||
case INTEL_FAM6_NEHALEM_EP:
|
||||
case INTEL_FAM6_NEHALEM_EX:
|
||||
case INTEL_FAM6_WESTMERE:
|
||||
case INTEL_FAM6_WESTMERE_EP:
|
||||
case INTEL_FAM6_SANDYBRIDGE:
|
||||
setup_clear_cpu_cap(X86_FEATURE_SELFSNOOP);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ring3mwait_disabled __read_mostly;
|
||||
|
||||
static int __init ring3mwait_disable(char *__unused)
|
||||
@@ -304,6 +330,7 @@ static void early_init_intel(struct cpuinfo_x86 *c)
|
||||
}
|
||||
|
||||
check_mpx_erratum(c);
|
||||
check_memory_type_self_snoop_errata(c);
|
||||
|
||||
/*
|
||||
* Get the number of SMT siblings early from the extended topology
|
||||
|
@@ -743,7 +743,15 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
|
||||
/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
|
||||
cr0 = read_cr0() | X86_CR0_CD;
|
||||
write_cr0(cr0);
|
||||
wbinvd();
|
||||
|
||||
/*
|
||||
* Cache flushing is the most time-consuming step when programming
|
||||
* the MTRRs. Fortunately, as per the Intel Software Development
|
||||
* Manual, we can skip it if the processor supports cache self-
|
||||
* snooping.
|
||||
*/
|
||||
if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
|
||||
wbinvd();
|
||||
|
||||
/* Save value of CR4 and clear Page Global Enable (bit 7) */
|
||||
if (boot_cpu_has(X86_FEATURE_PGE)) {
|
||||
@@ -760,7 +768,10 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
|
||||
|
||||
/* Disable MTRRs, and set the default type to uncached */
|
||||
mtrr_wrmsr(MSR_MTRRdefType, deftype_lo & ~0xcff, deftype_hi);
|
||||
wbinvd();
|
||||
|
||||
/* Again, only flush caches if we have to. */
|
||||
if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
|
||||
wbinvd();
|
||||
}
|
||||
|
||||
static void post_set(void) __releases(set_atomicity_lock)
|
||||
|
@@ -26,6 +26,10 @@ struct cpuid_bit {
|
||||
static const struct cpuid_bit cpuid_bits[] = {
|
||||
{ X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 },
|
||||
{ X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 },
|
||||
{ X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 },
|
||||
{ X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 },
|
||||
{ X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 },
|
||||
{ X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 },
|
||||
{ X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 },
|
||||
{ X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 },
|
||||
{ X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 },
|
||||
|
200
arch/x86/kernel/cpu/umwait.c
Normal file
200
arch/x86/kernel/cpu/umwait.c
Normal file
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
|
||||
#define UMWAIT_C02_ENABLE 0
|
||||
|
||||
#define UMWAIT_CTRL_VAL(max_time, c02_disable) \
|
||||
(((max_time) & MSR_IA32_UMWAIT_CONTROL_TIME_MASK) | \
|
||||
((c02_disable) & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE))
|
||||
|
||||
/*
|
||||
* Cache IA32_UMWAIT_CONTROL MSR. This is a systemwide control. By default,
|
||||
* umwait max time is 100000 in TSC-quanta and C0.2 is enabled
|
||||
*/
|
||||
static u32 umwait_control_cached = UMWAIT_CTRL_VAL(100000, UMWAIT_C02_ENABLE);
|
||||
|
||||
/*
|
||||
* Serialize access to umwait_control_cached and IA32_UMWAIT_CONTROL MSR in
|
||||
* the sysfs write functions.
|
||||
*/
|
||||
static DEFINE_MUTEX(umwait_lock);
|
||||
|
||||
static void umwait_update_control_msr(void * unused)
|
||||
{
|
||||
lockdep_assert_irqs_disabled();
|
||||
wrmsr(MSR_IA32_UMWAIT_CONTROL, READ_ONCE(umwait_control_cached), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The CPU hotplug callback sets the control MSR to the global control
|
||||
* value.
|
||||
*
|
||||
* Disable interrupts so the read of umwait_control_cached and the WRMSR
|
||||
* are protected against a concurrent sysfs write. Otherwise the sysfs
|
||||
* write could update the cached value after it had been read on this CPU
|
||||
* and issue the IPI before the old value had been written. The IPI would
|
||||
* interrupt, write the new value and after return from IPI the previous
|
||||
* value would be written by this CPU.
|
||||
*
|
||||
* With interrupts disabled the upcoming CPU either sees the new control
|
||||
* value or the IPI is updating this CPU to the new control value after
|
||||
* interrupts have been reenabled.
|
||||
*/
|
||||
static int umwait_cpu_online(unsigned int cpu)
|
||||
{
|
||||
local_irq_disable();
|
||||
umwait_update_control_msr(NULL);
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* On resume, restore IA32_UMWAIT_CONTROL MSR on the boot processor which
|
||||
* is the only active CPU at this time. The MSR is set up on the APs via the
|
||||
* CPU hotplug callback.
|
||||
*
|
||||
* This function is invoked on resume from suspend and hibernation. On
|
||||
* resume from suspend the restore should be not required, but we neither
|
||||
* trust the firmware nor does it matter if the same value is written
|
||||
* again.
|
||||
*/
|
||||
static void umwait_syscore_resume(void)
|
||||
{
|
||||
umwait_update_control_msr(NULL);
|
||||
}
|
||||
|
||||
static struct syscore_ops umwait_syscore_ops = {
|
||||
.resume = umwait_syscore_resume,
|
||||
};
|
||||
|
||||
/* sysfs interface */
|
||||
|
||||
/*
|
||||
* When bit 0 in IA32_UMWAIT_CONTROL MSR is 1, C0.2 is disabled.
|
||||
* Otherwise, C0.2 is enabled.
|
||||
*/
|
||||
static inline bool umwait_ctrl_c02_enabled(u32 ctrl)
|
||||
{
|
||||
return !(ctrl & MSR_IA32_UMWAIT_CONTROL_C02_DISABLE);
|
||||
}
|
||||
|
||||
static inline u32 umwait_ctrl_max_time(u32 ctrl)
|
||||
{
|
||||
return ctrl & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
|
||||
}
|
||||
|
||||
static inline void umwait_update_control(u32 maxtime, bool c02_enable)
|
||||
{
|
||||
u32 ctrl = maxtime & MSR_IA32_UMWAIT_CONTROL_TIME_MASK;
|
||||
|
||||
if (!c02_enable)
|
||||
ctrl |= MSR_IA32_UMWAIT_CONTROL_C02_DISABLE;
|
||||
|
||||
WRITE_ONCE(umwait_control_cached, ctrl);
|
||||
/* Propagate to all CPUs */
|
||||
on_each_cpu(umwait_update_control_msr, NULL, 1);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
enable_c02_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 ctrl = READ_ONCE(umwait_control_cached);
|
||||
|
||||
return sprintf(buf, "%d\n", umwait_ctrl_c02_enabled(ctrl));
|
||||
}
|
||||
|
||||
static ssize_t enable_c02_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
bool c02_enable;
|
||||
u32 ctrl;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &c02_enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&umwait_lock);
|
||||
|
||||
ctrl = READ_ONCE(umwait_control_cached);
|
||||
if (c02_enable != umwait_ctrl_c02_enabled(ctrl))
|
||||
umwait_update_control(ctrl, c02_enable);
|
||||
|
||||
mutex_unlock(&umwait_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_c02);
|
||||
|
||||
static ssize_t
|
||||
max_time_show(struct device *kobj, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 ctrl = READ_ONCE(umwait_control_cached);
|
||||
|
||||
return sprintf(buf, "%u\n", umwait_ctrl_max_time(ctrl));
|
||||
}
|
||||
|
||||
static ssize_t max_time_store(struct device *kobj,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u32 max_time, ctrl;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &max_time);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* bits[1:0] must be zero */
|
||||
if (max_time & ~MSR_IA32_UMWAIT_CONTROL_TIME_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&umwait_lock);
|
||||
|
||||
ctrl = READ_ONCE(umwait_control_cached);
|
||||
if (max_time != umwait_ctrl_max_time(ctrl))
|
||||
umwait_update_control(max_time, umwait_ctrl_c02_enabled(ctrl));
|
||||
|
||||
mutex_unlock(&umwait_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(max_time);
|
||||
|
||||
static struct attribute *umwait_attrs[] = {
|
||||
&dev_attr_enable_c02.attr,
|
||||
&dev_attr_max_time.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group umwait_attr_group = {
|
||||
.attrs = umwait_attrs,
|
||||
.name = "umwait_control",
|
||||
};
|
||||
|
||||
static int __init umwait_init(void)
|
||||
{
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_WAITPKG))
|
||||
return -ENODEV;
|
||||
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "umwait:online",
|
||||
umwait_cpu_online, NULL);
|
||||
|
||||
register_syscore_ops(&umwait_syscore_ops);
|
||||
|
||||
/*
|
||||
* Add umwait control interface. Ignore failure, so at least the
|
||||
* default values are set up in case the machine manages to boot.
|
||||
*/
|
||||
dev = cpu_subsys.dev_root;
|
||||
return sysfs_create_group(&dev->kobj, &umwait_attr_group);
|
||||
}
|
||||
device_initcall(umwait_init);
|
167
arch/x86/kernel/cpu/zhaoxin.c
Normal file
167
arch/x86/kernel/cpu/zhaoxin.c
Normal file
@@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/clock.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define MSR_ZHAOXIN_FCR57 0x00001257
|
||||
|
||||
#define ACE_PRESENT (1 << 6)
|
||||
#define ACE_ENABLED (1 << 7)
|
||||
#define ACE_FCR (1 << 7) /* MSR_ZHAOXIN_FCR */
|
||||
|
||||
#define RNG_PRESENT (1 << 2)
|
||||
#define RNG_ENABLED (1 << 3)
|
||||
#define RNG_ENABLE (1 << 8) /* MSR_ZHAOXIN_RNG */
|
||||
|
||||
#define X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW 0x00200000
|
||||
#define X86_VMX_FEATURE_PROC_CTLS_VNMI 0x00400000
|
||||
#define X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS 0x80000000
|
||||
#define X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC 0x00000001
|
||||
#define X86_VMX_FEATURE_PROC_CTLS2_EPT 0x00000002
|
||||
#define X86_VMX_FEATURE_PROC_CTLS2_VPID 0x00000020
|
||||
|
||||
static void init_zhaoxin_cap(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 lo, hi;
|
||||
|
||||
/* Test for Extended Feature Flags presence */
|
||||
if (cpuid_eax(0xC0000000) >= 0xC0000001) {
|
||||
u32 tmp = cpuid_edx(0xC0000001);
|
||||
|
||||
/* Enable ACE unit, if present and disabled */
|
||||
if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
|
||||
rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||
/* Enable ACE unit */
|
||||
lo |= ACE_FCR;
|
||||
wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||
pr_info("CPU: Enabled ACE h/w crypto\n");
|
||||
}
|
||||
|
||||
/* Enable RNG unit, if present and disabled */
|
||||
if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
|
||||
rdmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||
/* Enable RNG unit */
|
||||
lo |= RNG_ENABLE;
|
||||
wrmsr(MSR_ZHAOXIN_FCR57, lo, hi);
|
||||
pr_info("CPU: Enabled h/w RNG\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Store Extended Feature Flags as word 5 of the CPU
|
||||
* capability bit array
|
||||
*/
|
||||
c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
|
||||
}
|
||||
|
||||
if (c->x86 >= 0x6)
|
||||
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
|
||||
|
||||
cpu_detect_cache_sizes(c);
|
||||
}
|
||||
|
||||
static void early_init_zhaoxin(struct cpuinfo_x86 *c)
|
||||
{
|
||||
if (c->x86 >= 0x6)
|
||||
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||
#ifdef CONFIG_X86_64
|
||||
set_cpu_cap(c, X86_FEATURE_SYSENTER32);
|
||||
#endif
|
||||
if (c->x86_power & (1 << 8)) {
|
||||
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
||||
set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
|
||||
}
|
||||
|
||||
if (c->cpuid_level >= 0x00000001) {
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
|
||||
/*
|
||||
* If HTT (EDX[28]) is set EBX[16:23] contain the number of
|
||||
* apicids which are reserved per package. Store the resulting
|
||||
* shift value for the package management code.
|
||||
*/
|
||||
if (edx & (1U << 28))
|
||||
c->x86_coreid_bits = get_count_order((ebx >> 16) & 0xff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void zhaoxin_detect_vmx_virtcap(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 vmx_msr_low, vmx_msr_high, msr_ctl, msr_ctl2;
|
||||
|
||||
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS, vmx_msr_low, vmx_msr_high);
|
||||
msr_ctl = vmx_msr_high | vmx_msr_low;
|
||||
|
||||
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW)
|
||||
set_cpu_cap(c, X86_FEATURE_TPR_SHADOW);
|
||||
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_VNMI)
|
||||
set_cpu_cap(c, X86_FEATURE_VNMI);
|
||||
if (msr_ctl & X86_VMX_FEATURE_PROC_CTLS_2ND_CTLS) {
|
||||
rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2,
|
||||
vmx_msr_low, vmx_msr_high);
|
||||
msr_ctl2 = vmx_msr_high | vmx_msr_low;
|
||||
if ((msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VIRT_APIC) &&
|
||||
(msr_ctl & X86_VMX_FEATURE_PROC_CTLS_TPR_SHADOW))
|
||||
set_cpu_cap(c, X86_FEATURE_FLEXPRIORITY);
|
||||
if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_EPT)
|
||||
set_cpu_cap(c, X86_FEATURE_EPT);
|
||||
if (msr_ctl2 & X86_VMX_FEATURE_PROC_CTLS2_VPID)
|
||||
set_cpu_cap(c, X86_FEATURE_VPID);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_zhaoxin(struct cpuinfo_x86 *c)
|
||||
{
|
||||
early_init_zhaoxin(c);
|
||||
init_intel_cacheinfo(c);
|
||||
detect_num_cpu_cores(c);
|
||||
#ifdef CONFIG_X86_32
|
||||
detect_ht(c);
|
||||
#endif
|
||||
|
||||
if (c->cpuid_level > 9) {
|
||||
unsigned int eax = cpuid_eax(10);
|
||||
|
||||
/*
|
||||
* Check for version and the number of counters
|
||||
* Version(eax[7:0]) can't be 0;
|
||||
* Counters(eax[15:8]) should be greater than 1;
|
||||
*/
|
||||
if ((eax & 0xff) && (((eax >> 8) & 0xff) > 1))
|
||||
set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
|
||||
}
|
||||
|
||||
if (c->x86 >= 0x6)
|
||||
init_zhaoxin_cap(c);
|
||||
#ifdef CONFIG_X86_64
|
||||
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
|
||||
#endif
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_VMX))
|
||||
zhaoxin_detect_vmx_virtcap(c);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static unsigned int
|
||||
zhaoxin_size_cache(struct cpuinfo_x86 *c, unsigned int size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct cpu_dev zhaoxin_cpu_dev = {
|
||||
.c_vendor = "zhaoxin",
|
||||
.c_ident = { " Shanghai " },
|
||||
.c_early_init = early_init_zhaoxin,
|
||||
.c_init = init_zhaoxin,
|
||||
#ifdef CONFIG_X86_32
|
||||
.legacy_cache_size = zhaoxin_size_cache,
|
||||
#endif
|
||||
.c_x86_vendor = X86_VENDOR_ZHAOXIN,
|
||||
};
|
||||
|
||||
cpu_dev_register(zhaoxin_cpu_dev);
|
@@ -397,22 +397,12 @@ static int putreg(struct task_struct *child,
|
||||
case offsetof(struct user_regs_struct,fs_base):
|
||||
if (value >= TASK_SIZE_MAX)
|
||||
return -EIO;
|
||||
/*
|
||||
* When changing the FS base, use do_arch_prctl_64()
|
||||
* to set the index to zero and to set the base
|
||||
* as requested.
|
||||
*/
|
||||
if (child->thread.fsbase != value)
|
||||
return do_arch_prctl_64(child, ARCH_SET_FS, value);
|
||||
x86_fsbase_write_task(child, value);
|
||||
return 0;
|
||||
case offsetof(struct user_regs_struct,gs_base):
|
||||
/*
|
||||
* Exactly the same here as the %fs handling above.
|
||||
*/
|
||||
if (value >= TASK_SIZE_MAX)
|
||||
return -EIO;
|
||||
if (child->thread.gsbase != value)
|
||||
return do_arch_prctl_64(child, ARCH_SET_GS, value);
|
||||
x86_gsbase_write_task(child, value);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user