Skip to content

Commit e0ba94f

Browse files
Alex ShiH. Peter Anvin
authored andcommitted
x86/tlb_info: get last level TLB entry number of CPU
For 4KB pages, x86 CPU has 2 or 1 level TLB, first level is data TLB and instruction TLB, second level is shared TLB for both data and instructions. For hupe page TLB, usually there is just one level and seperated by 2MB/4MB and 1GB. Although each levels TLB size is important for performance tuning, but for genernal and rude optimizing, last level TLB entry number is suitable. And in fact, last level TLB always has the biggest entry number. This patch will get the biggest TLB entry number and use it in furture TLB optimizing. Accroding Borislav's suggestion, except tlb_ll[i/d]_* array, other function and data will be released after system boot up. For all kinds of x86 vendor friendly, vendor specific code was moved to its specific files. Signed-off-by: Alex Shi <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: H. Peter Anvin <[email protected]>
1 parent 0816b0f commit e0ba94f

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

arch/x86/include/asm/processor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ static inline void *current_text_addr(void)
6161
# define ARCH_MIN_MMSTRUCT_ALIGN 0
6262
#endif
6363

64+
enum tlb_infos {
65+
ENTRIES,
66+
NR_INFO
67+
};
68+
69+
extern u16 __read_mostly tlb_lli_4k[NR_INFO];
70+
extern u16 __read_mostly tlb_lli_2m[NR_INFO];
71+
extern u16 __read_mostly tlb_lli_4m[NR_INFO];
72+
extern u16 __read_mostly tlb_lld_4k[NR_INFO];
73+
extern u16 __read_mostly tlb_lld_2m[NR_INFO];
74+
extern u16 __read_mostly tlb_lld_4m[NR_INFO];
6475
/*
6576
* CPU type and hardware bug flags. Kept separately for each CPU.
6677
* Members of this structure are referenced in head.S, so think twice

arch/x86/kernel/cpu/common.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,25 @@ void __cpuinit cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
452452
c->x86_cache_size = l2size;
453453
}
454454

455+
u16 __read_mostly tlb_lli_4k[NR_INFO];
456+
u16 __read_mostly tlb_lli_2m[NR_INFO];
457+
u16 __read_mostly tlb_lli_4m[NR_INFO];
458+
u16 __read_mostly tlb_lld_4k[NR_INFO];
459+
u16 __read_mostly tlb_lld_2m[NR_INFO];
460+
u16 __read_mostly tlb_lld_4m[NR_INFO];
461+
462+
void __cpuinit cpu_detect_tlb(struct cpuinfo_x86 *c)
463+
{
464+
if (this_cpu->c_detect_tlb)
465+
this_cpu->c_detect_tlb(c);
466+
467+
printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
468+
"Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n",
469+
tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES],
470+
tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES],
471+
tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES]);
472+
}
473+
455474
void __cpuinit detect_ht(struct cpuinfo_x86 *c)
456475
{
457476
#ifdef CONFIG_X86_HT
@@ -911,6 +930,8 @@ void __init identify_boot_cpu(void)
911930
#else
912931
vgetcpu_set_mode();
913932
#endif
933+
if (boot_cpu_data.cpuid_level >= 2)
934+
cpu_detect_tlb(&boot_cpu_data);
914935
}
915936

916937
void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)

arch/x86/kernel/cpu/cpu.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@ struct cpu_dev {
2020
void (*c_bsp_init)(struct cpuinfo_x86 *);
2121
void (*c_init)(struct cpuinfo_x86 *);
2222
void (*c_identify)(struct cpuinfo_x86 *);
23+
void (*c_detect_tlb)(struct cpuinfo_x86 *);
2324
unsigned int (*c_size_cache)(struct cpuinfo_x86 *, unsigned int);
2425
int c_x86_vendor;
2526
};
2627

28+
struct _tlb_table {
29+
unsigned char descriptor;
30+
char tlb_type;
31+
unsigned int entries;
32+
/* unsigned int ways; */
33+
char info[128];
34+
};
35+
2736
#define cpu_dev_register(cpu_devX) \
2837
static const struct cpu_dev *const __cpu_dev_##cpu_devX __used \
2938
__attribute__((__section__(".x86_cpu_dev.init"))) = \

arch/x86/kernel/cpu/intel.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,147 @@ static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned i
491491
}
492492
#endif
493493

494+
#define TLB_INST_4K 0x01
495+
#define TLB_INST_4M 0x02
496+
#define TLB_INST_2M_4M 0x03
497+
498+
#define TLB_INST_ALL 0x05
499+
#define TLB_INST_1G 0x06
500+
501+
#define TLB_DATA_4K 0x11
502+
#define TLB_DATA_4M 0x12
503+
#define TLB_DATA_2M_4M 0x13
504+
#define TLB_DATA_4K_4M 0x14
505+
506+
#define TLB_DATA_1G 0x16
507+
508+
#define TLB_DATA0_4K 0x21
509+
#define TLB_DATA0_4M 0x22
510+
#define TLB_DATA0_2M_4M 0x23
511+
512+
#define STLB_4K 0x41
513+
514+
static const struct _tlb_table intel_tlb_table[] __cpuinitconst = {
515+
{ 0x01, TLB_INST_4K, 32, " TLB_INST 4 KByte pages, 4-way set associative" },
516+
{ 0x02, TLB_INST_4M, 2, " TLB_INST 4 MByte pages, full associative" },
517+
{ 0x03, TLB_DATA_4K, 64, " TLB_DATA 4 KByte pages, 4-way set associative" },
518+
{ 0x04, TLB_DATA_4M, 8, " TLB_DATA 4 MByte pages, 4-way set associative" },
519+
{ 0x05, TLB_DATA_4M, 32, " TLB_DATA 4 MByte pages, 4-way set associative" },
520+
{ 0x0b, TLB_INST_4M, 4, " TLB_INST 4 MByte pages, 4-way set associative" },
521+
{ 0x4f, TLB_INST_4K, 32, " TLB_INST 4 KByte pages */" },
522+
{ 0x50, TLB_INST_ALL, 64, " TLB_INST 4 KByte and 2-MByte or 4-MByte pages" },
523+
{ 0x51, TLB_INST_ALL, 128, " TLB_INST 4 KByte and 2-MByte or 4-MByte pages" },
524+
{ 0x52, TLB_INST_ALL, 256, " TLB_INST 4 KByte and 2-MByte or 4-MByte pages" },
525+
{ 0x55, TLB_INST_2M_4M, 7, " TLB_INST 2-MByte or 4-MByte pages, fully associative" },
526+
{ 0x56, TLB_DATA0_4M, 16, " TLB_DATA0 4 MByte pages, 4-way set associative" },
527+
{ 0x57, TLB_DATA0_4K, 16, " TLB_DATA0 4 KByte pages, 4-way associative" },
528+
{ 0x59, TLB_DATA0_4K, 16, " TLB_DATA0 4 KByte pages, fully associative" },
529+
{ 0x5a, TLB_DATA0_2M_4M, 32, " TLB_DATA0 2-MByte or 4 MByte pages, 4-way set associative" },
530+
{ 0x5b, TLB_DATA_4K_4M, 64, " TLB_DATA 4 KByte and 4 MByte pages" },
531+
{ 0x5c, TLB_DATA_4K_4M, 128, " TLB_DATA 4 KByte and 4 MByte pages" },
532+
{ 0x5d, TLB_DATA_4K_4M, 256, " TLB_DATA 4 KByte and 4 MByte pages" },
533+
{ 0xb0, TLB_INST_4K, 128, " TLB_INST 4 KByte pages, 4-way set associative" },
534+
{ 0xb1, TLB_INST_2M_4M, 4, " TLB_INST 2M pages, 4-way, 8 entries or 4M pages, 4-way entries" },
535+
{ 0xb2, TLB_INST_4K, 64, " TLB_INST 4KByte pages, 4-way set associative" },
536+
{ 0xb3, TLB_DATA_4K, 128, " TLB_DATA 4 KByte pages, 4-way set associative" },
537+
{ 0xb4, TLB_DATA_4K, 256, " TLB_DATA 4 KByte pages, 4-way associative" },
538+
{ 0xba, TLB_DATA_4K, 64, " TLB_DATA 4 KByte pages, 4-way associative" },
539+
{ 0xc0, TLB_DATA_4K_4M, 8, " TLB_DATA 4 KByte and 4 MByte pages, 4-way associative" },
540+
{ 0xca, STLB_4K, 512, " STLB 4 KByte pages, 4-way associative" },
541+
{ 0x00, 0, 0 }
542+
};
543+
544+
static void __cpuinit intel_tlb_lookup(const unsigned char desc)
545+
{
546+
unsigned char k;
547+
if (desc == 0)
548+
return;
549+
550+
/* look up this descriptor in the table */
551+
for (k = 0; intel_tlb_table[k].descriptor != desc && \
552+
intel_tlb_table[k].descriptor != 0; k++)
553+
;
554+
555+
if (intel_tlb_table[k].tlb_type == 0)
556+
return;
557+
558+
switch (intel_tlb_table[k].tlb_type) {
559+
case STLB_4K:
560+
if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
561+
tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
562+
if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
563+
tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
564+
break;
565+
case TLB_INST_ALL:
566+
if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
567+
tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
568+
if (tlb_lli_2m[ENTRIES] < intel_tlb_table[k].entries)
569+
tlb_lli_2m[ENTRIES] = intel_tlb_table[k].entries;
570+
if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
571+
tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
572+
break;
573+
case TLB_INST_4K:
574+
if (tlb_lli_4k[ENTRIES] < intel_tlb_table[k].entries)
575+
tlb_lli_4k[ENTRIES] = intel_tlb_table[k].entries;
576+
break;
577+
case TLB_INST_4M:
578+
if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
579+
tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
580+
break;
581+
case TLB_INST_2M_4M:
582+
if (tlb_lli_2m[ENTRIES] < intel_tlb_table[k].entries)
583+
tlb_lli_2m[ENTRIES] = intel_tlb_table[k].entries;
584+
if (tlb_lli_4m[ENTRIES] < intel_tlb_table[k].entries)
585+
tlb_lli_4m[ENTRIES] = intel_tlb_table[k].entries;
586+
break;
587+
case TLB_DATA_4K:
588+
case TLB_DATA0_4K:
589+
if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
590+
tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
591+
break;
592+
case TLB_DATA_4M:
593+
case TLB_DATA0_4M:
594+
if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
595+
tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
596+
break;
597+
case TLB_DATA_2M_4M:
598+
case TLB_DATA0_2M_4M:
599+
if (tlb_lld_2m[ENTRIES] < intel_tlb_table[k].entries)
600+
tlb_lld_2m[ENTRIES] = intel_tlb_table[k].entries;
601+
if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
602+
tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
603+
break;
604+
case TLB_DATA_4K_4M:
605+
if (tlb_lld_4k[ENTRIES] < intel_tlb_table[k].entries)
606+
tlb_lld_4k[ENTRIES] = intel_tlb_table[k].entries;
607+
if (tlb_lld_4m[ENTRIES] < intel_tlb_table[k].entries)
608+
tlb_lld_4m[ENTRIES] = intel_tlb_table[k].entries;
609+
break;
610+
}
611+
}
612+
613+
static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c)
614+
{
615+
int i, j, n;
616+
unsigned int regs[4];
617+
unsigned char *desc = (unsigned char *)regs;
618+
/* Number of times to iterate */
619+
n = cpuid_eax(2) & 0xFF;
620+
621+
for (i = 0 ; i < n ; i++) {
622+
cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
623+
624+
/* If bit 31 is set, this is an unknown format */
625+
for (j = 0 ; j < 3 ; j++)
626+
if (regs[j] & (1 << 31))
627+
regs[j] = 0;
628+
629+
/* Byte 0 is level count, not a descriptor */
630+
for (j = 1 ; j < 16 ; j++)
631+
intel_tlb_lookup(desc[j]);
632+
}
633+
}
634+
494635
static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
495636
.c_vendor = "Intel",
496637
.c_ident = { "GenuineIntel" },
@@ -546,6 +687,7 @@ static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
546687
},
547688
.c_size_cache = intel_size_cache,
548689
#endif
690+
.c_detect_tlb = intel_detect_tlb,
549691
.c_early_init = early_init_intel,
550692
.c_init = init_intel,
551693
.c_x86_vendor = X86_VENDOR_INTEL,

0 commit comments

Comments
 (0)