diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-12-29 03:45:15 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-12-29 03:45:15 -0500 |
| commit | e1df957670aef74ffd9a4ad93e6d2c90bf6b4845 (patch) | |
| tree | bca1fcfef55b3e3e82c9a822b4ac6428fce2b419 /arch/x86/kernel/cpu | |
| parent | 2b583d8bc8d7105b58d7481a4a0ceb718dac49c6 (diff) | |
| parent | 3c92ec8ae91ecf59d88c798301833d7cf83f2179 (diff) | |
Merge branch 'linus' into perfcounters/core
Conflicts:
fs/exec.c
include/linux/init_task.h
Simple context conflicts.
Diffstat (limited to 'arch/x86/kernel/cpu')
| -rw-r--r-- | arch/x86/kernel/cpu/Makefile | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/addon_cpuid_features.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/amd.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 58 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 23 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel_cacheinfo.c | 17 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_64.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_amd_64.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_intel_64.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 346 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/vmware.c | 112 |
13 files changed, 397 insertions, 201 deletions
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 89e53361fe24..c3813306e0b4 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile | |||
| @@ -2,8 +2,14 @@ | |||
| 2 | # Makefile for x86-compatible CPU details, features and quirks | 2 | # Makefile for x86-compatible CPU details, features and quirks |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | # Don't trace early stages of a secondary CPU boot | ||
| 6 | ifdef CONFIG_FUNCTION_TRACER | ||
| 7 | CFLAGS_REMOVE_common.o = -pg | ||
| 8 | endif | ||
| 9 | |||
| 5 | obj-y := intel_cacheinfo.o addon_cpuid_features.o | 10 | obj-y := intel_cacheinfo.o addon_cpuid_features.o |
| 6 | obj-y += proc.o capflags.o powerflags.o common.o | 11 | obj-y += proc.o capflags.o powerflags.o common.o |
| 12 | obj-y += vmware.o hypervisor.o | ||
| 7 | 13 | ||
| 8 | obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o | 14 | obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o |
| 9 | obj-$(CONFIG_X86_64) += bugs_64.o | 15 | obj-$(CONFIG_X86_64) += bugs_64.o |
diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c index ef8f831af823..2cf23634b6d9 100644 --- a/arch/x86/kernel/cpu/addon_cpuid_features.c +++ b/arch/x86/kernel/cpu/addon_cpuid_features.c | |||
| @@ -120,9 +120,17 @@ void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c) | |||
| 120 | c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width) | 120 | c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width) |
| 121 | & core_select_mask; | 121 | & core_select_mask; |
| 122 | c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width); | 122 | c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width); |
| 123 | /* | ||
| 124 | * Reinit the apicid, now that we have extended initial_apicid. | ||
| 125 | */ | ||
| 126 | c->apicid = phys_pkg_id(c->initial_apicid, 0); | ||
| 123 | #else | 127 | #else |
| 124 | c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask; | 128 | c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask; |
| 125 | c->phys_proc_id = phys_pkg_id(core_plus_mask_width); | 129 | c->phys_proc_id = phys_pkg_id(core_plus_mask_width); |
| 130 | /* | ||
| 131 | * Reinit the apicid, now that we have extended initial_apicid. | ||
| 132 | */ | ||
| 133 | c->apicid = phys_pkg_id(0); | ||
| 126 | #endif | 134 | #endif |
| 127 | c->x86_max_cores = (core_level_siblings / smp_num_siblings); | 135 | c->x86_max_cores = (core_level_siblings / smp_num_siblings); |
| 128 | 136 | ||
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 8f1e31db2ad5..7c878f6aa919 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
| @@ -283,9 +283,14 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) | |||
| 283 | { | 283 | { |
| 284 | early_init_amd_mc(c); | 284 | early_init_amd_mc(c); |
| 285 | 285 | ||
| 286 | /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ | 286 | /* |
| 287 | if (c->x86_power & (1<<8)) | 287 | * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate |
| 288 | * with P/T states and does not stop in deep C-states | ||
| 289 | */ | ||
| 290 | if (c->x86_power & (1 << 8)) { | ||
| 288 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | 291 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); |
| 292 | set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); | ||
| 293 | } | ||
| 289 | 294 | ||
| 290 | #ifdef CONFIG_X86_64 | 295 | #ifdef CONFIG_X86_64 |
| 291 | set_cpu_cap(c, X86_FEATURE_SYSCALL32); | 296 | set_cpu_cap(c, X86_FEATURE_SYSCALL32); |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ad331b4d6238..376b9f9d8d23 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <asm/proto.h> | 37 | #include <asm/proto.h> |
| 38 | #include <asm/sections.h> | 38 | #include <asm/sections.h> |
| 39 | #include <asm/setup.h> | 39 | #include <asm/setup.h> |
| 40 | #include <asm/hypervisor.h> | ||
| 40 | 41 | ||
| 41 | #include "cpu.h" | 42 | #include "cpu.h" |
| 42 | 43 | ||
| @@ -704,6 +705,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) | |||
| 704 | detect_ht(c); | 705 | detect_ht(c); |
| 705 | #endif | 706 | #endif |
| 706 | 707 | ||
| 708 | init_hypervisor(c); | ||
| 707 | /* | 709 | /* |
| 708 | * On SMP, boot_cpu_data holds the common feature set between | 710 | * On SMP, boot_cpu_data holds the common feature set between |
| 709 | * all CPUs; so make sure that we indicate which features are | 711 | * all CPUs; so make sure that we indicate which features are |
| @@ -864,7 +866,7 @@ EXPORT_SYMBOL(_cpu_pda); | |||
| 864 | 866 | ||
| 865 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; | 867 | struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; |
| 866 | 868 | ||
| 867 | char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; | 869 | static char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; |
| 868 | 870 | ||
| 869 | void __cpuinit pda_init(int cpu) | 871 | void __cpuinit pda_init(int cpu) |
| 870 | { | 872 | { |
| @@ -905,8 +907,8 @@ void __cpuinit pda_init(int cpu) | |||
| 905 | } | 907 | } |
| 906 | } | 908 | } |
| 907 | 909 | ||
| 908 | char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + | 910 | static char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + |
| 909 | DEBUG_STKSZ] __page_aligned_bss; | 911 | DEBUG_STKSZ] __page_aligned_bss; |
| 910 | 912 | ||
| 911 | extern asmlinkage void ignore_sysret(void); | 913 | extern asmlinkage void ignore_sysret(void); |
| 912 | 914 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index 8e48c5d4467d..88ea02dcb622 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/cpufreq.h> | 33 | #include <linux/cpufreq.h> |
| 34 | #include <linux/compiler.h> | 34 | #include <linux/compiler.h> |
| 35 | #include <linux/dmi.h> | 35 | #include <linux/dmi.h> |
| 36 | #include <linux/ftrace.h> | ||
| 36 | 37 | ||
| 37 | #include <linux/acpi.h> | 38 | #include <linux/acpi.h> |
| 38 | #include <acpi/processor.h> | 39 | #include <acpi/processor.h> |
| @@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
| 391 | unsigned int next_perf_state = 0; /* Index into perf table */ | 392 | unsigned int next_perf_state = 0; /* Index into perf table */ |
| 392 | unsigned int i; | 393 | unsigned int i; |
| 393 | int result = 0; | 394 | int result = 0; |
| 395 | struct power_trace it; | ||
| 394 | 396 | ||
| 395 | dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); | 397 | dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); |
| 396 | 398 | ||
| @@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
| 427 | } | 429 | } |
| 428 | } | 430 | } |
| 429 | 431 | ||
| 432 | trace_power_mark(&it, POWER_PSTATE, next_perf_state); | ||
| 433 | |||
| 430 | switch (data->cpu_feature) { | 434 | switch (data->cpu_feature) { |
| 431 | case SYSTEM_INTEL_MSR_CAPABLE: | 435 | case SYSTEM_INTEL_MSR_CAPABLE: |
| 432 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; | 436 | cmd.type = SYSTEM_INTEL_MSR_CAPABLE; |
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c new file mode 100644 index 000000000000..fb5b86af0b01 --- /dev/null +++ b/arch/x86/kernel/cpu/hypervisor.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Common hypervisor code | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008, VMware, Inc. | ||
| 5 | * Author : Alok N Kataria <akataria@vmware.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 15 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
| 16 | * details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <asm/processor.h> | ||
| 25 | #include <asm/vmware.h> | ||
| 26 | #include <asm/hypervisor.h> | ||
| 27 | |||
| 28 | static inline void __cpuinit | ||
| 29 | detect_hypervisor_vendor(struct cpuinfo_x86 *c) | ||
| 30 | { | ||
| 31 | if (vmware_platform()) { | ||
| 32 | c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; | ||
| 33 | } else { | ||
| 34 | c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | unsigned long get_hypervisor_tsc_freq(void) | ||
| 39 | { | ||
| 40 | if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) | ||
| 41 | return vmware_get_tsc_khz(); | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline void __cpuinit | ||
| 46 | hypervisor_set_feature_bits(struct cpuinfo_x86 *c) | ||
| 47 | { | ||
| 48 | if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { | ||
| 49 | vmware_set_feature_bits(c); | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) | ||
| 55 | { | ||
| 56 | detect_hypervisor_vendor(c); | ||
| 57 | hypervisor_set_feature_bits(c); | ||
| 58 | } | ||
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index cce0b6118d55..8ea6929e974c 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include <asm/pgtable.h> | 11 | #include <asm/pgtable.h> |
| 12 | #include <asm/msr.h> | 12 | #include <asm/msr.h> |
| 13 | #include <asm/uaccess.h> | 13 | #include <asm/uaccess.h> |
| 14 | #include <asm/ptrace.h> | ||
| 15 | #include <asm/ds.h> | 14 | #include <asm/ds.h> |
| 16 | #include <asm/bugs.h> | 15 | #include <asm/bugs.h> |
| 17 | 16 | ||
| @@ -41,6 +40,16 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) | |||
| 41 | if (c->x86 == 15 && c->x86_cache_alignment == 64) | 40 | if (c->x86 == 15 && c->x86_cache_alignment == 64) |
| 42 | c->x86_cache_alignment = 128; | 41 | c->x86_cache_alignment = 128; |
| 43 | #endif | 42 | #endif |
| 43 | |||
| 44 | /* | ||
| 45 | * c->x86_power is 8000_0007 edx. Bit 8 is TSC runs at constant rate | ||
| 46 | * with P/T states and does not stop in deep C-states | ||
| 47 | */ | ||
| 48 | if (c->x86_power & (1 << 8)) { | ||
| 49 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | ||
| 50 | set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); | ||
| 51 | } | ||
| 52 | |||
| 44 | } | 53 | } |
| 45 | 54 | ||
| 46 | #ifdef CONFIG_X86_32 | 55 | #ifdef CONFIG_X86_32 |
| @@ -242,6 +251,13 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) | |||
| 242 | 251 | ||
| 243 | intel_workarounds(c); | 252 | intel_workarounds(c); |
| 244 | 253 | ||
| 254 | /* | ||
| 255 | * Detect the extended topology information if available. This | ||
| 256 | * will reinitialise the initial_apicid which will be used | ||
| 257 | * in init_intel_cacheinfo() | ||
| 258 | */ | ||
| 259 | detect_extended_topology(c); | ||
| 260 | |||
| 245 | l2 = init_intel_cacheinfo(c); | 261 | l2 = init_intel_cacheinfo(c); |
| 246 | if (c->cpuid_level > 9) { | 262 | if (c->cpuid_level > 9) { |
| 247 | unsigned eax = cpuid_eax(10); | 263 | unsigned eax = cpuid_eax(10); |
| @@ -307,13 +323,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) | |||
| 307 | set_cpu_cap(c, X86_FEATURE_P4); | 323 | set_cpu_cap(c, X86_FEATURE_P4); |
| 308 | if (c->x86 == 6) | 324 | if (c->x86 == 6) |
| 309 | set_cpu_cap(c, X86_FEATURE_P3); | 325 | set_cpu_cap(c, X86_FEATURE_P3); |
| 310 | |||
| 311 | if (cpu_has_bts) | ||
| 312 | ptrace_bts_init_intel(c); | ||
| 313 | |||
| 314 | #endif | 326 | #endif |
| 315 | 327 | ||
| 316 | detect_extended_topology(c); | ||
| 317 | if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { | 328 | if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { |
| 318 | /* | 329 | /* |
| 319 | * let's use the legacy cpuid vector 0x1 and 0x4 for topology | 330 | * let's use the legacy cpuid vector 0x1 and 0x4 for topology |
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 3f46afbb1cf1..68b5d8681cbb 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c | |||
| @@ -644,20 +644,17 @@ static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf) | |||
| 644 | return show_shared_cpu_map_func(leaf, 1, buf); | 644 | return show_shared_cpu_map_func(leaf, 1, buf); |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) { | 647 | static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) |
| 648 | switch(this_leaf->eax.split.type) { | 648 | { |
| 649 | case CACHE_TYPE_DATA: | 649 | switch (this_leaf->eax.split.type) { |
| 650 | case CACHE_TYPE_DATA: | ||
| 650 | return sprintf(buf, "Data\n"); | 651 | return sprintf(buf, "Data\n"); |
| 651 | break; | 652 | case CACHE_TYPE_INST: |
| 652 | case CACHE_TYPE_INST: | ||
| 653 | return sprintf(buf, "Instruction\n"); | 653 | return sprintf(buf, "Instruction\n"); |
| 654 | break; | 654 | case CACHE_TYPE_UNIFIED: |
| 655 | case CACHE_TYPE_UNIFIED: | ||
| 656 | return sprintf(buf, "Unified\n"); | 655 | return sprintf(buf, "Unified\n"); |
| 657 | break; | 656 | default: |
| 658 | default: | ||
| 659 | return sprintf(buf, "Unknown\n"); | 657 | return sprintf(buf, "Unknown\n"); |
| 660 | break; | ||
| 661 | } | 658 | } |
| 662 | } | 659 | } |
| 663 | 660 | ||
diff --git a/arch/x86/kernel/cpu/mcheck/mce_64.c b/arch/x86/kernel/cpu/mcheck/mce_64.c index 4b031a4ac856..1c838032fd37 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_64.c | |||
| @@ -510,12 +510,9 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c) | |||
| 510 | */ | 510 | */ |
| 511 | void __cpuinit mcheck_init(struct cpuinfo_x86 *c) | 511 | void __cpuinit mcheck_init(struct cpuinfo_x86 *c) |
| 512 | { | 512 | { |
| 513 | static cpumask_t mce_cpus = CPU_MASK_NONE; | ||
| 514 | |||
| 515 | mce_cpu_quirks(c); | 513 | mce_cpu_quirks(c); |
| 516 | 514 | ||
| 517 | if (mce_dont_init || | 515 | if (mce_dont_init || |
| 518 | cpu_test_and_set(smp_processor_id(), mce_cpus) || | ||
| 519 | !mce_available(c)) | 516 | !mce_available(c)) |
| 520 | return; | 517 | return; |
| 521 | 518 | ||
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c index 5eb390a4b2e9..748c8f9e7a05 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd_64.c | |||
| @@ -237,7 +237,7 @@ asmlinkage void mce_threshold_interrupt(void) | |||
| 237 | } | 237 | } |
| 238 | } | 238 | } |
| 239 | out: | 239 | out: |
| 240 | add_pda(irq_threshold_count, 1); | 240 | inc_irq_stat(irq_threshold_count); |
| 241 | irq_exit(); | 241 | irq_exit(); |
| 242 | } | 242 | } |
| 243 | 243 | ||
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c index c17eaf5dd6dd..4b48f251fd39 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c | |||
| @@ -26,7 +26,7 @@ asmlinkage void smp_thermal_interrupt(void) | |||
| 26 | if (therm_throt_process(msr_val & 1)) | 26 | if (therm_throt_process(msr_val & 1)) |
| 27 | mce_log_therm_throt_event(smp_processor_id(), msr_val); | 27 | mce_log_therm_throt_event(smp_processor_id(), msr_val); |
| 28 | 28 | ||
| 29 | add_pda(irq_thermal_count, 1); | 29 | inc_irq_stat(irq_thermal_count); |
| 30 | irq_exit(); | 30 | irq_exit(); |
| 31 | } | 31 | } |
| 32 | 32 | ||
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index c78c04821ea1..1159e269e596 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
| @@ -803,6 +803,7 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, | |||
| 803 | } | 803 | } |
| 804 | 804 | ||
| 805 | static struct res_range __initdata range[RANGE_NUM]; | 805 | static struct res_range __initdata range[RANGE_NUM]; |
| 806 | static int __initdata nr_range; | ||
| 806 | 807 | ||
| 807 | #ifdef CONFIG_MTRR_SANITIZER | 808 | #ifdef CONFIG_MTRR_SANITIZER |
| 808 | 809 | ||
| @@ -1206,39 +1207,43 @@ struct mtrr_cleanup_result { | |||
| 1206 | #define PSHIFT (PAGE_SHIFT - 10) | 1207 | #define PSHIFT (PAGE_SHIFT - 10) |
| 1207 | 1208 | ||
| 1208 | static struct mtrr_cleanup_result __initdata result[NUM_RESULT]; | 1209 | static struct mtrr_cleanup_result __initdata result[NUM_RESULT]; |
| 1209 | static struct res_range __initdata range_new[RANGE_NUM]; | ||
| 1210 | static unsigned long __initdata min_loss_pfn[RANGE_NUM]; | 1210 | static unsigned long __initdata min_loss_pfn[RANGE_NUM]; |
| 1211 | 1211 | ||
| 1212 | static int __init mtrr_cleanup(unsigned address_bits) | 1212 | static void __init print_out_mtrr_range_state(void) |
| 1213 | { | 1213 | { |
| 1214 | unsigned long extra_remove_base, extra_remove_size; | ||
| 1215 | unsigned long base, size, def, dummy; | ||
| 1216 | mtrr_type type; | ||
| 1217 | int nr_range, nr_range_new; | ||
| 1218 | u64 chunk_size, gran_size; | ||
| 1219 | unsigned long range_sums, range_sums_new; | ||
| 1220 | int index_good; | ||
| 1221 | int num_reg_good; | ||
| 1222 | int i; | 1214 | int i; |
| 1215 | char start_factor = 'K', size_factor = 'K'; | ||
| 1216 | unsigned long start_base, size_base; | ||
| 1217 | mtrr_type type; | ||
| 1223 | 1218 | ||
| 1224 | /* extra one for all 0 */ | 1219 | for (i = 0; i < num_var_ranges; i++) { |
| 1225 | int num[MTRR_NUM_TYPES + 1]; | ||
| 1226 | 1220 | ||
| 1227 | if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) | 1221 | size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10); |
| 1228 | return 0; | 1222 | if (!size_base) |
| 1229 | rdmsr(MTRRdefType_MSR, def, dummy); | 1223 | continue; |
| 1230 | def &= 0xff; | ||
| 1231 | if (def != MTRR_TYPE_UNCACHABLE) | ||
| 1232 | return 0; | ||
| 1233 | 1224 | ||
| 1234 | /* get it and store it aside */ | 1225 | size_base = to_size_factor(size_base, &size_factor), |
| 1235 | memset(range_state, 0, sizeof(range_state)); | 1226 | start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); |
| 1236 | for (i = 0; i < num_var_ranges; i++) { | 1227 | start_base = to_size_factor(start_base, &start_factor), |
| 1237 | mtrr_if->get(i, &base, &size, &type); | 1228 | type = range_state[i].type; |
| 1238 | range_state[i].base_pfn = base; | 1229 | |
| 1239 | range_state[i].size_pfn = size; | 1230 | printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n", |
| 1240 | range_state[i].type = type; | 1231 | i, start_base, start_factor, |
| 1232 | size_base, size_factor, | ||
| 1233 | (type == MTRR_TYPE_UNCACHABLE) ? "UC" : | ||
| 1234 | ((type == MTRR_TYPE_WRPROT) ? "WP" : | ||
| 1235 | ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")) | ||
| 1236 | ); | ||
| 1241 | } | 1237 | } |
| 1238 | } | ||
| 1239 | |||
| 1240 | static int __init mtrr_need_cleanup(void) | ||
| 1241 | { | ||
| 1242 | int i; | ||
| 1243 | mtrr_type type; | ||
| 1244 | unsigned long size; | ||
| 1245 | /* extra one for all 0 */ | ||
| 1246 | int num[MTRR_NUM_TYPES + 1]; | ||
| 1242 | 1247 | ||
| 1243 | /* check entries number */ | 1248 | /* check entries number */ |
| 1244 | memset(num, 0, sizeof(num)); | 1249 | memset(num, 0, sizeof(num)); |
| @@ -1263,29 +1268,133 @@ static int __init mtrr_cleanup(unsigned address_bits) | |||
| 1263 | num_var_ranges - num[MTRR_NUM_TYPES]) | 1268 | num_var_ranges - num[MTRR_NUM_TYPES]) |
| 1264 | return 0; | 1269 | return 0; |
| 1265 | 1270 | ||
| 1266 | /* print original var MTRRs at first, for debugging: */ | 1271 | return 1; |
| 1267 | printk(KERN_DEBUG "original variable MTRRs\n"); | 1272 | } |
| 1268 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1269 | char start_factor = 'K', size_factor = 'K'; | ||
| 1270 | unsigned long start_base, size_base; | ||
| 1271 | 1273 | ||
| 1272 | size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10); | 1274 | static unsigned long __initdata range_sums; |
| 1273 | if (!size_base) | 1275 | static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size, |
| 1274 | continue; | 1276 | unsigned long extra_remove_base, |
| 1277 | unsigned long extra_remove_size, | ||
| 1278 | int i) | ||
| 1279 | { | ||
| 1280 | int num_reg; | ||
| 1281 | static struct res_range range_new[RANGE_NUM]; | ||
| 1282 | static int nr_range_new; | ||
| 1283 | unsigned long range_sums_new; | ||
| 1284 | |||
| 1285 | /* convert ranges to var ranges state */ | ||
| 1286 | num_reg = x86_setup_var_mtrrs(range, nr_range, | ||
| 1287 | chunk_size, gran_size); | ||
| 1288 | |||
| 1289 | /* we got new setting in range_state, check it */ | ||
| 1290 | memset(range_new, 0, sizeof(range_new)); | ||
| 1291 | nr_range_new = x86_get_mtrr_mem_range(range_new, 0, | ||
| 1292 | extra_remove_base, extra_remove_size); | ||
| 1293 | range_sums_new = sum_ranges(range_new, nr_range_new); | ||
| 1294 | |||
| 1295 | result[i].chunk_sizek = chunk_size >> 10; | ||
| 1296 | result[i].gran_sizek = gran_size >> 10; | ||
| 1297 | result[i].num_reg = num_reg; | ||
| 1298 | if (range_sums < range_sums_new) { | ||
| 1299 | result[i].lose_cover_sizek = | ||
| 1300 | (range_sums_new - range_sums) << PSHIFT; | ||
| 1301 | result[i].bad = 1; | ||
| 1302 | } else | ||
| 1303 | result[i].lose_cover_sizek = | ||
| 1304 | (range_sums - range_sums_new) << PSHIFT; | ||
| 1275 | 1305 | ||
| 1276 | size_base = to_size_factor(size_base, &size_factor), | 1306 | /* double check it */ |
| 1277 | start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); | 1307 | if (!result[i].bad && !result[i].lose_cover_sizek) { |
| 1278 | start_base = to_size_factor(start_base, &start_factor), | 1308 | if (nr_range_new != nr_range || |
| 1279 | type = range_state[i].type; | 1309 | memcmp(range, range_new, sizeof(range))) |
| 1310 | result[i].bad = 1; | ||
| 1311 | } | ||
| 1280 | 1312 | ||
| 1281 | printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n", | 1313 | if (!result[i].bad && (range_sums - range_sums_new < |
| 1282 | i, start_base, start_factor, | 1314 | min_loss_pfn[num_reg])) { |
| 1283 | size_base, size_factor, | 1315 | min_loss_pfn[num_reg] = |
| 1284 | (type == MTRR_TYPE_UNCACHABLE) ? "UC" : | 1316 | range_sums - range_sums_new; |
| 1285 | ((type == MTRR_TYPE_WRPROT) ? "WP" : | ||
| 1286 | ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")) | ||
| 1287 | ); | ||
| 1288 | } | 1317 | } |
| 1318 | } | ||
| 1319 | |||
| 1320 | static void __init mtrr_print_out_one_result(int i) | ||
| 1321 | { | ||
| 1322 | char gran_factor, chunk_factor, lose_factor; | ||
| 1323 | unsigned long gran_base, chunk_base, lose_base; | ||
| 1324 | |||
| 1325 | gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), | ||
| 1326 | chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), | ||
| 1327 | lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), | ||
| 1328 | printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", | ||
| 1329 | result[i].bad ? "*BAD*" : " ", | ||
| 1330 | gran_base, gran_factor, chunk_base, chunk_factor); | ||
| 1331 | printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", | ||
| 1332 | result[i].num_reg, result[i].bad ? "-" : "", | ||
| 1333 | lose_base, lose_factor); | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | static int __init mtrr_search_optimal_index(void) | ||
| 1337 | { | ||
| 1338 | int i; | ||
| 1339 | int num_reg_good; | ||
| 1340 | int index_good; | ||
| 1341 | |||
| 1342 | if (nr_mtrr_spare_reg >= num_var_ranges) | ||
| 1343 | nr_mtrr_spare_reg = num_var_ranges - 1; | ||
| 1344 | num_reg_good = -1; | ||
| 1345 | for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { | ||
| 1346 | if (!min_loss_pfn[i]) | ||
| 1347 | num_reg_good = i; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | index_good = -1; | ||
| 1351 | if (num_reg_good != -1) { | ||
| 1352 | for (i = 0; i < NUM_RESULT; i++) { | ||
| 1353 | if (!result[i].bad && | ||
| 1354 | result[i].num_reg == num_reg_good && | ||
| 1355 | !result[i].lose_cover_sizek) { | ||
| 1356 | index_good = i; | ||
| 1357 | break; | ||
| 1358 | } | ||
| 1359 | } | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | return index_good; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | |||
| 1366 | static int __init mtrr_cleanup(unsigned address_bits) | ||
| 1367 | { | ||
| 1368 | unsigned long extra_remove_base, extra_remove_size; | ||
| 1369 | unsigned long base, size, def, dummy; | ||
| 1370 | mtrr_type type; | ||
| 1371 | u64 chunk_size, gran_size; | ||
| 1372 | int index_good; | ||
| 1373 | int i; | ||
| 1374 | |||
| 1375 | if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1) | ||
| 1376 | return 0; | ||
| 1377 | rdmsr(MTRRdefType_MSR, def, dummy); | ||
| 1378 | def &= 0xff; | ||
| 1379 | if (def != MTRR_TYPE_UNCACHABLE) | ||
| 1380 | return 0; | ||
| 1381 | |||
| 1382 | /* get it and store it aside */ | ||
| 1383 | memset(range_state, 0, sizeof(range_state)); | ||
| 1384 | for (i = 0; i < num_var_ranges; i++) { | ||
| 1385 | mtrr_if->get(i, &base, &size, &type); | ||
| 1386 | range_state[i].base_pfn = base; | ||
| 1387 | range_state[i].size_pfn = size; | ||
| 1388 | range_state[i].type = type; | ||
| 1389 | } | ||
| 1390 | |||
| 1391 | /* check if we need handle it and can handle it */ | ||
| 1392 | if (!mtrr_need_cleanup()) | ||
| 1393 | return 0; | ||
| 1394 | |||
| 1395 | /* print original var MTRRs at first, for debugging: */ | ||
| 1396 | printk(KERN_DEBUG "original variable MTRRs\n"); | ||
| 1397 | print_out_mtrr_range_state(); | ||
| 1289 | 1398 | ||
| 1290 | memset(range, 0, sizeof(range)); | 1399 | memset(range, 0, sizeof(range)); |
| 1291 | extra_remove_size = 0; | 1400 | extra_remove_size = 0; |
| @@ -1309,176 +1418,64 @@ static int __init mtrr_cleanup(unsigned address_bits) | |||
| 1309 | range_sums >> (20 - PAGE_SHIFT)); | 1418 | range_sums >> (20 - PAGE_SHIFT)); |
| 1310 | 1419 | ||
| 1311 | if (mtrr_chunk_size && mtrr_gran_size) { | 1420 | if (mtrr_chunk_size && mtrr_gran_size) { |
| 1312 | int num_reg; | 1421 | i = 0; |
| 1313 | char gran_factor, chunk_factor, lose_factor; | 1422 | mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size, |
| 1314 | unsigned long gran_base, chunk_base, lose_base; | 1423 | extra_remove_base, extra_remove_size, i); |
| 1315 | |||
| 1316 | debug_print++; | ||
| 1317 | /* convert ranges to var ranges state */ | ||
| 1318 | num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size, | ||
| 1319 | mtrr_gran_size); | ||
| 1320 | 1424 | ||
| 1321 | /* we got new setting in range_state, check it */ | 1425 | mtrr_print_out_one_result(i); |
| 1322 | memset(range_new, 0, sizeof(range_new)); | ||
| 1323 | nr_range_new = x86_get_mtrr_mem_range(range_new, 0, | ||
| 1324 | extra_remove_base, | ||
| 1325 | extra_remove_size); | ||
| 1326 | range_sums_new = sum_ranges(range_new, nr_range_new); | ||
| 1327 | 1426 | ||
| 1328 | i = 0; | ||
| 1329 | result[i].chunk_sizek = mtrr_chunk_size >> 10; | ||
| 1330 | result[i].gran_sizek = mtrr_gran_size >> 10; | ||
| 1331 | result[i].num_reg = num_reg; | ||
| 1332 | if (range_sums < range_sums_new) { | ||
| 1333 | result[i].lose_cover_sizek = | ||
| 1334 | (range_sums_new - range_sums) << PSHIFT; | ||
| 1335 | result[i].bad = 1; | ||
| 1336 | } else | ||
| 1337 | result[i].lose_cover_sizek = | ||
| 1338 | (range_sums - range_sums_new) << PSHIFT; | ||
| 1339 | |||
| 1340 | gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), | ||
| 1341 | chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), | ||
| 1342 | lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), | ||
| 1343 | printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", | ||
| 1344 | result[i].bad?"*BAD*":" ", | ||
| 1345 | gran_base, gran_factor, chunk_base, chunk_factor); | ||
| 1346 | printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", | ||
| 1347 | result[i].num_reg, result[i].bad?"-":"", | ||
| 1348 | lose_base, lose_factor); | ||
| 1349 | if (!result[i].bad) { | 1427 | if (!result[i].bad) { |
| 1350 | set_var_mtrr_all(address_bits); | 1428 | set_var_mtrr_all(address_bits); |
| 1351 | return 1; | 1429 | return 1; |
| 1352 | } | 1430 | } |
| 1353 | printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, " | 1431 | printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, " |
| 1354 | "will find optimal one\n"); | 1432 | "will find optimal one\n"); |
| 1355 | debug_print--; | ||
| 1356 | memset(result, 0, sizeof(result[0])); | ||
| 1357 | } | 1433 | } |
| 1358 | 1434 | ||
| 1359 | i = 0; | 1435 | i = 0; |
| 1360 | memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn)); | 1436 | memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn)); |
| 1361 | memset(result, 0, sizeof(result)); | 1437 | memset(result, 0, sizeof(result)); |
| 1362 | for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) { | 1438 | for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) { |
| 1363 | char gran_factor; | ||
| 1364 | unsigned long gran_base; | ||
| 1365 | |||
| 1366 | if (debug_print) | ||
| 1367 | gran_base = to_size_factor(gran_size >> 10, &gran_factor); | ||
| 1368 | 1439 | ||
| 1369 | for (chunk_size = gran_size; chunk_size < (1ULL<<32); | 1440 | for (chunk_size = gran_size; chunk_size < (1ULL<<32); |
| 1370 | chunk_size <<= 1) { | 1441 | chunk_size <<= 1) { |
| 1371 | int num_reg; | ||
| 1372 | 1442 | ||
| 1373 | if (debug_print) { | ||
| 1374 | char chunk_factor; | ||
| 1375 | unsigned long chunk_base; | ||
| 1376 | |||
| 1377 | chunk_base = to_size_factor(chunk_size>>10, &chunk_factor), | ||
| 1378 | printk(KERN_INFO "\n"); | ||
| 1379 | printk(KERN_INFO "gran_size: %ld%c chunk_size: %ld%c \n", | ||
| 1380 | gran_base, gran_factor, chunk_base, chunk_factor); | ||
| 1381 | } | ||
| 1382 | if (i >= NUM_RESULT) | 1443 | if (i >= NUM_RESULT) |
| 1383 | continue; | 1444 | continue; |
| 1384 | 1445 | ||
| 1385 | /* convert ranges to var ranges state */ | 1446 | mtrr_calc_range_state(chunk_size, gran_size, |
| 1386 | num_reg = x86_setup_var_mtrrs(range, nr_range, | 1447 | extra_remove_base, extra_remove_size, i); |
| 1387 | chunk_size, gran_size); | 1448 | if (debug_print) { |
| 1388 | 1449 | mtrr_print_out_one_result(i); | |
| 1389 | /* we got new setting in range_state, check it */ | 1450 | printk(KERN_INFO "\n"); |
| 1390 | memset(range_new, 0, sizeof(range_new)); | ||
| 1391 | nr_range_new = x86_get_mtrr_mem_range(range_new, 0, | ||
| 1392 | extra_remove_base, extra_remove_size); | ||
| 1393 | range_sums_new = sum_ranges(range_new, nr_range_new); | ||
| 1394 | |||
| 1395 | result[i].chunk_sizek = chunk_size >> 10; | ||
| 1396 | result[i].gran_sizek = gran_size >> 10; | ||
| 1397 | result[i].num_reg = num_reg; | ||
| 1398 | if (range_sums < range_sums_new) { | ||
| 1399 | result[i].lose_cover_sizek = | ||
| 1400 | (range_sums_new - range_sums) << PSHIFT; | ||
| 1401 | result[i].bad = 1; | ||
| 1402 | } else | ||
| 1403 | result[i].lose_cover_sizek = | ||
| 1404 | (range_sums - range_sums_new) << PSHIFT; | ||
| 1405 | |||
| 1406 | /* double check it */ | ||
| 1407 | if (!result[i].bad && !result[i].lose_cover_sizek) { | ||
| 1408 | if (nr_range_new != nr_range || | ||
| 1409 | memcmp(range, range_new, sizeof(range))) | ||
| 1410 | result[i].bad = 1; | ||
| 1411 | } | 1451 | } |
| 1412 | 1452 | ||
| 1413 | if (!result[i].bad && (range_sums - range_sums_new < | ||
| 1414 | min_loss_pfn[num_reg])) { | ||
| 1415 | min_loss_pfn[num_reg] = | ||
| 1416 | range_sums - range_sums_new; | ||
| 1417 | } | ||
| 1418 | i++; | 1453 | i++; |
| 1419 | } | 1454 | } |
| 1420 | } | 1455 | } |
| 1421 | 1456 | ||
| 1422 | /* print out all */ | ||
| 1423 | for (i = 0; i < NUM_RESULT; i++) { | ||
| 1424 | char gran_factor, chunk_factor, lose_factor; | ||
| 1425 | unsigned long gran_base, chunk_base, lose_base; | ||
| 1426 | |||
| 1427 | gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), | ||
| 1428 | chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), | ||
| 1429 | lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), | ||
| 1430 | printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t", | ||
| 1431 | result[i].bad?"*BAD*":" ", | ||
| 1432 | gran_base, gran_factor, chunk_base, chunk_factor); | ||
| 1433 | printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n", | ||
| 1434 | result[i].num_reg, result[i].bad?"-":"", | ||
| 1435 | lose_base, lose_factor); | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | /* try to find the optimal index */ | 1457 | /* try to find the optimal index */ |
| 1439 | if (nr_mtrr_spare_reg >= num_var_ranges) | 1458 | index_good = mtrr_search_optimal_index(); |
| 1440 | nr_mtrr_spare_reg = num_var_ranges - 1; | ||
| 1441 | num_reg_good = -1; | ||
| 1442 | for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) { | ||
| 1443 | if (!min_loss_pfn[i]) | ||
| 1444 | num_reg_good = i; | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | index_good = -1; | ||
| 1448 | if (num_reg_good != -1) { | ||
| 1449 | for (i = 0; i < NUM_RESULT; i++) { | ||
| 1450 | if (!result[i].bad && | ||
| 1451 | result[i].num_reg == num_reg_good && | ||
| 1452 | !result[i].lose_cover_sizek) { | ||
| 1453 | index_good = i; | ||
| 1454 | break; | ||
| 1455 | } | ||
| 1456 | } | ||
| 1457 | } | ||
| 1458 | 1459 | ||
| 1459 | if (index_good != -1) { | 1460 | if (index_good != -1) { |
| 1460 | char gran_factor, chunk_factor, lose_factor; | ||
| 1461 | unsigned long gran_base, chunk_base, lose_base; | ||
| 1462 | |||
| 1463 | printk(KERN_INFO "Found optimal setting for mtrr clean up\n"); | 1461 | printk(KERN_INFO "Found optimal setting for mtrr clean up\n"); |
| 1464 | i = index_good; | 1462 | i = index_good; |
| 1465 | gran_base = to_size_factor(result[i].gran_sizek, &gran_factor), | 1463 | mtrr_print_out_one_result(i); |
| 1466 | chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor), | 1464 | |
| 1467 | lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor), | ||
| 1468 | printk(KERN_INFO "gran_size: %ld%c \tchunk_size: %ld%c \t", | ||
| 1469 | gran_base, gran_factor, chunk_base, chunk_factor); | ||
| 1470 | printk(KERN_CONT "num_reg: %d \tlose RAM: %ld%c\n", | ||
| 1471 | result[i].num_reg, lose_base, lose_factor); | ||
| 1472 | /* convert ranges to var ranges state */ | 1465 | /* convert ranges to var ranges state */ |
| 1473 | chunk_size = result[i].chunk_sizek; | 1466 | chunk_size = result[i].chunk_sizek; |
| 1474 | chunk_size <<= 10; | 1467 | chunk_size <<= 10; |
| 1475 | gran_size = result[i].gran_sizek; | 1468 | gran_size = result[i].gran_sizek; |
| 1476 | gran_size <<= 10; | 1469 | gran_size <<= 10; |
| 1477 | debug_print++; | ||
| 1478 | x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size); | 1470 | x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size); |
| 1479 | debug_print--; | ||
| 1480 | set_var_mtrr_all(address_bits); | 1471 | set_var_mtrr_all(address_bits); |
| 1472 | printk(KERN_DEBUG "New variable MTRRs\n"); | ||
| 1473 | print_out_mtrr_range_state(); | ||
| 1481 | return 1; | 1474 | return 1; |
| 1475 | } else { | ||
| 1476 | /* print out all */ | ||
| 1477 | for (i = 0; i < NUM_RESULT; i++) | ||
| 1478 | mtrr_print_out_one_result(i); | ||
| 1482 | } | 1479 | } |
| 1483 | 1480 | ||
| 1484 | printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n"); | 1481 | printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n"); |
| @@ -1562,7 +1559,6 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | |||
| 1562 | { | 1559 | { |
| 1563 | unsigned long i, base, size, highest_pfn = 0, def, dummy; | 1560 | unsigned long i, base, size, highest_pfn = 0, def, dummy; |
| 1564 | mtrr_type type; | 1561 | mtrr_type type; |
| 1565 | int nr_range; | ||
| 1566 | u64 total_trim_size; | 1562 | u64 total_trim_size; |
| 1567 | 1563 | ||
| 1568 | /* extra one for all 0 */ | 1564 | /* extra one for all 0 */ |
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c new file mode 100644 index 000000000000..284c399e3234 --- /dev/null +++ b/arch/x86/kernel/cpu/vmware.c | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | /* | ||
| 2 | * VMware Detection code. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008, VMware, Inc. | ||
| 5 | * Author : Alok N Kataria <akataria@vmware.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 15 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
| 16 | * details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/dmi.h> | ||
| 25 | #include <asm/div64.h> | ||
| 26 | #include <asm/vmware.h> | ||
| 27 | |||
| 28 | #define CPUID_VMWARE_INFO_LEAF 0x40000000 | ||
| 29 | #define VMWARE_HYPERVISOR_MAGIC 0x564D5868 | ||
| 30 | #define VMWARE_HYPERVISOR_PORT 0x5658 | ||
| 31 | |||
| 32 | #define VMWARE_PORT_CMD_GETVERSION 10 | ||
| 33 | #define VMWARE_PORT_CMD_GETHZ 45 | ||
| 34 | |||
| 35 | #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ | ||
| 36 | __asm__("inl (%%dx)" : \ | ||
| 37 | "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ | ||
| 38 | "0"(VMWARE_HYPERVISOR_MAGIC), \ | ||
| 39 | "1"(VMWARE_PORT_CMD_##cmd), \ | ||
| 40 | "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ | ||
| 41 | "memory"); | ||
| 42 | |||
| 43 | static inline int __vmware_platform(void) | ||
| 44 | { | ||
| 45 | uint32_t eax, ebx, ecx, edx; | ||
| 46 | VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); | ||
| 47 | return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; | ||
| 48 | } | ||
| 49 | |||
| 50 | static unsigned long __vmware_get_tsc_khz(void) | ||
| 51 | { | ||
| 52 | uint64_t tsc_hz; | ||
| 53 | uint32_t eax, ebx, ecx, edx; | ||
| 54 | |||
| 55 | VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); | ||
| 56 | |||
| 57 | if (ebx == UINT_MAX) | ||
| 58 | return 0; | ||
| 59 | tsc_hz = eax | (((uint64_t)ebx) << 32); | ||
| 60 | do_div(tsc_hz, 1000); | ||
| 61 | BUG_ON(tsc_hz >> 32); | ||
| 62 | return tsc_hz; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * While checking the dmi string infomation, just checking the product | ||
| 67 | * serial key should be enough, as this will always have a VMware | ||
| 68 | * specific string when running under VMware hypervisor. | ||
| 69 | */ | ||
| 70 | int vmware_platform(void) | ||
| 71 | { | ||
| 72 | if (cpu_has_hypervisor) { | ||
| 73 | unsigned int eax, ebx, ecx, edx; | ||
| 74 | char hyper_vendor_id[13]; | ||
| 75 | |||
| 76 | cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); | ||
| 77 | memcpy(hyper_vendor_id + 0, &ebx, 4); | ||
| 78 | memcpy(hyper_vendor_id + 4, &ecx, 4); | ||
| 79 | memcpy(hyper_vendor_id + 8, &edx, 4); | ||
| 80 | hyper_vendor_id[12] = '\0'; | ||
| 81 | if (!strcmp(hyper_vendor_id, "VMwareVMware")) | ||
| 82 | return 1; | ||
| 83 | } else if (dmi_available && dmi_name_in_serial("VMware") && | ||
| 84 | __vmware_platform()) | ||
| 85 | return 1; | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | unsigned long vmware_get_tsc_khz(void) | ||
| 91 | { | ||
| 92 | BUG_ON(!vmware_platform()); | ||
| 93 | return __vmware_get_tsc_khz(); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | ||
| 97 | * VMware hypervisor takes care of exporting a reliable TSC to the guest. | ||
| 98 | * Still, due to timing difference when running on virtual cpus, the TSC can | ||
| 99 | * be marked as unstable in some cases. For example, the TSC sync check at | ||
| 100 | * bootup can fail due to a marginal offset between vcpus' TSCs (though the | ||
| 101 | * TSCs do not drift from each other). Also, the ACPI PM timer clocksource | ||
| 102 | * is not suitable as a watchdog when running on a hypervisor because the | ||
| 103 | * kernel may miss a wrap of the counter if the vcpu is descheduled for a | ||
| 104 | * long time. To skip these checks at runtime we set these capability bits, | ||
| 105 | * so that the kernel could just trust the hypervisor with providing a | ||
| 106 | * reliable virtual TSC that is suitable for timekeeping. | ||
| 107 | */ | ||
| 108 | void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) | ||
| 109 | { | ||
| 110 | set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); | ||
| 111 | set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); | ||
| 112 | } | ||
