x86/tlb_info: get last level TLB entry number of CPU
[firefly-linux-kernel-4.4.55.git] / arch / x86 / kernel / cpu / intel.c
index 3e6ff6cbf42af90b87ff625cee1d9d785802656d..ed0d512cf51b3c7b08d58b2545fc9350ca3bafad 100644 (file)
@@ -491,6 +491,147 @@ static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned i
 }
 #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_DATA0_4K   0x21
+#define TLB_DATA0_4M   0x22
+#define TLB_DATA0_2M_4M        0x23
+
+#define STLB_4K                0x41
+
+static const struct _tlb_table intel_tlb_table[] __cpuinitconst = {
+       { 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" },
+       { 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" },
+       { 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" },
+       { 0xca, STLB_4K,                512,    " STLB 4 KByte pages, 4-way associative" },
+       { 0x00, 0, 0 }
+};
+
+static void __cpuinit intel_tlb_lookup(const unsigned char desc)
+{
+       unsigned char k;
+       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;
+
+       switch (intel_tlb_table[k].tlb_type) {
+       case STLB_4K:
+               if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_INST_ALL:
+               if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lli_2m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_2m[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_INST_4K:
+               if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_INST_4M:
+               if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_INST_2M_4M:
+               if (tlb_lli_2m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_2m[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_DATA_4K:
+       case TLB_DATA0_4K:
+               if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_DATA_4M:
+       case TLB_DATA0_4M:
+               if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_DATA_2M_4M:
+       case TLB_DATA0_2M_4M:
+               if (tlb_lld_2m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_2m[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       case TLB_DATA_4K_4M:
+               if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
+               if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
+                       tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
+               break;
+       }
+}
+
+static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c)
+{
+       int i, j, n;
+       unsigned int regs[4];
+       unsigned char *desc = (unsigned char *)regs;
+       /* Number of times to iterate */
+       n = cpuid_eax(2) & 0xFF;
+
+       for (i = 0 ; i < n ; i++) {
+               cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
+
+               /* If bit 31 is set, this is an unknown format */
+               for (j = 0 ; j < 3 ; 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]);
+       }
+}
+
 static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
        .c_vendor       = "Intel",
        .c_ident        = { "GenuineIntel" },
@@ -546,6 +687,7 @@ static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
        },
        .c_size_cache   = intel_size_cache,
 #endif
+       .c_detect_tlb   = intel_detect_tlb,
        .c_early_init   = early_init_intel,
        .c_init         = init_intel,
        .c_x86_vendor   = X86_VENDOR_INTEL,