diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2012-08-06 13:00:38 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-08-06 22:18:34 -0400 |
commit | b46882e4c4de4813947fce940fe74af794a1eb72 (patch) | |
tree | 786c342272340043c3415b9348fe6fcc3366f9bf | |
parent | 5b556332c3ab19e6375836d35ca658776e9ba0f6 (diff) |
x86, cpu: Add AMD TLB size detection
Read I- and DTLB entries count from CPUID on AMD. Handle all the
different family-specific cases.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Link: http://lkml.kernel.org/r/1344272439-29080-4-git-send-email-bp@amd64.org
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 9d92e19039f0..bcd200839c90 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -737,6 +737,59 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, | |||
737 | } | 737 | } |
738 | #endif | 738 | #endif |
739 | 739 | ||
740 | static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c) | ||
741 | { | ||
742 | u32 ebx, eax, ecx, edx; | ||
743 | u16 mask = 0xfff; | ||
744 | |||
745 | if (c->x86 < 0xf) | ||
746 | return; | ||
747 | |||
748 | if (c->extended_cpuid_level < 0x80000006) | ||
749 | return; | ||
750 | |||
751 | cpuid(0x80000006, &eax, &ebx, &ecx, &edx); | ||
752 | |||
753 | tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask; | ||
754 | tlb_lli_4k[ENTRIES] = ebx & mask; | ||
755 | |||
756 | /* | ||
757 | * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB | ||
758 | * characteristics from the CPUID function 0x80000005 instead. | ||
759 | */ | ||
760 | if (c->x86 == 0xf) { | ||
761 | cpuid(0x80000005, &eax, &ebx, &ecx, &edx); | ||
762 | mask = 0xff; | ||
763 | } | ||
764 | |||
765 | /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ | ||
766 | if (!((eax >> 16) & mask)) { | ||
767 | u32 a, b, c, d; | ||
768 | |||
769 | cpuid(0x80000005, &a, &b, &c, &d); | ||
770 | tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff; | ||
771 | } else { | ||
772 | tlb_lld_2m[ENTRIES] = (eax >> 16) & mask; | ||
773 | } | ||
774 | |||
775 | /* a 4M entry uses two 2M entries */ | ||
776 | tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1; | ||
777 | |||
778 | /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ | ||
779 | if (!(eax & mask)) { | ||
780 | /* Erratum 658 */ | ||
781 | if (c->x86 == 0x15 && c->x86_model <= 0x1f) { | ||
782 | tlb_lli_2m[ENTRIES] = 1024; | ||
783 | } else { | ||
784 | cpuid(0x80000005, &eax, &ebx, &ecx, &edx); | ||
785 | tlb_lli_2m[ENTRIES] = eax & 0xff; | ||
786 | } | ||
787 | } else | ||
788 | tlb_lli_2m[ENTRIES] = eax & mask; | ||
789 | |||
790 | tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1; | ||
791 | } | ||
792 | |||
740 | static const struct cpu_dev __cpuinitconst amd_cpu_dev = { | 793 | static const struct cpu_dev __cpuinitconst amd_cpu_dev = { |
741 | .c_vendor = "AMD", | 794 | .c_vendor = "AMD", |
742 | .c_ident = { "AuthenticAMD" }, | 795 | .c_ident = { "AuthenticAMD" }, |
@@ -756,6 +809,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = { | |||
756 | .c_size_cache = amd_size_cache, | 809 | .c_size_cache = amd_size_cache, |
757 | #endif | 810 | #endif |
758 | .c_early_init = early_init_amd, | 811 | .c_early_init = early_init_amd, |
812 | .c_detect_tlb = cpu_detect_tlb_amd, | ||
759 | .c_bsp_init = bsp_init_amd, | 813 | .c_bsp_init = bsp_init_amd, |
760 | .c_init = init_amd, | 814 | .c_init = init_amd, |
761 | .c_x86_vendor = X86_VENDOR_AMD, | 815 | .c_x86_vendor = X86_VENDOR_AMD, |