mirror of
https://github.com/torvalds/linux.git
synced 2024-11-07 20:51:47 +00:00
2bbf0a1427
The Way Access Filter in recent AMD CPUs may hurt the performance of some workloads, caused by aliasing issues in the L1 cache. This patch disables it on the affected CPUs. The issue is similar to that one of last year: http://lkml.indiana.edu/hypermail/linux/kernel/1107.3/00041.html This new patch does not replace the old one, we just need another quirk for newer CPUs. The performance penalty without the patch depends on the circumstances, but is a bit less than the last year's 3%. The workloads affected would be those that access code from the same physical page under different virtual addresses, so different processes using the same libraries with ASLR or multiple instances of PIE-binaries. The code needs to be accessed simultaneously from both cores of the same compute unit. More details can be found here: http://developer.amd.com/Assets/SharedL1InstructionCacheonAMD15hCPU.pdf CPUs affected are anything with the core known as Piledriver. That includes the new parts of the AMD A-Series (aka Trinity) and the just released new CPUs of the FX-Series (aka Vishera). The model numbering is a bit odd here: FX CPUs have model 2, A-Series has model 10h, with possible extensions to 1Fh. Hence the range of model ids. Signed-off-by: Andre Przywara <osp@andrep.de> Link: http://lkml.kernel.org/r/1351700450-9277-1-git-send-email-osp@andrep.de Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
917 lines
22 KiB
C
917 lines
22 KiB
C
#include <linux/export.h>
|
|
#include <linux/init.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/elf.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/sched.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/apic.h>
|
|
#include <asm/cpu.h>
|
|
#include <asm/pci-direct.h>
|
|
|
|
#ifdef CONFIG_X86_64
|
|
# include <asm/numa_64.h>
|
|
# include <asm/mmconfig.h>
|
|
# include <asm/cacheflush.h>
|
|
#endif
|
|
|
|
#include "cpu.h"
|
|
|
|
static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
|
|
{
|
|
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
|
|
u32 gprs[8] = { 0 };
|
|
int err;
|
|
|
|
WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
|
|
|
|
gprs[1] = msr;
|
|
gprs[7] = 0x9c5a203a;
|
|
|
|
err = rdmsr_safe_regs(gprs);
|
|
|
|
*p = gprs[0] | ((u64)gprs[2] << 32);
|
|
|
|
return err;
|
|
}
|
|
|
|
static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
|
|
{
|
|
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
|
|
u32 gprs[8] = { 0 };
|
|
|
|
WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
|
|
|
|
gprs[0] = (u32)val;
|
|
gprs[1] = msr;
|
|
gprs[2] = val >> 32;
|
|
gprs[7] = 0x9c5a203a;
|
|
|
|
return wrmsr_safe_regs(gprs);
|
|
}
|
|
|
|
#ifdef CONFIG_X86_32
|
|
/*
|
|
* B step AMD K6 before B 9730xxxx have hardware bugs that can cause
|
|
* misexecution of code under Linux. Owners of such processors should
|
|
* contact AMD for precise details and a CPU swap.
|
|
*
|
|
* See http://www.multimania.com/poulot/k6bug.html
|
|
* and section 2.6.2 of "AMD-K6 Processor Revision Guide - Model 6"
|
|
* (Publication # 21266 Issue Date: August 1998)
|
|
*
|
|
* The following test is erm.. interesting. AMD neglected to up
|
|
* the chip setting when fixing the bug but they also tweaked some
|
|
* performance at the same time..
|
|
*/
|
|
|
|
extern void vide(void);
|
|
__asm__(".align 4\nvide: ret");
|
|
|
|
static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c)
|
|
{
|
|
/*
|
|
* General Systems BIOSen alias the cpu frequency registers
|
|
* of the Elan at 0x000df000. Unfortuantly, one of the Linux
|
|
* drivers subsequently pokes it, and changes the CPU speed.
|
|
* Workaround : Remove the unneeded alias.
|
|
*/
|
|
#define CBAR (0xfffc) /* Configuration Base Address (32-bit) */
|
|
#define CBAR_ENB (0x80000000)
|
|
#define CBAR_KEY (0X000000CB)
|
|
if (c->x86_model == 9 || c->x86_model == 10) {
|
|
if (inl(CBAR) & CBAR_ENB)
|
|
outl(0 | CBAR_KEY, CBAR);
|
|
}
|
|
}
|
|
|
|
|
|
static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 l, h;
|
|
int mbytes = num_physpages >> (20-PAGE_SHIFT);
|
|
|
|
if (c->x86_model < 6) {
|
|
/* Based on AMD doc 20734R - June 2000 */
|
|
if (c->x86_model == 0) {
|
|
clear_cpu_cap(c, X86_FEATURE_APIC);
|
|
set_cpu_cap(c, X86_FEATURE_PGE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (c->x86_model == 6 && c->x86_mask == 1) {
|
|
const int K6_BUG_LOOP = 1000000;
|
|
int n;
|
|
void (*f_vide)(void);
|
|
unsigned long d, d2;
|
|
|
|
printk(KERN_INFO "AMD K6 stepping B detected - ");
|
|
|
|
/*
|
|
* It looks like AMD fixed the 2.6.2 bug and improved indirect
|
|
* calls at the same time.
|
|
*/
|
|
|
|
n = K6_BUG_LOOP;
|
|
f_vide = vide;
|
|
rdtscl(d);
|
|
while (n--)
|
|
f_vide();
|
|
rdtscl(d2);
|
|
d = d2-d;
|
|
|
|
if (d > 20*K6_BUG_LOOP)
|
|
printk(KERN_CONT
|
|
"system stability may be impaired when more than 32 MB are used.\n");
|
|
else
|
|
printk(KERN_CONT "probably OK (after B9730xxxx).\n");
|
|
}
|
|
|
|
/* K6 with old style WHCR */
|
|
if (c->x86_model < 8 ||
|
|
(c->x86_model == 8 && c->x86_mask < 8)) {
|
|
/* We can only write allocate on the low 508Mb */
|
|
if (mbytes > 508)
|
|
mbytes = 508;
|
|
|
|
rdmsr(MSR_K6_WHCR, l, h);
|
|
if ((l&0x0000FFFF) == 0) {
|
|
unsigned long flags;
|
|
l = (1<<0)|((mbytes/4)<<1);
|
|
local_irq_save(flags);
|
|
wbinvd();
|
|
wrmsr(MSR_K6_WHCR, l, h);
|
|
local_irq_restore(flags);
|
|
printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
|
|
mbytes);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((c->x86_model == 8 && c->x86_mask > 7) ||
|
|
c->x86_model == 9 || c->x86_model == 13) {
|
|
/* The more serious chips .. */
|
|
|
|
if (mbytes > 4092)
|
|
mbytes = 4092;
|
|
|
|
rdmsr(MSR_K6_WHCR, l, h);
|
|
if ((l&0xFFFF0000) == 0) {
|
|
unsigned long flags;
|
|
l = ((mbytes>>2)<<22)|(1<<16);
|
|
local_irq_save(flags);
|
|
wbinvd();
|
|
wrmsr(MSR_K6_WHCR, l, h);
|
|
local_irq_restore(flags);
|
|
printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
|
|
mbytes);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (c->x86_model == 10) {
|
|
/* AMD Geode LX is model 10 */
|
|
/* placeholder for any needed mods */
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
|
|
{
|
|
/* calling is from identify_secondary_cpu() ? */
|
|
if (!c->cpu_index)
|
|
return;
|
|
|
|
/*
|
|
* Certain Athlons might work (for various values of 'work') in SMP
|
|
* but they are not certified as MP capable.
|
|
*/
|
|
/* Athlon 660/661 is valid. */
|
|
if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
|
|
(c->x86_mask == 1)))
|
|
goto valid_k7;
|
|
|
|
/* Duron 670 is valid */
|
|
if ((c->x86_model == 7) && (c->x86_mask == 0))
|
|
goto valid_k7;
|
|
|
|
/*
|
|
* Athlon 662, Duron 671, and Athlon >model 7 have capability
|
|
* bit. It's worth noting that the A5 stepping (662) of some
|
|
* Athlon XP's have the MP bit set.
|
|
* See http://www.heise.de/newsticker/data/jow-18.10.01-000 for
|
|
* more.
|
|
*/
|
|
if (((c->x86_model == 6) && (c->x86_mask >= 2)) ||
|
|
((c->x86_model == 7) && (c->x86_mask >= 1)) ||
|
|
(c->x86_model > 7))
|
|
if (cpu_has_mp)
|
|
goto valid_k7;
|
|
|
|
/* If we get here, not a certified SMP capable AMD system. */
|
|
|
|
/*
|
|
* Don't taint if we are running SMP kernel on a single non-MP
|
|
* approved Athlon
|
|
*/
|
|
WARN_ONCE(1, "WARNING: This combination of AMD"
|
|
" processors is not suitable for SMP.\n");
|
|
if (!test_taint(TAINT_UNSAFE_SMP))
|
|
add_taint(TAINT_UNSAFE_SMP);
|
|
|
|
valid_k7:
|
|
;
|
|
}
|
|
|
|
static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 l, h;
|
|
|
|
/*
|
|
* Bit 15 of Athlon specific MSR 15, needs to be 0
|
|
* to enable SSE on Palomino/Morgan/Barton CPU's.
|
|
* If the BIOS didn't enable it already, enable it here.
|
|
*/
|
|
if (c->x86_model >= 6 && c->x86_model <= 10) {
|
|
if (!cpu_has(c, X86_FEATURE_XMM)) {
|
|
printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
|
|
rdmsr(MSR_K7_HWCR, l, h);
|
|
l &= ~0x00008000;
|
|
wrmsr(MSR_K7_HWCR, l, h);
|
|
set_cpu_cap(c, X86_FEATURE_XMM);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* It's been determined by AMD that Athlons since model 8 stepping 1
|
|
* are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
|
|
* As per AMD technical note 27212 0.2
|
|
*/
|
|
if ((c->x86_model == 8 && c->x86_mask >= 1) || (c->x86_model > 8)) {
|
|
rdmsr(MSR_K7_CLK_CTL, l, h);
|
|
if ((l & 0xfff00000) != 0x20000000) {
|
|
printk(KERN_INFO
|
|
"CPU: CLK_CTL MSR was %x. Reprogramming to %x\n",
|
|
l, ((l & 0x000fffff)|0x20000000));
|
|
wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
|
|
}
|
|
}
|
|
|
|
set_cpu_cap(c, X86_FEATURE_K7);
|
|
|
|
amd_k7_smp_check(c);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_NUMA
|
|
/*
|
|
* To workaround broken NUMA config. Read the comment in
|
|
* srat_detect_node().
|
|
*/
|
|
static int __cpuinit nearby_node(int apicid)
|
|
{
|
|
int i, node;
|
|
|
|
for (i = apicid - 1; i >= 0; i--) {
|
|
node = __apicid_to_node[i];
|
|
if (node != NUMA_NO_NODE && node_online(node))
|
|
return node;
|
|
}
|
|
for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
|
|
node = __apicid_to_node[i];
|
|
if (node != NUMA_NO_NODE && node_online(node))
|
|
return node;
|
|
}
|
|
return first_node(node_online_map); /* Shouldn't happen */
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Fixup core topology information for
|
|
* (1) AMD multi-node processors
|
|
* Assumption: Number of cores in each internal node is the same.
|
|
* (2) AMD processors supporting compute units
|
|
*/
|
|
#ifdef CONFIG_X86_HT
|
|
static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 nodes, cores_per_cu = 1;
|
|
u8 node_id;
|
|
int cpu = smp_processor_id();
|
|
|
|
/* get information required for multi-node processors */
|
|
if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
|
|
nodes = ((ecx >> 8) & 7) + 1;
|
|
node_id = ecx & 7;
|
|
|
|
/* get compute unit information */
|
|
smp_num_siblings = ((ebx >> 8) & 3) + 1;
|
|
c->compute_unit_id = ebx & 0xff;
|
|
cores_per_cu += ((ebx >> 8) & 3);
|
|
} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
|
|
u64 value;
|
|
|
|
rdmsrl(MSR_FAM10H_NODE_ID, value);
|
|
nodes = ((value >> 3) & 7) + 1;
|
|
node_id = value & 7;
|
|
} else
|
|
return;
|
|
|
|
/* fixup multi-node processor information */
|
|
if (nodes > 1) {
|
|
u32 cores_per_node;
|
|
u32 cus_per_node;
|
|
|
|
set_cpu_cap(c, X86_FEATURE_AMD_DCM);
|
|
cores_per_node = c->x86_max_cores / nodes;
|
|
cus_per_node = cores_per_node / cores_per_cu;
|
|
|
|
/* store NodeID, use llc_shared_map to store sibling info */
|
|
per_cpu(cpu_llc_id, cpu) = node_id;
|
|
|
|
/* core id has to be in the [0 .. cores_per_node - 1] range */
|
|
c->cpu_core_id %= cores_per_node;
|
|
c->compute_unit_id %= cus_per_node;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* On a AMD dual core setup the lower bits of the APIC id distingush the cores.
|
|
* Assumes number of cores is a power of two.
|
|
*/
|
|
static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
|
|
{
|
|
#ifdef CONFIG_X86_HT
|
|
unsigned bits;
|
|
int cpu = smp_processor_id();
|
|
|
|
bits = c->x86_coreid_bits;
|
|
/* Low order bits define the core id (index of core in socket) */
|
|
c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
|
|
/* Convert the initial APIC ID into the socket ID */
|
|
c->phys_proc_id = c->initial_apicid >> bits;
|
|
/* use socket ID also for last level cache */
|
|
per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
|
|
amd_get_topology(c);
|
|
#endif
|
|
}
|
|
|
|
int amd_get_nb_id(int cpu)
|
|
{
|
|
int id = 0;
|
|
#ifdef CONFIG_SMP
|
|
id = per_cpu(cpu_llc_id, cpu);
|
|
#endif
|
|
return id;
|
|
}
|
|
EXPORT_SYMBOL_GPL(amd_get_nb_id);
|
|
|
|
static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
|
|
{
|
|
#ifdef CONFIG_NUMA
|
|
int cpu = smp_processor_id();
|
|
int node;
|
|
unsigned apicid = c->apicid;
|
|
|
|
node = numa_cpu_node(cpu);
|
|
if (node == NUMA_NO_NODE)
|
|
node = per_cpu(cpu_llc_id, cpu);
|
|
|
|
/*
|
|
* On multi-fabric platform (e.g. Numascale NumaChip) a
|
|
* platform-specific handler needs to be called to fixup some
|
|
* IDs of the CPU.
|
|
*/
|
|
if (x86_cpuinit.fixup_cpu_id)
|
|
x86_cpuinit.fixup_cpu_id(c, node);
|
|
|
|
if (!node_online(node)) {
|
|
/*
|
|
* Two possibilities here:
|
|
*
|
|
* - The CPU is missing memory and no node was created. In
|
|
* that case try picking one from a nearby CPU.
|
|
*
|
|
* - The APIC IDs differ from the HyperTransport node IDs
|
|
* which the K8 northbridge parsing fills in. Assume
|
|
* they are all increased by a constant offset, but in
|
|
* the same order as the HT nodeids. If that doesn't
|
|
* result in a usable node fall back to the path for the
|
|
* previous case.
|
|
*
|
|
* This workaround operates directly on the mapping between
|
|
* APIC ID and NUMA node, assuming certain relationship
|
|
* between APIC ID, HT node ID and NUMA topology. As going
|
|
* through CPU mapping may alter the outcome, directly
|
|
* access __apicid_to_node[].
|
|
*/
|
|
int ht_nodeid = c->initial_apicid;
|
|
|
|
if (ht_nodeid >= 0 &&
|
|
__apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
|
|
node = __apicid_to_node[ht_nodeid];
|
|
/* Pick a nearby node */
|
|
if (!node_online(node))
|
|
node = nearby_node(apicid);
|
|
}
|
|
numa_set_node(cpu, node);
|
|
#endif
|
|
}
|
|
|
|
static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
|
|
{
|
|
#ifdef CONFIG_X86_HT
|
|
unsigned bits, ecx;
|
|
|
|
/* Multi core CPU? */
|
|
if (c->extended_cpuid_level < 0x80000008)
|
|
return;
|
|
|
|
ecx = cpuid_ecx(0x80000008);
|
|
|
|
c->x86_max_cores = (ecx & 0xff) + 1;
|
|
|
|
/* CPU telling us the core id bits shift? */
|
|
bits = (ecx >> 12) & 0xF;
|
|
|
|
/* Otherwise recompute */
|
|
if (bits == 0) {
|
|
while ((1 << bits) < c->x86_max_cores)
|
|
bits++;
|
|
}
|
|
|
|
c->x86_coreid_bits = bits;
|
|
#endif
|
|
}
|
|
|
|
static void __cpuinit bsp_init_amd(struct cpuinfo_x86 *c)
|
|
{
|
|
if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
|
|
|
|
if (c->x86 > 0x10 ||
|
|
(c->x86 == 0x10 && c->x86_model >= 0x2)) {
|
|
u64 val;
|
|
|
|
rdmsrl(MSR_K7_HWCR, val);
|
|
if (!(val & BIT(24)))
|
|
printk(KERN_WARNING FW_BUG "TSC doesn't count "
|
|
"with P0 frequency!\n");
|
|
}
|
|
}
|
|
|
|
if (c->x86 == 0x15) {
|
|
unsigned long upperbit;
|
|
u32 cpuid, assoc;
|
|
|
|
cpuid = cpuid_edx(0x80000005);
|
|
assoc = cpuid >> 16 & 0xff;
|
|
upperbit = ((cpuid >> 24) << 10) / assoc;
|
|
|
|
va_align.mask = (upperbit - 1) & PAGE_MASK;
|
|
va_align.flags = ALIGN_VA_32 | ALIGN_VA_64;
|
|
}
|
|
}
|
|
|
|
static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
|
|
{
|
|
early_init_amd_mc(c);
|
|
|
|
/*
|
|
* c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate
|
|
* with P/T states and does not stop in deep C-states
|
|
*/
|
|
if (c->x86_power & (1 << 8)) {
|
|
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
|
|
set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
|
|
if (!check_tsc_unstable())
|
|
sched_clock_stable = 1;
|
|
}
|
|
|
|
#ifdef CONFIG_X86_64
|
|
set_cpu_cap(c, X86_FEATURE_SYSCALL32);
|
|
#else
|
|
/* Set MTRR capability flag if appropriate */
|
|
if (c->x86 == 5)
|
|
if (c->x86_model == 13 || c->x86_model == 9 ||
|
|
(c->x86_model == 8 && c->x86_mask >= 8))
|
|
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
|
|
#endif
|
|
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
|
|
/* check CPU config space for extended APIC ID */
|
|
if (cpu_has_apic && c->x86 >= 0xf) {
|
|
unsigned int val;
|
|
val = read_pci_config(0, 24, 0, 0x68);
|
|
if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18)))
|
|
set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 dummy;
|
|
|
|
#ifdef CONFIG_SMP
|
|
unsigned long long value;
|
|
|
|
/*
|
|
* Disable TLB flush filter by setting HWCR.FFDIS on K8
|
|
* bit 6 of msr C001_0015
|
|
*
|
|
* Errata 63 for SH-B3 steppings
|
|
* Errata 122 for all steppings (F+ have it disabled by default)
|
|
*/
|
|
if (c->x86 == 0xf) {
|
|
rdmsrl(MSR_K7_HWCR, value);
|
|
value |= 1 << 6;
|
|
wrmsrl(MSR_K7_HWCR, value);
|
|
}
|
|
#endif
|
|
|
|
early_init_amd(c);
|
|
|
|
/*
|
|
* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
|
|
* 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
|
|
*/
|
|
clear_cpu_cap(c, 0*32+31);
|
|
|
|
#ifdef CONFIG_X86_64
|
|
/* On C+ stepping K8 rep microcode works well for copy/memset */
|
|
if (c->x86 == 0xf) {
|
|
u32 level;
|
|
|
|
level = cpuid_eax(1);
|
|
if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
|
|
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
|
|
|
|
/*
|
|
* Some BIOSes incorrectly force this feature, but only K8
|
|
* revision D (model = 0x14) and later actually support it.
|
|
* (AMD Erratum #110, docId: 25759).
|
|
*/
|
|
if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM)) {
|
|
u64 val;
|
|
|
|
clear_cpu_cap(c, X86_FEATURE_LAHF_LM);
|
|
if (!rdmsrl_amd_safe(0xc001100d, &val)) {
|
|
val &= ~(1ULL << 32);
|
|
wrmsrl_amd_safe(0xc001100d, val);
|
|
}
|
|
}
|
|
|
|
}
|
|
if (c->x86 >= 0x10)
|
|
set_cpu_cap(c, X86_FEATURE_REP_GOOD);
|
|
|
|
/* get apicid instead of initial apic id from cpuid */
|
|
c->apicid = hard_smp_processor_id();
|
|
#else
|
|
|
|
/*
|
|
* FIXME: We should handle the K5 here. Set up the write
|
|
* range and also turn on MSR 83 bits 4 and 31 (write alloc,
|
|
* no bus pipeline)
|
|
*/
|
|
|
|
switch (c->x86) {
|
|
case 4:
|
|
init_amd_k5(c);
|
|
break;
|
|
case 5:
|
|
init_amd_k6(c);
|
|
break;
|
|
case 6: /* An Athlon/Duron */
|
|
init_amd_k7(c);
|
|
break;
|
|
}
|
|
|
|
/* K6s reports MCEs but don't actually have all the MSRs */
|
|
if (c->x86 < 6)
|
|
clear_cpu_cap(c, X86_FEATURE_MCE);
|
|
#endif
|
|
|
|
/* Enable workaround for FXSAVE leak */
|
|
if (c->x86 >= 6)
|
|
set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
|
|
|
|
if (!c->x86_model_id[0]) {
|
|
switch (c->x86) {
|
|
case 0xf:
|
|
/* Should distinguish Models here, but this is only
|
|
a fallback anyways. */
|
|
strcpy(c->x86_model_id, "Hammer");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* re-enable TopologyExtensions if switched off by BIOS */
|
|
if ((c->x86 == 0x15) &&
|
|
(c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
|
|
!cpu_has(c, X86_FEATURE_TOPOEXT)) {
|
|
u64 val;
|
|
|
|
if (!rdmsrl_safe(0xc0011005, &val)) {
|
|
val |= 1ULL << 54;
|
|
wrmsrl_safe(0xc0011005, val);
|
|
rdmsrl(0xc0011005, val);
|
|
if (val & (1ULL << 54)) {
|
|
set_cpu_cap(c, X86_FEATURE_TOPOEXT);
|
|
printk(KERN_INFO FW_INFO "CPU: Re-enabling "
|
|
"disabled Topology Extensions Support\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The way access filter has a performance penalty on some workloads.
|
|
* Disable it on the affected CPUs.
|
|
*/
|
|
if ((c->x86 == 0x15) &&
|
|
(c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
|
|
u64 val;
|
|
|
|
if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) {
|
|
val |= 0x1E;
|
|
wrmsrl_safe(0xc0011021, val);
|
|
}
|
|
}
|
|
|
|
cpu_detect_cache_sizes(c);
|
|
|
|
/* Multi core CPU? */
|
|
if (c->extended_cpuid_level >= 0x80000008) {
|
|
amd_detect_cmp(c);
|
|
srat_detect_node(c);
|
|
}
|
|
|
|
#ifdef CONFIG_X86_32
|
|
detect_ht(c);
|
|
#endif
|
|
|
|
if (c->extended_cpuid_level >= 0x80000006) {
|
|
if (cpuid_edx(0x80000006) & 0xf000)
|
|
num_cache_leaves = 4;
|
|
else
|
|
num_cache_leaves = 3;
|
|
}
|
|
|
|
if (c->x86 >= 0xf)
|
|
set_cpu_cap(c, X86_FEATURE_K8);
|
|
|
|
if (cpu_has_xmm2) {
|
|
/* MFENCE stops RDTSC speculation */
|
|
set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
|
|
}
|
|
|
|
#ifdef CONFIG_X86_64
|
|
if (c->x86 == 0x10) {
|
|
/* do this for boot cpu */
|
|
if (c == &boot_cpu_data)
|
|
check_enable_amd_mmconf_dmi();
|
|
|
|
fam10h_check_enable_mmcfg();
|
|
}
|
|
|
|
if (c == &boot_cpu_data && c->x86 >= 0xf) {
|
|
unsigned long long tseg;
|
|
|
|
/*
|
|
* Split up direct mapping around the TSEG SMM area.
|
|
* Don't do it for gbpages because there seems very little
|
|
* benefit in doing so.
|
|
*/
|
|
if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
|
|
printk(KERN_DEBUG "tseg: %010llx\n", tseg);
|
|
if ((tseg>>PMD_SHIFT) <
|
|
(max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
|
|
((tseg>>PMD_SHIFT) <
|
|
(max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
|
|
(tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
|
|
set_memory_4k((unsigned long)__va(tseg), 1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Family 0x12 and above processors have APIC timer
|
|
* running in deep C states.
|
|
*/
|
|
if (c->x86 > 0x11)
|
|
set_cpu_cap(c, X86_FEATURE_ARAT);
|
|
|
|
/*
|
|
* Disable GART TLB Walk Errors on Fam10h. We do this here
|
|
* because this is always needed when GART is enabled, even in a
|
|
* kernel which has no MCE support built in.
|
|
*/
|
|
if (c->x86 == 0x10) {
|
|
/*
|
|
* BIOS should disable GartTlbWlk Errors themself. If
|
|
* it doesn't do it here as suggested by the BKDG.
|
|
*
|
|
* Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
|
|
*/
|
|
u64 mask;
|
|
int err;
|
|
|
|
err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
|
|
if (err == 0) {
|
|
mask |= (1 << 10);
|
|
wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
|
|
}
|
|
}
|
|
|
|
rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
|
|
}
|
|
|
|
#ifdef CONFIG_X86_32
|
|
static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c,
|
|
unsigned int size)
|
|
{
|
|
/* AMD errata T13 (order #21922) */
|
|
if ((c->x86 == 6)) {
|
|
/* Duron Rev A0 */
|
|
if (c->x86_model == 3 && c->x86_mask == 0)
|
|
size = 64;
|
|
/* Tbird rev A1/A2 */
|
|
if (c->x86_model == 4 &&
|
|
(c->x86_mask == 0 || c->x86_mask == 1))
|
|
size = 256;
|
|
}
|
|
return size;
|
|
}
|
|
#endif
|
|
|
|
static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)
|
|
{
|
|
if (!cpu_has_invlpg)
|
|
return;
|
|
|
|
tlb_flushall_shift = 5;
|
|
|
|
if (c->x86 <= 0x11)
|
|
tlb_flushall_shift = 4;
|
|
}
|
|
|
|
static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
|
|
{
|
|
u32 ebx, eax, ecx, edx;
|
|
u16 mask = 0xfff;
|
|
|
|
if (c->x86 < 0xf)
|
|
return;
|
|
|
|
if (c->extended_cpuid_level < 0x80000006)
|
|
return;
|
|
|
|
cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
|
|
|
|
tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask;
|
|
tlb_lli_4k[ENTRIES] = ebx & mask;
|
|
|
|
/*
|
|
* K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
|
|
* characteristics from the CPUID function 0x80000005 instead.
|
|
*/
|
|
if (c->x86 == 0xf) {
|
|
cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
|
|
mask = 0xff;
|
|
}
|
|
|
|
/* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
|
|
if (!((eax >> 16) & mask)) {
|
|
u32 a, b, c, d;
|
|
|
|
cpuid(0x80000005, &a, &b, &c, &d);
|
|
tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff;
|
|
} else {
|
|
tlb_lld_2m[ENTRIES] = (eax >> 16) & mask;
|
|
}
|
|
|
|
/* a 4M entry uses two 2M entries */
|
|
tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1;
|
|
|
|
/* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
|
|
if (!(eax & mask)) {
|
|
/* Erratum 658 */
|
|
if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
|
|
tlb_lli_2m[ENTRIES] = 1024;
|
|
} else {
|
|
cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
|
|
tlb_lli_2m[ENTRIES] = eax & 0xff;
|
|
}
|
|
} else
|
|
tlb_lli_2m[ENTRIES] = eax & mask;
|
|
|
|
tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1;
|
|
|
|
cpu_set_tlb_flushall_shift(c);
|
|
}
|
|
|
|
static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
|
|
.c_vendor = "AMD",
|
|
.c_ident = { "AuthenticAMD" },
|
|
#ifdef CONFIG_X86_32
|
|
.c_models = {
|
|
{ .vendor = X86_VENDOR_AMD, .family = 4, .model_names =
|
|
{
|
|
[3] = "486 DX/2",
|
|
[7] = "486 DX/2-WB",
|
|
[8] = "486 DX/4",
|
|
[9] = "486 DX/4-WB",
|
|
[14] = "Am5x86-WT",
|
|
[15] = "Am5x86-WB"
|
|
}
|
|
},
|
|
},
|
|
.c_size_cache = amd_size_cache,
|
|
#endif
|
|
.c_early_init = early_init_amd,
|
|
.c_detect_tlb = cpu_detect_tlb_amd,
|
|
.c_bsp_init = bsp_init_amd,
|
|
.c_init = init_amd,
|
|
.c_x86_vendor = X86_VENDOR_AMD,
|
|
};
|
|
|
|
cpu_dev_register(amd_cpu_dev);
|
|
|
|
/*
|
|
* AMD errata checking
|
|
*
|
|
* Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
|
|
* AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
|
|
* have an OSVW id assigned, which it takes as first argument. Both take a
|
|
* variable number of family-specific model-stepping ranges created by
|
|
* AMD_MODEL_RANGE(). Each erratum also has to be declared as extern const
|
|
* int[] in arch/x86/include/asm/processor.h.
|
|
*
|
|
* Example:
|
|
*
|
|
* const int amd_erratum_319[] =
|
|
* AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
|
|
* AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
|
|
* AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
|
|
*/
|
|
|
|
const int amd_erratum_400[] =
|
|
AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
|
|
AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
|
|
EXPORT_SYMBOL_GPL(amd_erratum_400);
|
|
|
|
const int amd_erratum_383[] =
|
|
AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
|
|
EXPORT_SYMBOL_GPL(amd_erratum_383);
|
|
|
|
bool cpu_has_amd_erratum(const int *erratum)
|
|
{
|
|
struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
|
|
int osvw_id = *erratum++;
|
|
u32 range;
|
|
u32 ms;
|
|
|
|
/*
|
|
* If called early enough that current_cpu_data hasn't been initialized
|
|
* yet, fall back to boot_cpu_data.
|
|
*/
|
|
if (cpu->x86 == 0)
|
|
cpu = &boot_cpu_data;
|
|
|
|
if (cpu->x86_vendor != X86_VENDOR_AMD)
|
|
return false;
|
|
|
|
if (osvw_id >= 0 && osvw_id < 65536 &&
|
|
cpu_has(cpu, X86_FEATURE_OSVW)) {
|
|
u64 osvw_len;
|
|
|
|
rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
|
|
if (osvw_id < osvw_len) {
|
|
u64 osvw_bits;
|
|
|
|
rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
|
|
osvw_bits);
|
|
return osvw_bits & (1ULL << (osvw_id & 0x3f));
|
|
}
|
|
}
|
|
|
|
/* OSVW unavailable or ID unknown, match family-model-stepping range */
|
|
ms = (cpu->x86_model << 4) | cpu->x86_mask;
|
|
while ((range = *erratum++))
|
|
if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
|
|
(ms >= AMD_MODEL_RANGE_START(range)) &&
|
|
(ms <= AMD_MODEL_RANGE_END(range)))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(cpu_has_amd_erratum);
|