aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/mtrr/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/mtrr/main.c')
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c140
1 files changed, 116 insertions, 24 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 60af5ed2b5c0..ccd36ed2187b 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -38,8 +38,8 @@
38#include <linux/cpu.h> 38#include <linux/cpu.h>
39#include <linux/mutex.h> 39#include <linux/mutex.h>
40 40
41#include <asm/e820.h>
41#include <asm/mtrr.h> 42#include <asm/mtrr.h>
42
43#include <asm/uaccess.h> 43#include <asm/uaccess.h>
44#include <asm/processor.h> 44#include <asm/processor.h>
45#include <asm/msr.h> 45#include <asm/msr.h>
@@ -47,7 +47,7 @@
47 47
48u32 num_var_ranges = 0; 48u32 num_var_ranges = 0;
49 49
50unsigned int *usage_table; 50unsigned int mtrr_usage_table[MAX_VAR_RANGES];
51static DEFINE_MUTEX(mtrr_mutex); 51static DEFINE_MUTEX(mtrr_mutex);
52 52
53u64 size_or_mask, size_and_mask; 53u64 size_or_mask, size_and_mask;
@@ -121,13 +121,8 @@ static void __init init_table(void)
121 int i, max; 121 int i, max;
122 122
123 max = num_var_ranges; 123 max = num_var_ranges;
124 if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
125 == NULL) {
126 printk(KERN_ERR "mtrr: could not allocate\n");
127 return;
128 }
129 for (i = 0; i < max; i++) 124 for (i = 0; i < max; i++)
130 usage_table[i] = 1; 125 mtrr_usage_table[i] = 1;
131} 126}
132 127
133struct set_mtrr_data { 128struct set_mtrr_data {
@@ -383,7 +378,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
383 goto out; 378 goto out;
384 } 379 }
385 if (increment) 380 if (increment)
386 ++usage_table[i]; 381 ++mtrr_usage_table[i];
387 error = i; 382 error = i;
388 goto out; 383 goto out;
389 } 384 }
@@ -391,15 +386,15 @@ int mtrr_add_page(unsigned long base, unsigned long size,
391 i = mtrr_if->get_free_region(base, size, replace); 386 i = mtrr_if->get_free_region(base, size, replace);
392 if (i >= 0) { 387 if (i >= 0) {
393 set_mtrr(i, base, size, type); 388 set_mtrr(i, base, size, type);
394 if (likely(replace < 0)) 389 if (likely(replace < 0)) {
395 usage_table[i] = 1; 390 mtrr_usage_table[i] = 1;
396 else { 391 } else {
397 usage_table[i] = usage_table[replace]; 392 mtrr_usage_table[i] = mtrr_usage_table[replace];
398 if (increment) 393 if (increment)
399 usage_table[i]++; 394 mtrr_usage_table[i]++;
400 if (unlikely(replace != i)) { 395 if (unlikely(replace != i)) {
401 set_mtrr(replace, 0, 0, 0); 396 set_mtrr(replace, 0, 0, 0);
402 usage_table[replace] = 0; 397 mtrr_usage_table[replace] = 0;
403 } 398 }
404 } 399 }
405 } else 400 } else
@@ -529,11 +524,11 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
529 printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); 524 printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
530 goto out; 525 goto out;
531 } 526 }
532 if (usage_table[reg] < 1) { 527 if (mtrr_usage_table[reg] < 1) {
533 printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); 528 printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
534 goto out; 529 goto out;
535 } 530 }
536 if (--usage_table[reg] < 1) 531 if (--mtrr_usage_table[reg] < 1)
537 set_mtrr(reg, 0, 0, 0); 532 set_mtrr(reg, 0, 0, 0);
538 error = reg; 533 error = reg;
539 out: 534 out:
@@ -593,16 +588,11 @@ struct mtrr_value {
593 unsigned long lsize; 588 unsigned long lsize;
594}; 589};
595 590
596static struct mtrr_value * mtrr_state; 591static struct mtrr_value mtrr_state[MAX_VAR_RANGES];
597 592
598static int mtrr_save(struct sys_device * sysdev, pm_message_t state) 593static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
599{ 594{
600 int i; 595 int i;
601 int size = num_var_ranges * sizeof(struct mtrr_value);
602
603 mtrr_state = kzalloc(size,GFP_ATOMIC);
604 if (!mtrr_state)
605 return -ENOMEM;
606 596
607 for (i = 0; i < num_var_ranges; i++) { 597 for (i = 0; i < num_var_ranges; i++) {
608 mtrr_if->get(i, 598 mtrr_if->get(i,
@@ -624,7 +614,6 @@ static int mtrr_restore(struct sys_device * sysdev)
624 mtrr_state[i].lsize, 614 mtrr_state[i].lsize,
625 mtrr_state[i].ltype); 615 mtrr_state[i].ltype);
626 } 616 }
627 kfree(mtrr_state);
628 return 0; 617 return 0;
629} 618}
630 619
@@ -635,6 +624,109 @@ static struct sysdev_driver mtrr_sysdev_driver = {
635 .resume = mtrr_restore, 624 .resume = mtrr_restore,
636}; 625};
637 626
627#ifdef CONFIG_X86_64
628static int disable_mtrr_trim;
629
630static int __init disable_mtrr_trim_setup(char *str)
631{
632 disable_mtrr_trim = 1;
633 return 0;
634}
635early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
636
637/*
638 * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
639 * for memory >4GB. Check for that here.
640 * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
641 * apply to are wrong, but so far we don't know of any such case in the wild.
642 */
643#define Tom2Enabled (1U << 21)
644#define Tom2ForceMemTypeWB (1U << 22)
645
646static __init int amd_special_default_mtrr(unsigned long end_pfn)
647{
648 u32 l, h;
649
650 /* Doesn't apply to memory < 4GB */
651 if (end_pfn <= (0xffffffff >> PAGE_SHIFT))
652 return 0;
653 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
654 return 0;
655 if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
656 return 0;
657 /* In case some hypervisor doesn't pass SYSCFG through */
658 if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
659 return 0;
660 /*
661 * Memory between 4GB and top of mem is forced WB by this magic bit.
662 * Reserved before K8RevF, but should be zero there.
663 */
664 if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
665 (Tom2Enabled | Tom2ForceMemTypeWB))
666 return 1;
667 return 0;
668}
669
670/**
671 * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
672 *
673 * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
674 * memory configurations. This routine checks that the highest MTRR matches
675 * the end of memory, to make sure the MTRRs having a write back type cover
676 * all of the memory the kernel is intending to use. If not, it'll trim any
677 * memory off the end by adjusting end_pfn, removing it from the kernel's
678 * allocation pools, warning the user with an obnoxious message.
679 */
680int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
681{
682 unsigned long i, base, size, highest_addr = 0, def, dummy;
683 mtrr_type type;
684 u64 trim_start, trim_size;
685
686 /*
687 * Make sure we only trim uncachable memory on machines that
688 * support the Intel MTRR architecture:
689 */
690 rdmsr(MTRRdefType_MSR, def, dummy);
691 def &= 0xff;
692 if (!is_cpu(INTEL) || disable_mtrr_trim || def != MTRR_TYPE_UNCACHABLE)
693 return 0;
694
695 /* Find highest cached pfn */
696 for (i = 0; i < num_var_ranges; i++) {
697 mtrr_if->get(i, &base, &size, &type);
698 if (type != MTRR_TYPE_WRBACK)
699 continue;
700 base <<= PAGE_SHIFT;
701 size <<= PAGE_SHIFT;
702 if (highest_addr < base + size)
703 highest_addr = base + size;
704 }
705
706 if (amd_special_default_mtrr(end_pfn))
707 return 0;
708
709 if ((highest_addr >> PAGE_SHIFT) < end_pfn) {
710 printk(KERN_WARNING "***************\n");
711 printk(KERN_WARNING "**** WARNING: likely BIOS bug\n");
712 printk(KERN_WARNING "**** MTRRs don't cover all of "
713 "memory, trimmed %ld pages\n", end_pfn -
714 (highest_addr >> PAGE_SHIFT));
715 printk(KERN_WARNING "***************\n");
716
717 printk(KERN_INFO "update e820 for mtrr\n");
718 trim_start = highest_addr;
719 trim_size = end_pfn;
720 trim_size <<= PAGE_SHIFT;
721 trim_size -= trim_start;
722 add_memory_region(trim_start, trim_size, E820_RESERVED);
723 update_e820();
724 return 1;
725 }
726
727 return 0;
728}
729#endif
638 730
639/** 731/**
640 * mtrr_bp_init - initialize mtrrs on the boot CPU 732 * mtrr_bp_init - initialize mtrrs on the boot CPU