mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
Merge branch 'x86/cpu' into x86/core, to resolve conflicts
Conflicts: arch/x86/kernel/cpu/bugs.c Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
2fb8414e64
|
|
@ -1097,7 +1097,7 @@ R: Carlos Bilbao <carlos.bilbao@kernel.org>
|
|||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/arch/x86/amd_hsmp.rst
|
||||
F: arch/x86/include/asm/amd_hsmp.h
|
||||
F: arch/x86/include/asm/amd/hsmp.h
|
||||
F: arch/x86/include/uapi/asm/amd_hsmp.h
|
||||
F: drivers/platform/x86/amd/hsmp/
|
||||
|
||||
|
|
@ -1142,7 +1142,7 @@ M: Mario Limonciello <mario.limonciello@amd.com>
|
|||
M: Yazen Ghannam <yazen.ghannam@amd.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: arch/x86/include/asm/amd_node.h
|
||||
F: arch/x86/include/asm/amd/node.h
|
||||
F: arch/x86/kernel/amd_node.c
|
||||
|
||||
AMD PDS CORE DRIVER
|
||||
|
|
@ -26290,7 +26290,7 @@ R: Ahmed S. Darwish <darwi@linutronix.de>
|
|||
L: x86-cpuid@lists.linux.dev
|
||||
S: Maintained
|
||||
W: https://x86-cpuid.org
|
||||
F: tools/arch/x86/kcpuid/cpuid.csv
|
||||
F: tools/arch/x86/kcpuid/
|
||||
|
||||
X86 ENTRY CODE
|
||||
M: Andy Lutomirski <luto@kernel.org>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ static u32 ibs_caps;
|
|||
#include <linux/hardirq.h>
|
||||
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/amd-ibs.h>
|
||||
#include <asm/amd/ibs.h>
|
||||
|
||||
/* attr.config2 */
|
||||
#define IBS_SW_FILTER_MASK 1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
|
||||
#ifndef _ASM_X86_AMD_HSMP_H_
|
||||
#define _ASM_X86_AMD_HSMP_H_
|
||||
|
||||
|
|
@ -13,4 +12,5 @@ static inline int hsmp_send_message(struct hsmp_message *msg)
|
|||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_ASM_X86_AMD_HSMP_H_*/
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_AMD_IBS_H
|
||||
#define _ASM_X86_AMD_IBS_H
|
||||
|
||||
/*
|
||||
* From PPR Vol 1 for AMD Family 19h Model 01h B1
|
||||
* 55898 Rev 0.35 - Feb 5, 2021
|
||||
|
|
@ -151,3 +154,5 @@ struct perf_ibs_data {
|
|||
};
|
||||
u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
|
||||
};
|
||||
|
||||
#endif /* _ASM_X86_AMD_IBS_H */
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
struct amd_nb_bus_dev_range {
|
||||
u8 bus;
|
||||
|
|
@ -476,11 +476,11 @@
|
|||
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* Clear branch history at syscall entry using SW loop */
|
||||
#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */
|
||||
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
|
||||
#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
|
||||
#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */
|
||||
#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */
|
||||
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */
|
||||
#define X86_FEATURE_PREFER_YMM (21*32 + 8) /* Avoid ZMM registers due to downclocking */
|
||||
#define X86_FEATURE_CLEAR_BHB_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
|
||||
#define X86_FEATURE_AMD_FAST_CPPC (21*32+ 5) /* Fast CPPC */
|
||||
#define X86_FEATURE_AMD_HTR_CORES (21*32+ 6) /* Heterogeneous Core Topology */
|
||||
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32+ 7) /* Workload Classification */
|
||||
#define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */
|
||||
|
||||
/*
|
||||
* BUG word(s)
|
||||
|
|
@ -519,7 +519,7 @@
|
|||
#define X86_BUG_ITLB_MULTIHIT X86_BUG(23) /* "itlb_multihit" CPU may incur MCE during certain page attribute changes */
|
||||
#define X86_BUG_SRBDS X86_BUG(24) /* "srbds" CPU may leak RNG bits if not mitigated */
|
||||
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* "mmio_stale_data" CPU is affected by Processor MMIO Stale Data vulnerabilities */
|
||||
#define X86_BUG_MMIO_UNKNOWN X86_BUG(26) /* "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
|
||||
/* unused, was #define X86_BUG_MMIO_UNKNOWN X86_BUG(26) "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
|
||||
#define X86_BUG_RETBLEED X86_BUG(27) /* "retbleed" CPU is affected by RETBleed */
|
||||
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* "eibrs_pbrsb" EIBRS is vulnerable to Post Barrier RSB Predictions */
|
||||
#define X86_BUG_SMT_RSB X86_BUG(29) /* "smt_rsb" CPU is vulnerable to Cross-Thread Return Address Predictions */
|
||||
|
|
@ -527,10 +527,10 @@
|
|||
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* "tdx_pw_mce" CPU may incur #MC if non-TD software does partial write to TDX private memory */
|
||||
|
||||
/* BUG word 2 */
|
||||
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* "srso" AMD SRSO bug */
|
||||
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* "div0" AMD DIV0 speculation bug */
|
||||
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
|
||||
#define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */
|
||||
#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */
|
||||
#define X86_BUG_SPECTRE_V2_USER X86_BUG(1*32 + 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
|
||||
#define X86_BUG_SRSO X86_BUG( 1*32+ 0) /* "srso" AMD SRSO bug */
|
||||
#define X86_BUG_DIV0 X86_BUG( 1*32+ 1) /* "div0" AMD DIV0 speculation bug */
|
||||
#define X86_BUG_RFDS X86_BUG( 1*32+ 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
|
||||
#define X86_BUG_BHI X86_BUG( 1*32+ 3) /* "bhi" CPU is affected by Branch History Injection */
|
||||
#define X86_BUG_IBPB_NO_RET X86_BUG( 1*32+ 4) /* "ibpb_no_ret" IBPB omits return target predictions */
|
||||
#define X86_BUG_SPECTRE_V2_USER X86_BUG( 1*32+ 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
|
||||
#endif /* _ASM_X86_CPUFEATURES_H */
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@
|
|||
#define _ASM_X86_CPUID_H
|
||||
|
||||
#include <asm/cpuid/api.h>
|
||||
#include <asm/cpuid/leaf_0x2_api.h>
|
||||
|
||||
#endif /* _ASM_X86_CPUID_H */
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ static inline void native_cpuid(u32 *eax, u32 *ebx,
|
|||
}
|
||||
|
||||
#define NATIVE_CPUID_REG(reg) \
|
||||
static inline u32 native_cpuid_##reg(u32 op) \
|
||||
static inline u32 native_cpuid_##reg(u32 op) \
|
||||
{ \
|
||||
u32 eax = op, ebx, ecx = 0, edx; \
|
||||
u32 eax = op, ebx, ecx = 0, edx; \
|
||||
\
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx); \
|
||||
\
|
||||
|
|
@ -207,4 +207,13 @@ static inline u32 hypervisor_cpuid_base(const char *sig, u32 leaves)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPUID(0x80000006) parsing helpers
|
||||
*/
|
||||
|
||||
static inline bool cpuid_amd_hygon_has_l3_cache(void)
|
||||
{
|
||||
return cpuid_edx(0x80000006);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_CPUID_API_H */
|
||||
|
|
|
|||
73
arch/x86/include/asm/cpuid/leaf_0x2_api.h
Normal file
73
arch/x86/include/asm/cpuid/leaf_0x2_api.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUID_LEAF_0x2_API_H
|
||||
#define _ASM_X86_CPUID_LEAF_0x2_API_H
|
||||
|
||||
#include <asm/cpuid/api.h>
|
||||
#include <asm/cpuid/types.h>
|
||||
|
||||
/**
|
||||
* cpuid_get_leaf_0x2_regs() - Return sanitized leaf 0x2 register output
|
||||
* @regs: Output parameter
|
||||
*
|
||||
* Query CPUID leaf 0x2 and store its output in @regs. Force set any
|
||||
* invalid 1-byte descriptor returned by the hardware to zero (the NULL
|
||||
* cache/TLB descriptor) before returning it to the caller.
|
||||
*
|
||||
* Use for_each_leaf_0x2_entry() to iterate over the register output in
|
||||
* parsed form.
|
||||
*/
|
||||
static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
|
||||
{
|
||||
cpuid_leaf(0x2, regs);
|
||||
|
||||
/*
|
||||
* All Intel CPUs must report an iteration count of 1. In case
|
||||
* of bogus hardware, treat all returned descriptors as NULL.
|
||||
*/
|
||||
if (regs->desc[0] != 0x01) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
regs->regv[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The most significant bit (MSB) of each register must be clear.
|
||||
* If a register is invalid, replace its descriptors with NULL.
|
||||
*/
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (regs->reg[i].invalid)
|
||||
regs->regv[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for_each_leaf_0x2_entry() - Iterator for parsed leaf 0x2 descriptors
|
||||
* @regs: Leaf 0x2 register output, returned by cpuid_get_leaf_0x2_regs()
|
||||
* @__ptr: u8 pointer, for macro internal use only
|
||||
* @entry: Pointer to parsed descriptor information at each iteration
|
||||
*
|
||||
* Loop over the 1-byte descriptors in the passed leaf 0x2 output registers
|
||||
* @regs. Provide the parsed information for each descriptor through @entry.
|
||||
*
|
||||
* To handle cache-specific descriptors, switch on @entry->c_type. For TLB
|
||||
* descriptors, switch on @entry->t_type.
|
||||
*
|
||||
* Example usage for cache descriptors::
|
||||
*
|
||||
* const struct leaf_0x2_table *entry;
|
||||
* union leaf_0x2_regs regs;
|
||||
* u8 *ptr;
|
||||
*
|
||||
* cpuid_get_leaf_0x2_regs(®s);
|
||||
* for_each_leaf_0x2_entry(regs, ptr, entry) {
|
||||
* switch (entry->c_type) {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
#define for_each_leaf_0x2_entry(regs, __ptr, entry) \
|
||||
for (__ptr = &(regs).desc[1]; \
|
||||
__ptr < &(regs).desc[16] && (entry = &cpuid_0x2_table[*__ptr]); \
|
||||
__ptr++)
|
||||
|
||||
#endif /* _ASM_X86_CPUID_LEAF_0x2_API_H */
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef _ASM_X86_CPUID_TYPES_H
|
||||
#define _ASM_X86_CPUID_TYPES_H
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
|
|
@ -29,4 +30,99 @@ enum cpuid_regs_idx {
|
|||
#define CPUID_LEAF_FREQ 0x16
|
||||
#define CPUID_LEAF_TILE 0x1d
|
||||
|
||||
/*
|
||||
* Types for CPUID(0x2) parsing
|
||||
* Check <asm/cpuid/leaf_0x2_api.h>
|
||||
*/
|
||||
|
||||
struct leaf_0x2_reg {
|
||||
u32 : 31,
|
||||
invalid : 1;
|
||||
};
|
||||
|
||||
union leaf_0x2_regs {
|
||||
struct leaf_0x2_reg reg[4];
|
||||
u32 regv[4];
|
||||
u8 desc[16];
|
||||
};
|
||||
|
||||
/*
|
||||
* Leaf 0x2 1-byte descriptors' cache types
|
||||
* To be used for their mappings at cpuid_0x2_table[]
|
||||
*
|
||||
* Start at 1 since type 0 is reserved for HW byte descriptors which are
|
||||
* not recognized by the kernel; i.e., those without an explicit mapping.
|
||||
*/
|
||||
enum _cache_table_type {
|
||||
CACHE_L1_INST = 1,
|
||||
CACHE_L1_DATA,
|
||||
CACHE_L2,
|
||||
CACHE_L3
|
||||
/* Adjust __TLB_TABLE_TYPE_BEGIN before adding more types */
|
||||
} __packed;
|
||||
#ifndef __CHECKER__
|
||||
static_assert(sizeof(enum _cache_table_type) == 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ensure that leaf 0x2 cache and TLB type values do not intersect,
|
||||
* since they share the same type field at struct cpuid_0x2_table.
|
||||
*/
|
||||
#define __TLB_TABLE_TYPE_BEGIN (CACHE_L3 + 1)
|
||||
|
||||
/*
|
||||
* Leaf 0x2 1-byte descriptors' TLB types
|
||||
* To be used for their mappings at cpuid_0x2_table[]
|
||||
*/
|
||||
enum _tlb_table_type {
|
||||
TLB_INST_4K = __TLB_TABLE_TYPE_BEGIN,
|
||||
TLB_INST_4M,
|
||||
TLB_INST_2M_4M,
|
||||
TLB_INST_ALL,
|
||||
|
||||
TLB_DATA_4K,
|
||||
TLB_DATA_4M,
|
||||
TLB_DATA_2M_4M,
|
||||
TLB_DATA_4K_4M,
|
||||
TLB_DATA_1G,
|
||||
TLB_DATA_1G_2M_4M,
|
||||
|
||||
TLB_DATA0_4K,
|
||||
TLB_DATA0_4M,
|
||||
TLB_DATA0_2M_4M,
|
||||
|
||||
STLB_4K,
|
||||
STLB_4K_2M,
|
||||
} __packed;
|
||||
#ifndef __CHECKER__
|
||||
static_assert(sizeof(enum _tlb_table_type) == 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Combined parsing table for leaf 0x2 cache and TLB descriptors.
|
||||
*/
|
||||
|
||||
struct leaf_0x2_table {
|
||||
union {
|
||||
enum _cache_table_type c_type;
|
||||
enum _tlb_table_type t_type;
|
||||
};
|
||||
union {
|
||||
short c_size;
|
||||
short entries;
|
||||
};
|
||||
};
|
||||
|
||||
extern const struct leaf_0x2_table cpuid_0x2_table[256];
|
||||
|
||||
/*
|
||||
* All of leaf 0x2's one-byte TLB descriptors implies the same number of entries
|
||||
* for their respective TLB types. TLB descriptor 0x63 is an exception: it
|
||||
* implies 4 dTLB entries for 1GB pages and 32 dTLB entries for 2MB or 4MB pages.
|
||||
*
|
||||
* Encode that descriptor's dTLB entry count for 2MB/4MB pages here, as the entry
|
||||
* count for dTLB 1GB pages is already encoded at the cpuid_0x2_table[]'s mapping.
|
||||
*/
|
||||
#define TLB_0x63_2M_4M_ENTRIES 32
|
||||
|
||||
#endif /* _ASM_X86_CPUID_TYPES_H */
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@
|
|||
.endm
|
||||
|
||||
.macro CLEAR_BRANCH_HISTORY_VMEXIT
|
||||
ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT
|
||||
ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_VMEXIT
|
||||
.endm
|
||||
#else
|
||||
#define CLEAR_BRANCH_HISTORY
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
|
|||
}
|
||||
|
||||
/* detect if running on heterogeneous design */
|
||||
if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES)) {
|
||||
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) {
|
||||
switch (core_type) {
|
||||
case TOPO_CPU_TYPE_UNKNOWN:
|
||||
pr_warn("Undefined core type found for cpu %d\n", cpu);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
#include <asm/gart.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/x86_init.h>
|
||||
|
||||
static unsigned long iommu_bus_base; /* GART remapping area (physical) */
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <asm/amd_nb.h>
|
||||
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/cpuid.h>
|
||||
|
||||
static u32 *flush_words;
|
||||
|
||||
|
|
@ -91,10 +93,7 @@ static int amd_cache_northbridges(void)
|
|||
if (amd_gart_present())
|
||||
amd_northbridges.flags |= AMD_NB_GART;
|
||||
|
||||
/*
|
||||
* Check for L3 cache presence.
|
||||
*/
|
||||
if (!cpuid_edx(0x80000006))
|
||||
if (!cpuid_amd_hygon_has_l3_cache())
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
/*
|
||||
* AMD Nodes are a physical collection of I/O devices within an SoC. There can be one
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include <asm/gart.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <linux/crash_dump.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ obj-y += rdrand.o
|
|||
obj-y += match.o
|
||||
obj-y += bugs.o
|
||||
obj-y += aperfmperf.o
|
||||
obj-y += cpuid-deps.o
|
||||
obj-y += cpuid-deps.o cpuid_0x2_table.o
|
||||
obj-y += umwait.o
|
||||
obj-y += capflags.o powerflags.o
|
||||
|
||||
|
|
@ -38,6 +38,9 @@ obj-y += intel.o tsx.o
|
|||
obj-$(CONFIG_PM) += intel_epb.o
|
||||
endif
|
||||
obj-$(CONFIG_CPU_SUP_AMD) += amd.o
|
||||
ifeq ($(CONFIG_AMD_NB)$(CONFIG_SYSFS),yy)
|
||||
obj-y += amd_cache_disable.o
|
||||
endif
|
||||
obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
|
||||
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||
obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
|
||||
|
|
|
|||
301
arch/x86/kernel/cpu/amd_cache_disable.c
Normal file
301
arch/x86/kernel/cpu/amd_cache_disable.c
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* AMD L3 cache_disable_{0,1} sysfs handling
|
||||
* Documentation/ABI/testing/sysfs-devices-system-cpu
|
||||
*/
|
||||
|
||||
#include <linux/cacheinfo.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <asm/amd/nb.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/*
|
||||
* L3 cache descriptors
|
||||
*/
|
||||
static void amd_calc_l3_indices(struct amd_northbridge *nb)
|
||||
{
|
||||
struct amd_l3_cache *l3 = &nb->l3_cache;
|
||||
unsigned int sc0, sc1, sc2, sc3;
|
||||
u32 val = 0;
|
||||
|
||||
pci_read_config_dword(nb->misc, 0x1C4, &val);
|
||||
|
||||
/* calculate subcache sizes */
|
||||
l3->subcaches[0] = sc0 = !(val & BIT(0));
|
||||
l3->subcaches[1] = sc1 = !(val & BIT(4));
|
||||
|
||||
if (boot_cpu_data.x86 == 0x15) {
|
||||
l3->subcaches[0] = sc0 += !(val & BIT(1));
|
||||
l3->subcaches[1] = sc1 += !(val & BIT(5));
|
||||
}
|
||||
|
||||
l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9));
|
||||
l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
|
||||
|
||||
l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether a slot used for disabling an L3 index is occupied.
|
||||
* @l3: L3 cache descriptor
|
||||
* @slot: slot number (0..1)
|
||||
*
|
||||
* @returns: the disabled index if used or negative value if slot free.
|
||||
*/
|
||||
static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned int slot)
|
||||
{
|
||||
unsigned int reg = 0;
|
||||
|
||||
pci_read_config_dword(nb->misc, 0x1BC + slot * 4, ®);
|
||||
|
||||
/* check whether this slot is activated already */
|
||||
if (reg & (3UL << 30))
|
||||
return reg & 0xfff;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t show_cache_disable(struct cacheinfo *ci, char *buf, unsigned int slot)
|
||||
{
|
||||
int index;
|
||||
struct amd_northbridge *nb = ci->priv;
|
||||
|
||||
index = amd_get_l3_disable_slot(nb, slot);
|
||||
if (index >= 0)
|
||||
return sysfs_emit(buf, "%d\n", index);
|
||||
|
||||
return sysfs_emit(buf, "FREE\n");
|
||||
}
|
||||
|
||||
#define SHOW_CACHE_DISABLE(slot) \
|
||||
static ssize_t \
|
||||
cache_disable_##slot##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct cacheinfo *ci = dev_get_drvdata(dev); \
|
||||
return show_cache_disable(ci, buf, slot); \
|
||||
}
|
||||
|
||||
SHOW_CACHE_DISABLE(0)
|
||||
SHOW_CACHE_DISABLE(1)
|
||||
|
||||
static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu,
|
||||
unsigned int slot, unsigned long idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
idx |= BIT(30);
|
||||
|
||||
/*
|
||||
* disable index in all 4 subcaches
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
u32 reg = idx | (i << 20);
|
||||
|
||||
if (!nb->l3_cache.subcaches[i])
|
||||
continue;
|
||||
|
||||
pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
|
||||
|
||||
/*
|
||||
* We need to WBINVD on a core on the node containing the L3
|
||||
* cache which indices we disable therefore a simple wbinvd()
|
||||
* is not sufficient.
|
||||
*/
|
||||
wbinvd_on_cpu(cpu);
|
||||
|
||||
reg |= BIT(31);
|
||||
pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* disable a L3 cache index by using a disable-slot
|
||||
*
|
||||
* @l3: L3 cache descriptor
|
||||
* @cpu: A CPU on the node containing the L3 cache
|
||||
* @slot: slot number (0..1)
|
||||
* @index: index to disable
|
||||
*
|
||||
* @return: 0 on success, error status on failure
|
||||
*/
|
||||
static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu,
|
||||
unsigned int slot, unsigned long index)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* check if @slot is already used or the index is already disabled */
|
||||
ret = amd_get_l3_disable_slot(nb, slot);
|
||||
if (ret >= 0)
|
||||
return -EEXIST;
|
||||
|
||||
if (index > nb->l3_cache.indices)
|
||||
return -EINVAL;
|
||||
|
||||
/* check whether the other slot has disabled the same index already */
|
||||
if (index == amd_get_l3_disable_slot(nb, !slot))
|
||||
return -EEXIST;
|
||||
|
||||
amd_l3_disable_index(nb, cpu, slot, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_cache_disable(struct cacheinfo *ci, const char *buf,
|
||||
size_t count, unsigned int slot)
|
||||
{
|
||||
struct amd_northbridge *nb = ci->priv;
|
||||
unsigned long val = 0;
|
||||
int cpu, err = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
cpu = cpumask_first(&ci->shared_cpu_map);
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = amd_set_l3_disable_slot(nb, cpu, slot, val);
|
||||
if (err) {
|
||||
if (err == -EEXIST)
|
||||
pr_warn("L3 slot %d in use/index already disabled!\n",
|
||||
slot);
|
||||
return err;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#define STORE_CACHE_DISABLE(slot) \
|
||||
static ssize_t \
|
||||
cache_disable_##slot##_store(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct cacheinfo *ci = dev_get_drvdata(dev); \
|
||||
return store_cache_disable(ci, buf, count, slot); \
|
||||
}
|
||||
|
||||
STORE_CACHE_DISABLE(0)
|
||||
STORE_CACHE_DISABLE(1)
|
||||
|
||||
static ssize_t subcaches_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct cacheinfo *ci = dev_get_drvdata(dev);
|
||||
int cpu = cpumask_first(&ci->shared_cpu_map);
|
||||
|
||||
return sysfs_emit(buf, "%x\n", amd_get_subcaches(cpu));
|
||||
}
|
||||
|
||||
static ssize_t subcaches_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cacheinfo *ci = dev_get_drvdata(dev);
|
||||
int cpu = cpumask_first(&ci->shared_cpu_map);
|
||||
unsigned long val;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (kstrtoul(buf, 16, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (amd_set_subcaches(cpu, val))
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(cache_disable_0);
|
||||
static DEVICE_ATTR_RW(cache_disable_1);
|
||||
static DEVICE_ATTR_RW(subcaches);
|
||||
|
||||
static umode_t cache_private_attrs_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int unused)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct cacheinfo *ci = dev_get_drvdata(dev);
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
if (!ci->priv)
|
||||
return 0;
|
||||
|
||||
if ((attr == &dev_attr_subcaches.attr) &&
|
||||
amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
|
||||
return mode;
|
||||
|
||||
if ((attr == &dev_attr_cache_disable_0.attr ||
|
||||
attr == &dev_attr_cache_disable_1.attr) &&
|
||||
amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
|
||||
return mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute_group cache_private_group = {
|
||||
.is_visible = cache_private_attrs_is_visible,
|
||||
};
|
||||
|
||||
static void init_amd_l3_attrs(void)
|
||||
{
|
||||
static struct attribute **amd_l3_attrs;
|
||||
int n = 1;
|
||||
|
||||
if (amd_l3_attrs) /* already initialized */
|
||||
return;
|
||||
|
||||
if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
|
||||
n += 2;
|
||||
if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
|
||||
n += 1;
|
||||
|
||||
amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
|
||||
if (!amd_l3_attrs)
|
||||
return;
|
||||
|
||||
n = 0;
|
||||
if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
|
||||
amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
|
||||
amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
|
||||
}
|
||||
if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
|
||||
amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
|
||||
|
||||
cache_private_group.attrs = amd_l3_attrs;
|
||||
}
|
||||
|
||||
const struct attribute_group *cache_get_priv_group(struct cacheinfo *ci)
|
||||
{
|
||||
struct amd_northbridge *nb = ci->priv;
|
||||
|
||||
if (ci->level < 3 || !nb)
|
||||
return NULL;
|
||||
|
||||
if (nb && nb->l3_cache.indices)
|
||||
init_amd_l3_attrs();
|
||||
|
||||
return &cache_private_group;
|
||||
}
|
||||
|
||||
struct amd_northbridge *amd_init_l3_cache(int index)
|
||||
{
|
||||
struct amd_northbridge *nb;
|
||||
int node;
|
||||
|
||||
/* only for L3, and not in virtualized environments */
|
||||
if (index < 3)
|
||||
return NULL;
|
||||
|
||||
node = topology_amd_node_id(smp_processor_id());
|
||||
nb = node_to_amd_nb(node);
|
||||
if (nb && !nb->l3_cache.indices)
|
||||
amd_calc_l3_indices(nb);
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
|
@ -551,7 +551,6 @@ static const char * const mmio_strings[] = {
|
|||
static void __init mmio_select_mitigation(void)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
|
||||
boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN) ||
|
||||
cpu_mitigations_off()) {
|
||||
mmio_mitigation = MMIO_MITIGATION_OFF;
|
||||
return;
|
||||
|
|
@ -1880,13 +1879,13 @@ static void __init bhi_apply_mitigation(void)
|
|||
|
||||
if (bhi_mitigation == BHI_MITIGATION_VMEXIT_ONLY) {
|
||||
pr_info("Spectre BHI mitigation: SW BHB clearing on VM exit only\n");
|
||||
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT);
|
||||
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_VMEXIT);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("Spectre BHI mitigation: SW BHB clearing on syscall and VM exit\n");
|
||||
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP);
|
||||
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT);
|
||||
setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_VMEXIT);
|
||||
}
|
||||
|
||||
static void __init spectre_v2_select_mitigation(void)
|
||||
|
|
@ -2947,9 +2946,6 @@ static ssize_t tsx_async_abort_show_state(char *buf)
|
|||
|
||||
static ssize_t mmio_stale_data_show_state(char *buf)
|
||||
{
|
||||
if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
|
||||
return sysfs_emit(buf, "Unknown: No mitigations\n");
|
||||
|
||||
if (mmio_mitigation == MMIO_MITIGATION_OFF)
|
||||
return sysfs_emit(buf, "%s\n", mmio_strings[mmio_mitigation]);
|
||||
|
||||
|
|
@ -3025,7 +3021,7 @@ static const char *spectre_bhi_state(void)
|
|||
!boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
|
||||
rrsba_disabled)
|
||||
return "; BHI: Retpoline";
|
||||
else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT))
|
||||
else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_VMEXIT))
|
||||
return "; BHI: Vulnerable, KVM: SW loop";
|
||||
|
||||
return "; BHI: Vulnerable";
|
||||
|
|
@ -3134,7 +3130,6 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
|
|||
return srbds_show_state(buf);
|
||||
|
||||
case X86_BUG_MMIO_STALE_DATA:
|
||||
case X86_BUG_MMIO_UNKNOWN:
|
||||
return mmio_stale_data_show_state(buf);
|
||||
|
||||
case X86_BUG_RETBLEED:
|
||||
|
|
@ -3203,10 +3198,7 @@ ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *
|
|||
|
||||
ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
|
||||
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_UNKNOWN);
|
||||
else
|
||||
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
|
||||
return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
|
||||
}
|
||||
|
||||
ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1006,17 +1006,18 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
|||
c->x86_capability[CPUID_D_1_EAX] = eax;
|
||||
}
|
||||
|
||||
/* AMD-defined flags: level 0x80000001 */
|
||||
/*
|
||||
* Check if extended CPUID leaves are implemented: Max extended
|
||||
* CPUID leaf must be in the 0x80000001-0x8000ffff range.
|
||||
*/
|
||||
eax = cpuid_eax(0x80000000);
|
||||
c->extended_cpuid_level = eax;
|
||||
c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
|
||||
|
||||
if ((eax & 0xffff0000) == 0x80000000) {
|
||||
if (eax >= 0x80000001) {
|
||||
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
|
||||
if (c->extended_cpuid_level >= 0x80000001) {
|
||||
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
c->x86_capability[CPUID_8000_0001_ECX] = ecx;
|
||||
c->x86_capability[CPUID_8000_0001_EDX] = edx;
|
||||
}
|
||||
c->x86_capability[CPUID_8000_0001_ECX] = ecx;
|
||||
c->x86_capability[CPUID_8000_0001_EDX] = edx;
|
||||
}
|
||||
|
||||
if (c->extended_cpuid_level >= 0x80000007) {
|
||||
|
|
@ -1403,15 +1404,10 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
|
|||
* Affected CPU list is generally enough to enumerate the vulnerability,
|
||||
* but for virtualization case check for ARCH_CAP MSR bits also, VMM may
|
||||
* not want the guest to enumerate the bug.
|
||||
*
|
||||
* Set X86_BUG_MMIO_UNKNOWN for CPUs that are neither in the blacklist,
|
||||
* nor in the whitelist and also don't enumerate MSR ARCH_CAP MMIO bits.
|
||||
*/
|
||||
if (!arch_cap_mmio_immune(x86_arch_cap_msr)) {
|
||||
if (cpu_matches(cpu_vuln_blacklist, MMIO))
|
||||
setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
|
||||
else if (!cpu_matches(cpu_vuln_whitelist, NO_MMIO))
|
||||
setup_force_cpu_bug(X86_BUG_MMIO_UNKNOWN);
|
||||
}
|
||||
|
||||
if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,15 @@ extern void check_null_seg_clears_base(struct cpuinfo_x86 *c);
|
|||
void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, u16 die_id);
|
||||
void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c);
|
||||
|
||||
#if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
|
||||
struct amd_northbridge *amd_init_l3_cache(int index);
|
||||
#else
|
||||
static inline struct amd_northbridge *amd_init_l3_cache(int index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int aperfmperf_get_khz(int cpu);
|
||||
void cpu_select_mitigations(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -82,8 +82,12 @@ static const struct cpuid_dep cpuid_deps[] = {
|
|||
{ X86_FEATURE_XFD, X86_FEATURE_XSAVES },
|
||||
{ X86_FEATURE_XFD, X86_FEATURE_XGETBV1 },
|
||||
{ X86_FEATURE_AMX_TILE, X86_FEATURE_XFD },
|
||||
{ X86_FEATURE_AMX_FP16, X86_FEATURE_AMX_TILE },
|
||||
{ X86_FEATURE_AMX_BF16, X86_FEATURE_AMX_TILE },
|
||||
{ X86_FEATURE_AMX_INT8, X86_FEATURE_AMX_TILE },
|
||||
{ X86_FEATURE_SHSTK, X86_FEATURE_XSAVES },
|
||||
{ X86_FEATURE_FRED, X86_FEATURE_LKGS },
|
||||
{ X86_FEATURE_SPEC_CTRL_SSBD, X86_FEATURE_SPEC_CTRL },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
128
arch/x86/kernel/cpu/cpuid_0x2_table.c
Normal file
128
arch/x86/kernel/cpu/cpuid_0x2_table.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <asm/cpuid/types.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define CACHE_ENTRY(_desc, _type, _size) \
|
||||
[_desc] = { \
|
||||
.c_type = (_type), \
|
||||
.c_size = (_size) / SZ_1K, \
|
||||
}
|
||||
|
||||
#define TLB_ENTRY(_desc, _type, _entries) \
|
||||
[_desc] = { \
|
||||
.t_type = (_type), \
|
||||
.entries = (_entries), \
|
||||
}
|
||||
|
||||
const struct leaf_0x2_table cpuid_0x2_table[256] = {
|
||||
CACHE_ENTRY(0x06, CACHE_L1_INST, SZ_8K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x08, CACHE_L1_INST, SZ_16K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x09, CACHE_L1_INST, SZ_32K ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x0a, CACHE_L1_DATA, SZ_8K ), /* 2 way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x0c, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x0d, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x0e, CACHE_L1_DATA, SZ_24K ), /* 6-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x21, CACHE_L2, SZ_256K ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x22, CACHE_L3, SZ_512K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x23, CACHE_L3, SZ_1M ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x25, CACHE_L3, SZ_2M ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x29, CACHE_L3, SZ_4M ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x2c, CACHE_L1_DATA, SZ_32K ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x30, CACHE_L1_INST, SZ_32K ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x39, CACHE_L2, SZ_128K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3a, CACHE_L2, SZ_192K ), /* 6-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3b, CACHE_L2, SZ_128K ), /* 2-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3c, CACHE_L2, SZ_256K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3d, CACHE_L2, SZ_384K ), /* 6-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3e, CACHE_L2, SZ_512K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x3f, CACHE_L2, SZ_256K ), /* 2-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x41, CACHE_L2, SZ_128K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x42, CACHE_L2, SZ_256K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x43, CACHE_L2, SZ_512K ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x44, CACHE_L2, SZ_1M ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x45, CACHE_L2, SZ_2M ), /* 4-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x46, CACHE_L3, SZ_4M ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x47, CACHE_L3, SZ_8M ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x48, CACHE_L2, SZ_3M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x49, CACHE_L3, SZ_4M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x4a, CACHE_L3, SZ_6M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x4b, CACHE_L3, SZ_8M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x4c, CACHE_L3, SZ_12M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x4d, CACHE_L3, SZ_16M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x4e, CACHE_L2, SZ_6M ), /* 24-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x60, CACHE_L1_DATA, SZ_16K ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x66, CACHE_L1_DATA, SZ_8K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x67, CACHE_L1_DATA, SZ_16K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x68, CACHE_L1_DATA, SZ_32K ), /* 4-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x78, CACHE_L2, SZ_1M ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x79, CACHE_L2, SZ_128K ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x7a, CACHE_L2, SZ_256K ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x7b, CACHE_L2, SZ_512K ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x7c, CACHE_L2, SZ_1M ), /* 8-way set assoc, sectored cache, 64 byte line size */
|
||||
CACHE_ENTRY(0x7d, CACHE_L2, SZ_2M ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x7f, CACHE_L2, SZ_512K ), /* 2-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x80, CACHE_L2, SZ_512K ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x82, CACHE_L2, SZ_256K ), /* 8-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x83, CACHE_L2, SZ_512K ), /* 8-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x84, CACHE_L2, SZ_1M ), /* 8-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x85, CACHE_L2, SZ_2M ), /* 8-way set assoc, 32 byte line size */
|
||||
CACHE_ENTRY(0x86, CACHE_L2, SZ_512K ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0x87, CACHE_L2, SZ_1M ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd0, CACHE_L3, SZ_512K ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd1, CACHE_L3, SZ_1M ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd2, CACHE_L3, SZ_2M ), /* 4-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd6, CACHE_L3, SZ_1M ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd7, CACHE_L3, SZ_2M ), /* 8-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xd8, CACHE_L3, SZ_4M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xdc, CACHE_L3, SZ_2M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xdd, CACHE_L3, SZ_4M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xde, CACHE_L3, SZ_8M ), /* 12-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xe2, CACHE_L3, SZ_2M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xe3, CACHE_L3, SZ_4M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xe4, CACHE_L3, SZ_8M ), /* 16-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xea, CACHE_L3, SZ_12M ), /* 24-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xeb, CACHE_L3, SZ_18M ), /* 24-way set assoc, 64 byte line size */
|
||||
CACHE_ENTRY(0xec, CACHE_L3, SZ_24M ), /* 24-way set assoc, 64 byte line size */
|
||||
|
||||
TLB_ENTRY( 0x01, TLB_INST_4K, 32 ), /* TLB_INST 4 KByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x02, TLB_INST_4M, 2 ), /* TLB_INST 4 MByte pages, full associative */
|
||||
TLB_ENTRY( 0x03, TLB_DATA_4K, 64 ), /* TLB_DATA 4 KByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x04, TLB_DATA_4M, 8 ), /* TLB_DATA 4 MByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x05, TLB_DATA_4M, 32 ), /* TLB_DATA 4 MByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x0b, TLB_INST_4M, 4 ), /* TLB_INST 4 MByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x4f, TLB_INST_4K, 32 ), /* TLB_INST 4 KByte pages */
|
||||
TLB_ENTRY( 0x50, TLB_INST_ALL, 64 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
TLB_ENTRY( 0x51, TLB_INST_ALL, 128 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
TLB_ENTRY( 0x52, TLB_INST_ALL, 256 ), /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
TLB_ENTRY( 0x55, TLB_INST_2M_4M, 7 ), /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
|
||||
TLB_ENTRY( 0x56, TLB_DATA0_4M, 16 ), /* TLB_DATA0 4 MByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x57, TLB_DATA0_4K, 16 ), /* TLB_DATA0 4 KByte pages, 4-way associative */
|
||||
TLB_ENTRY( 0x59, TLB_DATA0_4K, 16 ), /* TLB_DATA0 4 KByte pages, fully associative */
|
||||
TLB_ENTRY( 0x5a, TLB_DATA0_2M_4M, 32 ), /* TLB_DATA0 2-MByte or 4 MByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0x5b, TLB_DATA_4K_4M, 64 ), /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
TLB_ENTRY( 0x5c, TLB_DATA_4K_4M, 128 ), /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
TLB_ENTRY( 0x5d, TLB_DATA_4K_4M, 256 ), /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
TLB_ENTRY( 0x61, TLB_INST_4K, 48 ), /* TLB_INST 4 KByte pages, full associative */
|
||||
TLB_ENTRY( 0x63, TLB_DATA_1G_2M_4M, 4 ), /* TLB_DATA 1 GByte pages, 4-way set associative
|
||||
* (plus 32 entries TLB_DATA 2 MByte or 4 MByte pages, not encoded here) */
|
||||
TLB_ENTRY( 0x6b, TLB_DATA_4K, 256 ), /* TLB_DATA 4 KByte pages, 8-way associative */
|
||||
TLB_ENTRY( 0x6c, TLB_DATA_2M_4M, 128 ), /* TLB_DATA 2 MByte or 4 MByte pages, 8-way associative */
|
||||
TLB_ENTRY( 0x6d, TLB_DATA_1G, 16 ), /* TLB_DATA 1 GByte pages, fully associative */
|
||||
TLB_ENTRY( 0x76, TLB_INST_2M_4M, 8 ), /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
|
||||
TLB_ENTRY( 0xb0, TLB_INST_4K, 128 ), /* TLB_INST 4 KByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0xb1, TLB_INST_2M_4M, 4 ), /* TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries */
|
||||
TLB_ENTRY( 0xb2, TLB_INST_4K, 64 ), /* TLB_INST 4KByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0xb3, TLB_DATA_4K, 128 ), /* TLB_DATA 4 KByte pages, 4-way set associative */
|
||||
TLB_ENTRY( 0xb4, TLB_DATA_4K, 256 ), /* TLB_DATA 4 KByte pages, 4-way associative */
|
||||
TLB_ENTRY( 0xb5, TLB_INST_4K, 64 ), /* TLB_INST 4 KByte pages, 8-way set associative */
|
||||
TLB_ENTRY( 0xb6, TLB_INST_4K, 128 ), /* TLB_INST 4 KByte pages, 8-way set associative */
|
||||
TLB_ENTRY( 0xba, TLB_DATA_4K, 64 ), /* TLB_DATA 4 KByte pages, 4-way associative */
|
||||
TLB_ENTRY( 0xc0, TLB_DATA_4K_4M, 8 ), /* TLB_DATA 4 KByte and 4 MByte pages, 4-way associative */
|
||||
TLB_ENTRY( 0xc1, STLB_4K_2M, 1024 ), /* STLB 4 KByte and 2 MByte pages, 8-way associative */
|
||||
TLB_ENTRY( 0xc2, TLB_DATA_2M_4M, 16 ), /* TLB_DATA 2 MByte/4MByte pages, 4-way associative */
|
||||
TLB_ENTRY( 0xca, STLB_4K, 512 ), /* STLB 4 KByte pages, 4-way associative */
|
||||
};
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/minmax.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#include <linux/topology.h>
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpuid.h>
|
||||
#include <asm/hwcap2.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/microcode.h>
|
||||
|
|
@ -646,103 +648,11 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
|
|||
}
|
||||
#endif
|
||||
|
||||
#define TLB_INST_4K 0x01
|
||||
#define TLB_INST_4M 0x02
|
||||
#define TLB_INST_2M_4M 0x03
|
||||
|
||||
#define TLB_INST_ALL 0x05
|
||||
#define TLB_INST_1G 0x06
|
||||
|
||||
#define TLB_DATA_4K 0x11
|
||||
#define TLB_DATA_4M 0x12
|
||||
#define TLB_DATA_2M_4M 0x13
|
||||
#define TLB_DATA_4K_4M 0x14
|
||||
|
||||
#define TLB_DATA_1G 0x16
|
||||
#define TLB_DATA_1G_2M_4M 0x17
|
||||
|
||||
#define TLB_DATA0_4K 0x21
|
||||
#define TLB_DATA0_4M 0x22
|
||||
#define TLB_DATA0_2M_4M 0x23
|
||||
|
||||
#define STLB_4K 0x41
|
||||
#define STLB_4K_2M 0x42
|
||||
|
||||
/*
|
||||
* All of leaf 0x2's one-byte TLB descriptors implies the same number of
|
||||
* entries for their respective TLB types. The 0x63 descriptor is an
|
||||
* exception: it implies 4 dTLB entries for 1GB pages 32 dTLB entries
|
||||
* for 2MB or 4MB pages. Encode descriptor 0x63 dTLB entry count for
|
||||
* 2MB/4MB pages here, as its count for dTLB 1GB pages is already at the
|
||||
* intel_tlb_table[] mapping.
|
||||
*/
|
||||
#define TLB_0x63_2M_4M_ENTRIES 32
|
||||
|
||||
struct _tlb_table {
|
||||
unsigned char descriptor;
|
||||
char tlb_type;
|
||||
unsigned int entries;
|
||||
};
|
||||
|
||||
static const struct _tlb_table intel_tlb_table[] = {
|
||||
{ 0x01, TLB_INST_4K, 32}, /* TLB_INST 4 KByte pages, 4-way set associative */
|
||||
{ 0x02, TLB_INST_4M, 2}, /* TLB_INST 4 MByte pages, full associative */
|
||||
{ 0x03, TLB_DATA_4K, 64}, /* TLB_DATA 4 KByte pages, 4-way set associative */
|
||||
{ 0x04, TLB_DATA_4M, 8}, /* TLB_DATA 4 MByte pages, 4-way set associative */
|
||||
{ 0x05, TLB_DATA_4M, 32}, /* TLB_DATA 4 MByte pages, 4-way set associative */
|
||||
{ 0x0b, TLB_INST_4M, 4}, /* TLB_INST 4 MByte pages, 4-way set associative */
|
||||
{ 0x4f, TLB_INST_4K, 32}, /* TLB_INST 4 KByte pages */
|
||||
{ 0x50, TLB_INST_ALL, 64}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
{ 0x51, TLB_INST_ALL, 128}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
{ 0x52, TLB_INST_ALL, 256}, /* TLB_INST 4 KByte and 2-MByte or 4-MByte pages */
|
||||
{ 0x55, TLB_INST_2M_4M, 7}, /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
|
||||
{ 0x56, TLB_DATA0_4M, 16}, /* TLB_DATA0 4 MByte pages, 4-way set associative */
|
||||
{ 0x57, TLB_DATA0_4K, 16}, /* TLB_DATA0 4 KByte pages, 4-way associative */
|
||||
{ 0x59, TLB_DATA0_4K, 16}, /* TLB_DATA0 4 KByte pages, fully associative */
|
||||
{ 0x5a, TLB_DATA0_2M_4M, 32}, /* TLB_DATA0 2-MByte or 4 MByte pages, 4-way set associative */
|
||||
{ 0x5b, TLB_DATA_4K_4M, 64}, /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
{ 0x5c, TLB_DATA_4K_4M, 128}, /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
{ 0x5d, TLB_DATA_4K_4M, 256}, /* TLB_DATA 4 KByte and 4 MByte pages */
|
||||
{ 0x61, TLB_INST_4K, 48}, /* TLB_INST 4 KByte pages, full associative */
|
||||
{ 0x63, TLB_DATA_1G_2M_4M, 4}, /* TLB_DATA 1 GByte pages, 4-way set associative
|
||||
* (plus 32 entries TLB_DATA 2 MByte or 4 MByte pages, not encoded here) */
|
||||
{ 0x6b, TLB_DATA_4K, 256}, /* TLB_DATA 4 KByte pages, 8-way associative */
|
||||
{ 0x6c, TLB_DATA_2M_4M, 128}, /* TLB_DATA 2 MByte or 4 MByte pages, 8-way associative */
|
||||
{ 0x6d, TLB_DATA_1G, 16}, /* TLB_DATA 1 GByte pages, fully associative */
|
||||
{ 0x76, TLB_INST_2M_4M, 8}, /* TLB_INST 2-MByte or 4-MByte pages, fully associative */
|
||||
{ 0xb0, TLB_INST_4K, 128}, /* TLB_INST 4 KByte pages, 4-way set associative */
|
||||
{ 0xb1, TLB_INST_2M_4M, 4}, /* TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries */
|
||||
{ 0xb2, TLB_INST_4K, 64}, /* TLB_INST 4KByte pages, 4-way set associative */
|
||||
{ 0xb3, TLB_DATA_4K, 128}, /* TLB_DATA 4 KByte pages, 4-way set associative */
|
||||
{ 0xb4, TLB_DATA_4K, 256}, /* TLB_DATA 4 KByte pages, 4-way associative */
|
||||
{ 0xb5, TLB_INST_4K, 64}, /* TLB_INST 4 KByte pages, 8-way set associative */
|
||||
{ 0xb6, TLB_INST_4K, 128}, /* TLB_INST 4 KByte pages, 8-way set associative */
|
||||
{ 0xba, TLB_DATA_4K, 64}, /* TLB_DATA 4 KByte pages, 4-way associative */
|
||||
{ 0xc0, TLB_DATA_4K_4M, 8}, /* TLB_DATA 4 KByte and 4 MByte pages, 4-way associative */
|
||||
{ 0xc1, STLB_4K_2M, 1024}, /* STLB 4 KByte and 2 MByte pages, 8-way associative */
|
||||
{ 0xc2, TLB_DATA_2M_4M, 16}, /* TLB_DATA 2 MByte/4MByte pages, 4-way associative */
|
||||
{ 0xca, STLB_4K, 512}, /* STLB 4 KByte pages, 4-way associative */
|
||||
{ 0x00, 0, 0 }
|
||||
};
|
||||
|
||||
static void intel_tlb_lookup(const unsigned char desc)
|
||||
static void intel_tlb_lookup(const struct leaf_0x2_table *entry)
|
||||
{
|
||||
unsigned int entries;
|
||||
unsigned char k;
|
||||
short entries = entry->entries;
|
||||
|
||||
if (desc == 0)
|
||||
return;
|
||||
|
||||
/* look up this descriptor in the table */
|
||||
for (k = 0; intel_tlb_table[k].descriptor != desc &&
|
||||
intel_tlb_table[k].descriptor != 0; k++)
|
||||
;
|
||||
|
||||
if (intel_tlb_table[k].tlb_type == 0)
|
||||
return;
|
||||
|
||||
entries = intel_tlb_table[k].entries;
|
||||
switch (intel_tlb_table[k].tlb_type) {
|
||||
switch (entry->t_type) {
|
||||
case STLB_4K:
|
||||
tlb_lli_4k = max(tlb_lli_4k, entries);
|
||||
tlb_lld_4k = max(tlb_lld_4k, entries);
|
||||
|
|
@ -799,28 +709,16 @@ static void intel_tlb_lookup(const unsigned char desc)
|
|||
|
||||
static void intel_detect_tlb(struct cpuinfo_x86 *c)
|
||||
{
|
||||
int i, j, n;
|
||||
unsigned int regs[4];
|
||||
unsigned char *desc = (unsigned char *)regs;
|
||||
const struct leaf_0x2_table *entry;
|
||||
union leaf_0x2_regs regs;
|
||||
u8 *ptr;
|
||||
|
||||
if (c->cpuid_level < 2)
|
||||
return;
|
||||
|
||||
/* Number of times to iterate */
|
||||
n = cpuid_eax(2) & 0xFF;
|
||||
|
||||
for (i = 0 ; i < n ; i++) {
|
||||
cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]);
|
||||
|
||||
/* If bit 31 is set, this is an unknown format */
|
||||
for (j = 0 ; j < 4 ; j++)
|
||||
if (regs[j] & (1 << 31))
|
||||
regs[j] = 0;
|
||||
|
||||
/* Byte 0 is level count, not a descriptor */
|
||||
for (j = 1 ; j < 16 ; j++)
|
||||
intel_tlb_lookup(desc[j]);
|
||||
}
|
||||
cpuid_get_leaf_0x2_regs(®s);
|
||||
for_each_leaf_0x2_entry(regs, ptr, entry)
|
||||
intel_tlb_lookup(entry);
|
||||
}
|
||||
|
||||
static const struct cpu_dev intel_cpu_dev = {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/irq_vectors.h>
|
||||
#include <asm/mce.h>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static const struct cpuid_bit cpuid_bits[] = {
|
|||
{ X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 },
|
||||
{ X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 },
|
||||
{ X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 },
|
||||
{ X86_FEATURE_AMD_HETEROGENEOUS_CORES, CPUID_EAX, 30, 0x80000026, 0 },
|
||||
{ X86_FEATURE_AMD_HTR_CORES, CPUID_EAX, 30, 0x80000026, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ static void parse_topology_amd(struct topo_scan *tscan)
|
|||
if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
|
||||
has_topoext = cpu_parse_topology_ext(tscan);
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES))
|
||||
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
|
||||
tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
|
||||
|
||||
if (!has_topoext && !parse_8000_0008(tscan))
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <asm/numa.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
|
||||
static unsigned char __initdata nodeids[8];
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
#include <asm/e820/api.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
|
||||
#include "numa_internal.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <linux/cpu.h>
|
||||
#include <linux/range.h>
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/pci_x86.h>
|
||||
|
||||
#include <asm/pci-direct.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/pci_x86.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/mmzone.h>
|
||||
#include <asm/page.h> /* PAGE_SIZE */
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/gart.h>
|
||||
#include "agp.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
#include <linux/ras.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include "amd64_edac.h"
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
static struct edac_pci_ctl_info *pci_ctl;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd/hsmp.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <uapi/asm-generic/errno-base.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "hsmp.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* This file provides a device implementation for HSMP interface
|
||||
*/
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd/hsmp.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_hsmp.h>
|
||||
#include <asm/amd/hsmp.h>
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/device.h>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "hsmp.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
#include "pmf.h"
|
||||
|
||||
/* PMF-SMU communication registers */
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
|
|||
|
||||
#ifdef CONFIG_AMD_NB
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd/nb.h>
|
||||
|
||||
static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/ras.h>
|
||||
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/nb.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "reg_fields.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "amd.h"
|
||||
#include "../mach-config.h"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "amd.h"
|
||||
#include "acp-mach.h"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#include "amd.h"
|
||||
#include "acp-mach.h"
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#define DRV_NAME "acp_asoc_acp70"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/amd_node.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "../ops.h"
|
||||
#include "acp.h"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* 55898 Rev 0.35 - Feb 5, 2021
|
||||
*/
|
||||
|
||||
#include "msr-index.h"
|
||||
#include "../msr-index.h"
|
||||
|
||||
/* IBS_OP_DATA2 DataSrc */
|
||||
#define IBS_DATA_SRC_LOC_CACHE 2
|
||||
|
|
@ -476,11 +476,11 @@
|
|||
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* Clear branch history at syscall entry using SW loop */
|
||||
#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */
|
||||
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
|
||||
#define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
|
||||
#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */
|
||||
#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */
|
||||
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */
|
||||
#define X86_FEATURE_PREFER_YMM (21*32 + 8) /* Avoid ZMM registers due to downclocking */
|
||||
#define X86_FEATURE_CLEAR_BHB_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
|
||||
#define X86_FEATURE_AMD_FAST_CPPC (21*32+ 5) /* Fast CPPC */
|
||||
#define X86_FEATURE_AMD_HTR_CORES (21*32+ 6) /* Heterogeneous Core Topology */
|
||||
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32+ 7) /* Workload Classification */
|
||||
#define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */
|
||||
|
||||
/*
|
||||
* BUG word(s)
|
||||
|
|
@ -519,7 +519,7 @@
|
|||
#define X86_BUG_ITLB_MULTIHIT X86_BUG(23) /* "itlb_multihit" CPU may incur MCE during certain page attribute changes */
|
||||
#define X86_BUG_SRBDS X86_BUG(24) /* "srbds" CPU may leak RNG bits if not mitigated */
|
||||
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* "mmio_stale_data" CPU is affected by Processor MMIO Stale Data vulnerabilities */
|
||||
#define X86_BUG_MMIO_UNKNOWN X86_BUG(26) /* "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
|
||||
/* unused, was #define X86_BUG_MMIO_UNKNOWN X86_BUG(26) "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
|
||||
#define X86_BUG_RETBLEED X86_BUG(27) /* "retbleed" CPU is affected by RETBleed */
|
||||
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* "eibrs_pbrsb" EIBRS is vulnerable to Post Barrier RSB Predictions */
|
||||
#define X86_BUG_SMT_RSB X86_BUG(29) /* "smt_rsb" CPU is vulnerable to Cross-Thread Return Address Predictions */
|
||||
|
|
@ -527,10 +527,10 @@
|
|||
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* "tdx_pw_mce" CPU may incur #MC if non-TD software does partial write to TDX private memory */
|
||||
|
||||
/* BUG word 2 */
|
||||
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* "srso" AMD SRSO bug */
|
||||
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* "div0" AMD DIV0 speculation bug */
|
||||
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
|
||||
#define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */
|
||||
#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */
|
||||
#define X86_BUG_SPECTRE_V2_USER X86_BUG(1*32 + 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
|
||||
#define X86_BUG_SRSO X86_BUG( 1*32+ 0) /* "srso" AMD SRSO bug */
|
||||
#define X86_BUG_DIV0 X86_BUG( 1*32+ 1) /* "div0" AMD DIV0 speculation bug */
|
||||
#define X86_BUG_RFDS X86_BUG( 1*32+ 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
|
||||
#define X86_BUG_BHI X86_BUG( 1*32+ 3) /* "bhi" CPU is affected by Branch History Injection */
|
||||
#define X86_BUG_IBPB_NO_RET X86_BUG( 1*32+ 4) /* "ibpb_no_ret" IBPB omits return target predictions */
|
||||
#define X86_BUG_SPECTRE_V2_USER X86_BUG( 1*32+ 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
|
||||
#endif /* _ASM_X86_CPUFEATURES_H */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,14 +1,17 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cpuid.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define __noreturn __attribute__((__noreturn__))
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
|
|
@ -49,7 +52,7 @@ static const char * const reg_names[] = {
|
|||
struct subleaf {
|
||||
u32 index;
|
||||
u32 sub;
|
||||
u32 eax, ebx, ecx, edx;
|
||||
u32 output[NR_REGS];
|
||||
struct reg_desc info[NR_REGS];
|
||||
};
|
||||
|
||||
|
|
@ -63,21 +66,64 @@ struct cpuid_func {
|
|||
int nr;
|
||||
};
|
||||
|
||||
enum range_index {
|
||||
RANGE_STD = 0, /* Standard */
|
||||
RANGE_EXT = 0x80000000, /* Extended */
|
||||
RANGE_TSM = 0x80860000, /* Transmeta */
|
||||
RANGE_CTR = 0xc0000000, /* Centaur/Zhaoxin */
|
||||
};
|
||||
|
||||
#define CPUID_INDEX_MASK 0xffff0000
|
||||
#define CPUID_FUNCTION_MASK (~CPUID_INDEX_MASK)
|
||||
|
||||
struct cpuid_range {
|
||||
/* array of main leafs */
|
||||
struct cpuid_func *funcs;
|
||||
/* number of valid leafs */
|
||||
int nr;
|
||||
bool is_ext;
|
||||
enum range_index index;
|
||||
};
|
||||
|
||||
/*
|
||||
* basic: basic functions range: [0... ]
|
||||
* ext: extended functions range: [0x80000000... ]
|
||||
*/
|
||||
struct cpuid_range *leafs_basic, *leafs_ext;
|
||||
static struct cpuid_range ranges[] = {
|
||||
{ .index = RANGE_STD, },
|
||||
{ .index = RANGE_EXT, },
|
||||
{ .index = RANGE_TSM, },
|
||||
{ .index = RANGE_CTR, },
|
||||
};
|
||||
|
||||
static char *range_to_str(struct cpuid_range *range)
|
||||
{
|
||||
switch (range->index) {
|
||||
case RANGE_STD: return "Standard";
|
||||
case RANGE_EXT: return "Extended";
|
||||
case RANGE_TSM: return "Transmeta";
|
||||
case RANGE_CTR: return "Centaur";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define __for_each_cpuid_range(range, __condition) \
|
||||
for (unsigned int i = 0; \
|
||||
i < ARRAY_SIZE(ranges) && ((range) = &ranges[i]) && (__condition); \
|
||||
i++)
|
||||
|
||||
#define for_each_valid_cpuid_range(range) __for_each_cpuid_range(range, (range)->nr != 0)
|
||||
#define for_each_cpuid_range(range) __for_each_cpuid_range(range, true)
|
||||
|
||||
struct cpuid_range *index_to_cpuid_range(u32 index)
|
||||
{
|
||||
u32 func_idx = index & CPUID_FUNCTION_MASK;
|
||||
u32 range_idx = index & CPUID_INDEX_MASK;
|
||||
struct cpuid_range *range;
|
||||
|
||||
for_each_valid_cpuid_range(range) {
|
||||
if (range->index == range_idx && (u32)range->nr > func_idx)
|
||||
return range;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool is_amd;
|
||||
static bool show_details;
|
||||
static bool show_raw;
|
||||
static bool show_flags_only = true;
|
||||
|
|
@ -85,16 +131,16 @@ static u32 user_index = 0xFFFFFFFF;
|
|||
static u32 user_sub = 0xFFFFFFFF;
|
||||
static int flines;
|
||||
|
||||
static inline void cpuid(u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
|
||||
{
|
||||
/* ecx is often an input as well as an output. */
|
||||
asm volatile("cpuid"
|
||||
: "=a" (*eax),
|
||||
"=b" (*ebx),
|
||||
"=c" (*ecx),
|
||||
"=d" (*edx)
|
||||
: "0" (*eax), "2" (*ecx));
|
||||
}
|
||||
/*
|
||||
* Force using <cpuid.h> __cpuid_count() instead of __cpuid(). The
|
||||
* latter leaves ECX uninitialized, which can break CPUID queries.
|
||||
*/
|
||||
|
||||
#define cpuid(leaf, a, b, c, d) \
|
||||
__cpuid_count(leaf, 0, a, b, c, d)
|
||||
|
||||
#define cpuid_count(leaf, subleaf, a, b, c, d) \
|
||||
__cpuid_count(leaf, subleaf, a, b, c, d)
|
||||
|
||||
static inline bool has_subleafs(u32 f)
|
||||
{
|
||||
|
|
@ -117,11 +163,11 @@ static void leaf_print_raw(struct subleaf *leaf)
|
|||
if (leaf->sub == 0)
|
||||
printf("0x%08x: subleafs:\n", leaf->index);
|
||||
|
||||
printf(" %2d: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
|
||||
leaf->sub, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx);
|
||||
printf(" %2d: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", leaf->sub,
|
||||
leaf->output[0], leaf->output[1], leaf->output[2], leaf->output[3]);
|
||||
} else {
|
||||
printf("0x%08x: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n",
|
||||
leaf->index, leaf->eax, leaf->ebx, leaf->ecx, leaf->edx);
|
||||
printf("0x%08x: EAX=0x%08x, EBX=0x%08x, ECX=0x%08x, EDX=0x%08x\n", leaf->index,
|
||||
leaf->output[0], leaf->output[1], leaf->output[2], leaf->output[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,19 +186,19 @@ static bool cpuid_store(struct cpuid_range *range, u32 f, int subleaf,
|
|||
* Cut off vendor-prefix from CPUID function as we're using it as an
|
||||
* index into ->funcs.
|
||||
*/
|
||||
func = &range->funcs[f & 0xffff];
|
||||
func = &range->funcs[f & CPUID_FUNCTION_MASK];
|
||||
|
||||
if (!func->leafs) {
|
||||
func->leafs = malloc(sizeof(struct subleaf));
|
||||
if (!func->leafs)
|
||||
perror("malloc func leaf");
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
func->nr = 1;
|
||||
} else {
|
||||
s = func->nr;
|
||||
func->leafs = realloc(func->leafs, (s + 1) * sizeof(*leaf));
|
||||
if (!func->leafs)
|
||||
perror("realloc f->leafs");
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
func->nr++;
|
||||
}
|
||||
|
|
@ -161,84 +207,73 @@ static bool cpuid_store(struct cpuid_range *range, u32 f, int subleaf,
|
|||
|
||||
leaf->index = f;
|
||||
leaf->sub = subleaf;
|
||||
leaf->eax = a;
|
||||
leaf->ebx = b;
|
||||
leaf->ecx = c;
|
||||
leaf->edx = d;
|
||||
leaf->output[R_EAX] = a;
|
||||
leaf->output[R_EBX] = b;
|
||||
leaf->output[R_ECX] = c;
|
||||
leaf->output[R_EDX] = d;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void raw_dump_range(struct cpuid_range *range)
|
||||
{
|
||||
u32 f;
|
||||
int i;
|
||||
|
||||
printf("%s Leafs :\n", range->is_ext ? "Extended" : "Basic");
|
||||
printf("%s Leafs :\n", range_to_str(range));
|
||||
printf("================\n");
|
||||
|
||||
for (f = 0; (int)f < range->nr; f++) {
|
||||
for (u32 f = 0; (int)f < range->nr; f++) {
|
||||
struct cpuid_func *func = &range->funcs[f];
|
||||
u32 index = f;
|
||||
|
||||
if (range->is_ext)
|
||||
index += 0x80000000;
|
||||
|
||||
/* Skip leaf without valid items */
|
||||
if (!func->nr)
|
||||
continue;
|
||||
|
||||
/* First item is the main leaf, followed by all subleafs */
|
||||
for (i = 0; i < func->nr; i++)
|
||||
for (int i = 0; i < func->nr; i++)
|
||||
leaf_print_raw(&func->leafs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_SUBLEAF_NUM 64
|
||||
struct cpuid_range *setup_cpuid_range(u32 input_eax)
|
||||
#define MAX_RANGE_INDEX_OFFSET 0xff
|
||||
void setup_cpuid_range(struct cpuid_range *range)
|
||||
{
|
||||
u32 max_func, idx_func, subleaf, max_subleaf;
|
||||
u32 eax, ebx, ecx, edx, f = input_eax;
|
||||
struct cpuid_range *range;
|
||||
bool allzero;
|
||||
u32 max_func, range_funcs_sz;
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
eax = input_eax;
|
||||
ebx = ecx = edx = 0;
|
||||
cpuid(range->index, max_func, ebx, ecx, edx);
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
max_func = eax;
|
||||
idx_func = (max_func & 0xffff) + 1;
|
||||
/*
|
||||
* If the CPUID range's maximum function value is garbage, then it
|
||||
* is not recognized by this CPU. Set the range's number of valid
|
||||
* leaves to zero so that for_each_valid_cpu_range() can ignore it.
|
||||
*/
|
||||
if (max_func < range->index || max_func > (range->index + MAX_RANGE_INDEX_OFFSET)) {
|
||||
range->nr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
range = malloc(sizeof(struct cpuid_range));
|
||||
if (!range)
|
||||
perror("malloc range");
|
||||
range->nr = (max_func & CPUID_FUNCTION_MASK) + 1;
|
||||
range_funcs_sz = range->nr * sizeof(struct cpuid_func);
|
||||
|
||||
if (input_eax & 0x80000000)
|
||||
range->is_ext = true;
|
||||
else
|
||||
range->is_ext = false;
|
||||
|
||||
range->funcs = malloc(sizeof(struct cpuid_func) * idx_func);
|
||||
range->funcs = malloc(range_funcs_sz);
|
||||
if (!range->funcs)
|
||||
perror("malloc range->funcs");
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
range->nr = idx_func;
|
||||
memset(range->funcs, 0, sizeof(struct cpuid_func) * idx_func);
|
||||
memset(range->funcs, 0, range_funcs_sz);
|
||||
|
||||
for (; f <= max_func; f++) {
|
||||
eax = f;
|
||||
subleaf = ecx = 0;
|
||||
for (u32 f = range->index; f <= max_func; f++) {
|
||||
u32 max_subleaf = MAX_SUBLEAF_NUM;
|
||||
bool allzero;
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx);
|
||||
cpuid(f, eax, ebx, ecx, edx);
|
||||
|
||||
allzero = cpuid_store(range, f, 0, eax, ebx, ecx, edx);
|
||||
if (allzero)
|
||||
continue;
|
||||
|
||||
if (!has_subleafs(f))
|
||||
continue;
|
||||
|
||||
max_subleaf = MAX_SUBLEAF_NUM;
|
||||
|
||||
/*
|
||||
* Some can provide the exact number of subleafs,
|
||||
* others have to be tried (0xf)
|
||||
|
|
@ -256,20 +291,15 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
|
|||
if (f == 0x80000026)
|
||||
max_subleaf = 5;
|
||||
|
||||
for (subleaf = 1; subleaf < max_subleaf; subleaf++) {
|
||||
eax = f;
|
||||
ecx = subleaf;
|
||||
for (u32 subleaf = 1; subleaf < max_subleaf; subleaf++) {
|
||||
cpuid_count(f, subleaf, eax, ebx, ecx, edx);
|
||||
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
allzero = cpuid_store(range, f, subleaf,
|
||||
eax, ebx, ecx, edx);
|
||||
allzero = cpuid_store(range, f, subleaf, eax, ebx, ecx, edx);
|
||||
if (allzero)
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -280,15 +310,13 @@ struct cpuid_range *setup_cpuid_range(u32 input_eax)
|
|||
* 0, 0, EAX, 31:0, max_basic_leafs, Max input value for supported subleafs
|
||||
* 1, 0, ECX, 0, sse3, Streaming SIMD Extensions 3(SSE3)
|
||||
*/
|
||||
static int parse_line(char *line)
|
||||
static void parse_line(char *line)
|
||||
{
|
||||
char *str;
|
||||
int i;
|
||||
struct cpuid_range *range;
|
||||
struct cpuid_func *func;
|
||||
struct subleaf *leaf;
|
||||
u32 index;
|
||||
u32 sub;
|
||||
char buffer[512];
|
||||
char *buf;
|
||||
/*
|
||||
|
|
@ -310,12 +338,12 @@ static int parse_line(char *line)
|
|||
|
||||
/* Skip comments and NULL line */
|
||||
if (line[0] == '#' || line[0] == '\n')
|
||||
return 0;
|
||||
return;
|
||||
|
||||
strncpy(buffer, line, 511);
|
||||
buffer[511] = 0;
|
||||
str = buffer;
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
tokens[i] = strtok(str, ",");
|
||||
if (!tokens[i])
|
||||
goto err_exit;
|
||||
|
|
@ -328,21 +356,19 @@ static int parse_line(char *line)
|
|||
/* index/main-leaf */
|
||||
index = strtoull(tokens[0], NULL, 0);
|
||||
|
||||
if (index & 0x80000000)
|
||||
range = leafs_ext;
|
||||
else
|
||||
range = leafs_basic;
|
||||
|
||||
index &= 0x7FFFFFFF;
|
||||
/* Skip line parsing for non-existing indexes */
|
||||
if ((int)index >= range->nr)
|
||||
return -1;
|
||||
/*
|
||||
* Skip line parsing if the index is not covered by known-valid
|
||||
* CPUID ranges on this CPU.
|
||||
*/
|
||||
range = index_to_cpuid_range(index);
|
||||
if (!range)
|
||||
return;
|
||||
|
||||
/* Skip line parsing if the index CPUID output is all zero */
|
||||
index &= CPUID_FUNCTION_MASK;
|
||||
func = &range->funcs[index];
|
||||
|
||||
/* Return if the index has no valid item on this platform */
|
||||
if (!func->nr)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* subleaf */
|
||||
buf = tokens[1];
|
||||
|
|
@ -355,11 +381,11 @@ static int parse_line(char *line)
|
|||
subleaf_start = strtoul(start, NULL, 0);
|
||||
subleaf_end = min(subleaf_end, (u32)(func->nr - 1));
|
||||
if (subleaf_start > subleaf_end)
|
||||
return 0;
|
||||
return;
|
||||
} else {
|
||||
subleaf_start = subleaf_end;
|
||||
if (subleaf_start > (u32)(func->nr - 1))
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* register */
|
||||
|
|
@ -382,7 +408,7 @@ static int parse_line(char *line)
|
|||
bit_end = strtoul(end, NULL, 0);
|
||||
bit_start = (start) ? strtoul(start, NULL, 0) : bit_end;
|
||||
|
||||
for (sub = subleaf_start; sub <= subleaf_end; sub++) {
|
||||
for (u32 sub = subleaf_start; sub <= subleaf_end; sub++) {
|
||||
leaf = &func->leafs[sub];
|
||||
reg = &leaf->info[reg_index];
|
||||
bdesc = ®->descs[reg->nr++];
|
||||
|
|
@ -392,12 +418,11 @@ static int parse_line(char *line)
|
|||
strcpy(bdesc->simp, strtok(tokens[4], " \t"));
|
||||
strcpy(bdesc->detail, tokens[5]);
|
||||
}
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err_exit:
|
||||
printf("Warning: wrong line format:\n");
|
||||
printf("\tline[%d]: %s\n", flines, line);
|
||||
return -1;
|
||||
warnx("Wrong line format:\n"
|
||||
"\tline[%d]: %s", flines, line);
|
||||
}
|
||||
|
||||
/* Parse csv file, and construct the array of all leafs and subleafs */
|
||||
|
|
@ -418,10 +443,8 @@ static void parse_text(void)
|
|||
file = fopen("./cpuid.csv", "r");
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
printf("Fail to open '%s'\n", filename);
|
||||
return;
|
||||
}
|
||||
if (!file)
|
||||
err(EXIT_FAILURE, "%s", filename);
|
||||
|
||||
while (1) {
|
||||
ret = getline(&line, &len, file);
|
||||
|
|
@ -436,21 +459,13 @@ static void parse_text(void)
|
|||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
/* Decode every eax/ebx/ecx/edx */
|
||||
static void decode_bits(u32 value, struct reg_desc *rdesc, enum cpuid_reg reg)
|
||||
static void show_reg(const struct reg_desc *rdesc, u32 value)
|
||||
{
|
||||
struct bits_desc *bdesc;
|
||||
int start, end, i;
|
||||
const struct bits_desc *bdesc;
|
||||
int start, end;
|
||||
u32 mask;
|
||||
|
||||
if (!rdesc->nr) {
|
||||
if (show_details)
|
||||
printf("\t %s: 0x%08x\n", reg_names[reg], value);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < rdesc->nr; i++) {
|
||||
for (int i = 0; i < rdesc->nr; i++) {
|
||||
bdesc = &rdesc->descs[i];
|
||||
|
||||
start = bdesc->start;
|
||||
|
|
@ -480,23 +495,21 @@ static void decode_bits(u32 value, struct reg_desc *rdesc, enum cpuid_reg reg)
|
|||
}
|
||||
}
|
||||
|
||||
static void show_reg_header(bool has_entries, u32 leaf, u32 subleaf, const char *reg_name)
|
||||
{
|
||||
if (show_details && has_entries)
|
||||
printf("CPUID_0x%x_%s[0x%x]:\n", leaf, reg_name, subleaf);
|
||||
}
|
||||
|
||||
static void show_leaf(struct subleaf *leaf)
|
||||
{
|
||||
if (!leaf)
|
||||
return;
|
||||
|
||||
if (show_raw) {
|
||||
if (show_raw)
|
||||
leaf_print_raw(leaf);
|
||||
} else {
|
||||
if (show_details)
|
||||
printf("CPUID_0x%x_ECX[0x%x]:\n",
|
||||
leaf->index, leaf->sub);
|
||||
}
|
||||
|
||||
decode_bits(leaf->eax, &leaf->info[R_EAX], R_EAX);
|
||||
decode_bits(leaf->ebx, &leaf->info[R_EBX], R_EBX);
|
||||
decode_bits(leaf->ecx, &leaf->info[R_ECX], R_ECX);
|
||||
decode_bits(leaf->edx, &leaf->info[R_EDX], R_EDX);
|
||||
for (int i = R_EAX; i < NR_REGS; i++) {
|
||||
show_reg_header((leaf->info[i].nr > 0), leaf->index, leaf->sub, reg_names[i]);
|
||||
show_reg(&leaf->info[i], leaf->output[i]);
|
||||
}
|
||||
|
||||
if (!show_raw && show_details)
|
||||
printf("\n");
|
||||
|
|
@ -504,46 +517,37 @@ static void show_leaf(struct subleaf *leaf)
|
|||
|
||||
static void show_func(struct cpuid_func *func)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!func)
|
||||
return;
|
||||
|
||||
for (i = 0; i < func->nr; i++)
|
||||
for (int i = 0; i < func->nr; i++)
|
||||
show_leaf(&func->leafs[i]);
|
||||
}
|
||||
|
||||
static void show_range(struct cpuid_range *range)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < range->nr; i++)
|
||||
for (int i = 0; i < range->nr; i++)
|
||||
show_func(&range->funcs[i]);
|
||||
}
|
||||
|
||||
static inline struct cpuid_func *index_to_func(u32 index)
|
||||
{
|
||||
u32 func_idx = index & CPUID_FUNCTION_MASK;
|
||||
struct cpuid_range *range;
|
||||
u32 func_idx;
|
||||
|
||||
range = (index & 0x80000000) ? leafs_ext : leafs_basic;
|
||||
func_idx = index & 0xffff;
|
||||
|
||||
if ((func_idx + 1) > (u32)range->nr) {
|
||||
printf("ERR: invalid input index (0x%x)\n", index);
|
||||
range = index_to_cpuid_range(index);
|
||||
if (!range)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &range->funcs[func_idx];
|
||||
}
|
||||
|
||||
static void show_info(void)
|
||||
{
|
||||
struct cpuid_range *range;
|
||||
struct cpuid_func *func;
|
||||
|
||||
if (show_raw) {
|
||||
/* Show all of the raw output of 'cpuid' instr */
|
||||
raw_dump_range(leafs_basic);
|
||||
raw_dump_range(leafs_ext);
|
||||
for_each_valid_cpuid_range(range)
|
||||
raw_dump_range(range);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -551,18 +555,19 @@ static void show_info(void)
|
|||
/* Only show specific leaf/subleaf info */
|
||||
func = index_to_func(user_index);
|
||||
if (!func)
|
||||
return;
|
||||
errx(EXIT_FAILURE, "Invalid input leaf (0x%x)", user_index);
|
||||
|
||||
/* Dump the raw data also */
|
||||
show_raw = true;
|
||||
|
||||
if (user_sub != 0xFFFFFFFF) {
|
||||
if (user_sub + 1 <= (u32)func->nr) {
|
||||
show_leaf(&func->leafs[user_sub]);
|
||||
return;
|
||||
if (user_sub + 1 > (u32)func->nr) {
|
||||
errx(EXIT_FAILURE, "Leaf 0x%x has no valid subleaf = 0x%x",
|
||||
user_index, user_sub);
|
||||
}
|
||||
|
||||
printf("ERR: invalid input subleaf (0x%x)\n", user_sub);
|
||||
show_leaf(&func->leafs[user_sub]);
|
||||
return;
|
||||
}
|
||||
|
||||
show_func(func);
|
||||
|
|
@ -570,38 +575,21 @@ static void show_info(void)
|
|||
}
|
||||
|
||||
printf("CPU features:\n=============\n\n");
|
||||
show_range(leafs_basic);
|
||||
show_range(leafs_ext);
|
||||
for_each_valid_cpuid_range(range)
|
||||
show_range(range);
|
||||
}
|
||||
|
||||
static void setup_platform_cpuid(void)
|
||||
static void __noreturn usage(int exit_code)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
/* Check vendor */
|
||||
eax = ebx = ecx = edx = 0;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
/* "htuA" */
|
||||
if (ebx == 0x68747541)
|
||||
is_amd = true;
|
||||
|
||||
/* Setup leafs for the basic and extended range */
|
||||
leafs_basic = setup_cpuid_range(0x0);
|
||||
leafs_ext = setup_cpuid_range(0x80000000);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("kcpuid [-abdfhr] [-l leaf] [-s subleaf]\n"
|
||||
"\t-a|--all Show both bit flags and complex bit fields info\n"
|
||||
"\t-b|--bitflags Show boolean flags only\n"
|
||||
"\t-d|--detail Show details of the flag/fields (default)\n"
|
||||
"\t-f|--flags Specify the cpuid csv file\n"
|
||||
"\t-h|--help Show usage info\n"
|
||||
"\t-l|--leaf=index Specify the leaf you want to check\n"
|
||||
"\t-r|--raw Show raw cpuid data\n"
|
||||
"\t-s|--subleaf=sub Specify the subleaf you want to check\n"
|
||||
errx(exit_code, "kcpuid [-abdfhr] [-l leaf] [-s subleaf]\n"
|
||||
"\t-a|--all Show both bit flags and complex bit fields info\n"
|
||||
"\t-b|--bitflags Show boolean flags only\n"
|
||||
"\t-d|--detail Show details of the flag/fields (default)\n"
|
||||
"\t-f|--flags Specify the CPUID CSV file\n"
|
||||
"\t-h|--help Show usage info\n"
|
||||
"\t-l|--leaf=index Specify the leaf you want to check\n"
|
||||
"\t-r|--raw Show raw CPUID data\n"
|
||||
"\t-s|--subleaf=sub Specify the subleaf you want to check"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -617,7 +605,7 @@ static struct option opts[] = {
|
|||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static int parse_options(int argc, char *argv[])
|
||||
static void parse_options(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
|
|
@ -637,9 +625,7 @@ static int parse_options(int argc, char *argv[])
|
|||
user_csv = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(1);
|
||||
break;
|
||||
usage(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
/* main leaf */
|
||||
user_index = strtoul(optarg, NULL, 0);
|
||||
|
|
@ -652,11 +638,8 @@ static int parse_options(int argc, char *argv[])
|
|||
user_sub = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
printf("%s: Invalid option '%c'\n", argv[0], optopt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -669,11 +652,13 @@ static int parse_options(int argc, char *argv[])
|
|||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (parse_options(argc, argv))
|
||||
return -1;
|
||||
struct cpuid_range *range;
|
||||
|
||||
parse_options(argc, argv);
|
||||
|
||||
/* Setup the cpuid leafs of current platform */
|
||||
setup_platform_cpuid();
|
||||
for_each_cpuid_range(range)
|
||||
setup_cpuid_range(range);
|
||||
|
||||
/* Read and parse the 'cpuid.csv' */
|
||||
parse_text();
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ done
|
|||
# diff with extra ignore lines
|
||||
check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memcpy_\(erms\|orig\))" -I"^#include <linux/cfi_types.h>"'
|
||||
check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memset_\(erms\|orig\))"'
|
||||
check arch/x86/include/asm/amd-ibs.h '-I "^#include [<\"]\(asm/\)*msr-index.h"'
|
||||
check arch/x86/include/asm/amd/ibs.h '-I "^#include [<\"]\(asm/\)*msr-index.h"'
|
||||
check arch/arm64/include/asm/cputype.h '-I "^#include [<\"]\(asm/\)*sysreg.h"'
|
||||
check include/linux/unaligned.h '-I "^#include <linux/unaligned/packed_struct.h>" -I "^#include <asm/byteorder.h>" -I "^#pragma GCC diagnostic"'
|
||||
check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common\(-tools\)*.h>"'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#include <linux/string.h>
|
||||
#include "../../arch/x86/include/asm/amd-ibs.h"
|
||||
#include "../../arch/x86/include/asm/amd/ibs.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "session.h"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user