diff options
-rw-r--r-- | arch/x86/include/asm/hardirq.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/amd.c | 67 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/intel.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/irq.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/tlb.c | 4 |
6 files changed, 82 insertions, 6 deletions
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index d3895dbf4ddb..81f04cee5f74 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h | |||
@@ -18,6 +18,10 @@ typedef struct { | |||
18 | #ifdef CONFIG_SMP | 18 | #ifdef CONFIG_SMP |
19 | unsigned int irq_resched_count; | 19 | unsigned int irq_resched_count; |
20 | unsigned int irq_call_count; | 20 | unsigned int irq_call_count; |
21 | /* | ||
22 | * irq_tlb_count is double-counted in irq_call_count, so it must be | ||
23 | * subtracted from irq_call_count when displaying irq_call_count | ||
24 | */ | ||
21 | unsigned int irq_tlb_count; | 25 | unsigned int irq_tlb_count; |
22 | #endif | 26 | #endif |
23 | #ifdef CONFIG_X86_THERMAL_VECTOR | 27 | #ifdef CONFIG_X86_THERMAL_VECTOR |
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 9d92e19039f0..f7e98a2c0d12 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -737,6 +737,72 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, | |||
737 | } | 737 | } |
738 | #endif | 738 | #endif |
739 | 739 | ||
740 | static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c) | ||
741 | { | ||
742 | if (!cpu_has_invlpg) | ||
743 | return; | ||
744 | |||
745 | tlb_flushall_shift = 5; | ||
746 | |||
747 | if (c->x86 <= 0x11) | ||
748 | tlb_flushall_shift = 4; | ||
749 | } | ||
750 | |||
751 | static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c) | ||
752 | { | ||
753 | u32 ebx, eax, ecx, edx; | ||
754 | u16 mask = 0xfff; | ||
755 | |||
756 | if (c->x86 < 0xf) | ||
757 | return; | ||
758 | |||
759 | if (c->extended_cpuid_level < 0x80000006) | ||
760 | return; | ||
761 | |||
762 | cpuid(0x80000006, &eax, &ebx, &ecx, &edx); | ||
763 | |||
764 | tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask; | ||
765 | tlb_lli_4k[ENTRIES] = ebx & mask; | ||
766 | |||
767 | /* | ||
768 | * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB | ||
769 | * characteristics from the CPUID function 0x80000005 instead. | ||
770 | */ | ||
771 | if (c->x86 == 0xf) { | ||
772 | cpuid(0x80000005, &eax, &ebx, &ecx, &edx); | ||
773 | mask = 0xff; | ||
774 | } | ||
775 | |||
776 | /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ | ||
777 | if (!((eax >> 16) & mask)) { | ||
778 | u32 a, b, c, d; | ||
779 | |||
780 | cpuid(0x80000005, &a, &b, &c, &d); | ||
781 | tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff; | ||
782 | } else { | ||
783 | tlb_lld_2m[ENTRIES] = (eax >> 16) & mask; | ||
784 | } | ||
785 | |||
786 | /* a 4M entry uses two 2M entries */ | ||
787 | tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1; | ||
788 | |||
789 | /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ | ||
790 | if (!(eax & mask)) { | ||
791 | /* Erratum 658 */ | ||
792 | if (c->x86 == 0x15 && c->x86_model <= 0x1f) { | ||
793 | tlb_lli_2m[ENTRIES] = 1024; | ||
794 | } else { | ||
795 | cpuid(0x80000005, &eax, &ebx, &ecx, &edx); | ||
796 | tlb_lli_2m[ENTRIES] = eax & 0xff; | ||
797 | } | ||
798 | } else | ||
799 | tlb_lli_2m[ENTRIES] = eax & mask; | ||
800 | |||
801 | tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1; | ||
802 | |||
803 | cpu_set_tlb_flushall_shift(c); | ||
804 | } | ||
805 | |||
740 | static const struct cpu_dev __cpuinitconst amd_cpu_dev = { | 806 | static const struct cpu_dev __cpuinitconst amd_cpu_dev = { |
741 | .c_vendor = "AMD", | 807 | .c_vendor = "AMD", |
742 | .c_ident = { "AuthenticAMD" }, | 808 | .c_ident = { "AuthenticAMD" }, |
@@ -756,6 +822,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = { | |||
756 | .c_size_cache = amd_size_cache, | 822 | .c_size_cache = amd_size_cache, |
757 | #endif | 823 | #endif |
758 | .c_early_init = early_init_amd, | 824 | .c_early_init = early_init_amd, |
825 | .c_detect_tlb = cpu_detect_tlb_amd, | ||
759 | .c_bsp_init = bsp_init_amd, | 826 | .c_bsp_init = bsp_init_amd, |
760 | .c_init = init_amd, | 827 | .c_init = init_amd, |
761 | .c_x86_vendor = X86_VENDOR_AMD, | 828 | .c_x86_vendor = X86_VENDOR_AMD, |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 761cb3547041..532691b6c8fe 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -476,7 +476,7 @@ void __cpuinit cpu_detect_tlb(struct cpuinfo_x86 *c) | |||
476 | 476 | ||
477 | printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \ | 477 | printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \ |
478 | "Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \ | 478 | "Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \ |
479 | "tlb_flushall_shift is 0x%x\n", | 479 | "tlb_flushall_shift: %d\n", |
480 | tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES], | 480 | tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES], |
481 | tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES], | 481 | tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES], |
482 | tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES], | 482 | tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES], |
@@ -942,8 +942,7 @@ void __init identify_boot_cpu(void) | |||
942 | #else | 942 | #else |
943 | vgetcpu_set_mode(); | 943 | vgetcpu_set_mode(); |
944 | #endif | 944 | #endif |
945 | if (boot_cpu_data.cpuid_level >= 2) | 945 | cpu_detect_tlb(&boot_cpu_data); |
946 | cpu_detect_tlb(&boot_cpu_data); | ||
947 | } | 946 | } |
948 | 947 | ||
949 | void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) | 948 | void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 0a4ce2980a5a..198e019a531a 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -648,6 +648,10 @@ static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c) | |||
648 | int i, j, n; | 648 | int i, j, n; |
649 | unsigned int regs[4]; | 649 | unsigned int regs[4]; |
650 | unsigned char *desc = (unsigned char *)regs; | 650 | unsigned char *desc = (unsigned char *)regs; |
651 | |||
652 | if (c->cpuid_level < 2) | ||
653 | return; | ||
654 | |||
651 | /* Number of times to iterate */ | 655 | /* Number of times to iterate */ |
652 | n = cpuid_eax(2) & 0xFF; | 656 | n = cpuid_eax(2) & 0xFF; |
653 | 657 | ||
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index d44f7829968e..e4595f105910 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c | |||
@@ -92,7 +92,8 @@ int arch_show_interrupts(struct seq_file *p, int prec) | |||
92 | seq_printf(p, " Rescheduling interrupts\n"); | 92 | seq_printf(p, " Rescheduling interrupts\n"); |
93 | seq_printf(p, "%*s: ", prec, "CAL"); | 93 | seq_printf(p, "%*s: ", prec, "CAL"); |
94 | for_each_online_cpu(j) | 94 | for_each_online_cpu(j) |
95 | seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); | 95 | seq_printf(p, "%10u ", irq_stats(j)->irq_call_count - |
96 | irq_stats(j)->irq_tlb_count); | ||
96 | seq_printf(p, " Function call interrupts\n"); | 97 | seq_printf(p, " Function call interrupts\n"); |
97 | seq_printf(p, "%*s: ", prec, "TLB"); | 98 | seq_printf(p, "%*s: ", prec, "TLB"); |
98 | for_each_online_cpu(j) | 99 | for_each_online_cpu(j) |
@@ -147,7 +148,6 @@ u64 arch_irq_stat_cpu(unsigned int cpu) | |||
147 | #ifdef CONFIG_SMP | 148 | #ifdef CONFIG_SMP |
148 | sum += irq_stats(cpu)->irq_resched_count; | 149 | sum += irq_stats(cpu)->irq_resched_count; |
149 | sum += irq_stats(cpu)->irq_call_count; | 150 | sum += irq_stats(cpu)->irq_call_count; |
150 | sum += irq_stats(cpu)->irq_tlb_count; | ||
151 | #endif | 151 | #endif |
152 | #ifdef CONFIG_X86_THERMAL_VECTOR | 152 | #ifdef CONFIG_X86_THERMAL_VECTOR |
153 | sum += irq_stats(cpu)->irq_thermal_count; | 153 | sum += irq_stats(cpu)->irq_thermal_count; |
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 613cd83e8c0c..0777f042e400 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c | |||
@@ -98,6 +98,8 @@ static void flush_tlb_func(void *info) | |||
98 | { | 98 | { |
99 | struct flush_tlb_info *f = info; | 99 | struct flush_tlb_info *f = info; |
100 | 100 | ||
101 | inc_irq_stat(irq_tlb_count); | ||
102 | |||
101 | if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm)) | 103 | if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm)) |
102 | return; | 104 | return; |
103 | 105 | ||
@@ -320,7 +322,7 @@ static ssize_t tlbflush_write_file(struct file *file, | |||
320 | if (kstrtos8(buf, 0, &shift)) | 322 | if (kstrtos8(buf, 0, &shift)) |
321 | return -EINVAL; | 323 | return -EINVAL; |
322 | 324 | ||
323 | if (shift > 64) | 325 | if (shift < -1 || shift >= BITS_PER_LONG) |
324 | return -EINVAL; | 326 | return -EINVAL; |
325 | 327 | ||
326 | tlb_flushall_shift = shift; | 328 | tlb_flushall_shift = shift; |