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; |
