aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@amd.com>2010-07-28 13:09:30 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2010-07-28 16:12:04 -0400
commitd78d671db478eb8b14c78501c0cee1cc7baf6967 (patch)
tree584432da234b4c50a7e1500459d6ada7d7517cc3 /arch
parent7d50d07da23995a18ac449636cb42aec2cb2808d (diff)
x86, cpu: AMD errata checking framework
Errata are defined 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(). Iff an erratum has an OSVW id, OSVW is available on the CPU, and the OSVW id is known to the hardware, it is used to determine whether an erratum is present. Otherwise, the model-stepping ranges are matched against the current CPU to find out whether the erratum applies. For certain special errata, the code using this framework might have to conduct further checks to make sure an erratum is really (not) present. Signed-off-by: Hans Rosenfeld <hans.rosenfeld@amd.com> LKML-Reference: <1280336972-865982-1-git-send-email-hans.rosenfeld@amd.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/processor.h18
-rw-r--r--arch/x86/kernel/cpu/amd.c60
2 files changed, 78 insertions, 0 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 7e5c6a60b8ee..5084c2f5ac20 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -1025,4 +1025,22 @@ unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
1025 return ratio; 1025 return ratio;
1026} 1026}
1027 1027
1028/*
1029 * AMD errata checking
1030 */
1031#ifdef CONFIG_CPU_SUP_AMD
1032extern bool cpu_has_amd_erratum(const int *);
1033
1034#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
1035#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
1036#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
1037 ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
1038#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
1039#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
1040#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
1041
1042#else
1043#define cpu_has_amd_erratum(x) (false)
1044#endif /* CONFIG_CPU_SUP_AMD */
1045
1028#endif /* _ASM_X86_PROCESSOR_H */ 1046#endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 12b9cff047c1..80665410b064 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -609,3 +609,63 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
609}; 609};
610 610
611cpu_dev_register(amd_cpu_dev); 611cpu_dev_register(amd_cpu_dev);
612
613/*
614 * AMD errata checking
615 *
616 * Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or
617 * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
618 * have an OSVW id assigned, which it takes as first argument. Both take a
619 * variable number of family-specific model-stepping ranges created by
620 * AMD_MODEL_RANGE(). Each erratum also has to be declared as extern const
621 * int[] in arch/x86/include/asm/processor.h.
622 *
623 * Example:
624 *
625 * const int amd_erratum_319[] =
626 * AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2),
627 * AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0),
628 * AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
629 */
630
631bool cpu_has_amd_erratum(const int *erratum)
632{
633 struct cpuinfo_x86 *cpu = &current_cpu_data;
634 int osvw_id = *erratum++;
635 u32 range;
636 u32 ms;
637
638 /*
639 * If called early enough that current_cpu_data hasn't been initialized
640 * yet, fall back to boot_cpu_data.
641 */
642 if (cpu->x86 == 0)
643 cpu = &boot_cpu_data;
644
645 if (cpu->x86_vendor != X86_VENDOR_AMD)
646 return false;
647
648 if (osvw_id >= 0 && osvw_id < 65536 &&
649 cpu_has(cpu, X86_FEATURE_OSVW)) {
650 u64 osvw_len;
651
652 rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len);
653 if (osvw_id < osvw_len) {
654 u64 osvw_bits;
655
656 rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6),
657 osvw_bits);
658 return osvw_bits & (1ULL << (osvw_id & 0x3f));
659 }
660 }
661
662 /* OSVW unavailable or ID unknown, match family-model-stepping range */
663 ms = (cpu->x86_model << 8) | cpu->x86_mask;
664 while ((range = *erratum++))
665 if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) &&
666 (ms >= AMD_MODEL_RANGE_START(range)) &&
667 (ms <= AMD_MODEL_RANGE_END(range)))
668 return true;
669
670 return false;
671}