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.c164
1 files changed, 90 insertions, 74 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 5a2a4c146333..79597d3c3431 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -611,17 +611,9 @@ static struct sysdev_driver mtrr_sysdev_driver = {
611}; 611};
612 612
613#ifdef CONFIG_MTRR_SANITIZER 613#ifdef CONFIG_MTRR_SANITIZER
614 614static int enable_mtrr_cleanup __initdata = CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
615#ifdef CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT
616static int enable_mtrr_cleanup __initdata = 1;
617#else
618static int enable_mtrr_cleanup __initdata;
619#endif
620
621#else 615#else
622
623static int enable_mtrr_cleanup __initdata = -1; 616static int enable_mtrr_cleanup __initdata = -1;
624
625#endif 617#endif
626 618
627static int __init disable_mtrr_cleanup_setup(char *str) 619static int __init disable_mtrr_cleanup_setup(char *str)
@@ -640,6 +632,7 @@ static int __init enable_mtrr_cleanup_setup(char *str)
640} 632}
641early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup); 633early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup);
642 634
635/* should be related to MTRR_VAR_RANGES nums */
643#define RANGE_NUM 256 636#define RANGE_NUM 256
644 637
645struct res_range { 638struct res_range {
@@ -647,13 +640,27 @@ struct res_range {
647 unsigned long end; 640 unsigned long end;
648}; 641};
649 642
650static int __init add_range(struct res_range *range, int nr_range, unsigned long start, 643static int __init
651 unsigned long end, int merge) 644add_range(struct res_range *range, int nr_range, unsigned long start,
645 unsigned long end)
652{ 646{
653 int i; 647 /* out of slots */
648 if (nr_range >= RANGE_NUM)
649 return nr_range;
654 650
655 if (!merge) 651 range[nr_range].start = start;
656 goto addit; 652 range[nr_range].end = end;
653
654 nr_range++;
655
656 return nr_range;
657}
658
659static int __init
660add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
661 unsigned long end)
662{
663 int i;
657 664
658 /* try to merge it with old one */ 665 /* try to merge it with old one */
659 for (i = 0; i < nr_range; i++) { 666 for (i = 0; i < nr_range; i++) {
@@ -676,24 +683,14 @@ static int __init add_range(struct res_range *range, int nr_range, unsigned long
676 return nr_range; 683 return nr_range;
677 } 684 }
678 685
679addit:
680 /* need to add that */ 686 /* need to add that */
681 if (nr_range >= RANGE_NUM) 687 return add_range(range, nr_range, start, end);
682 return nr_range;
683
684 range[nr_range].start = start;
685 range[nr_range].end = end;
686
687 nr_range++;
688
689 return nr_range;
690
691} 688}
692static void __init subtract_range(struct res_range *range, unsigned long start, 689
693 unsigned long end) 690static void __init
691subtract_range(struct res_range *range, unsigned long start, unsigned long end)
694{ 692{
695 int i; 693 int i, j;
696 int j;
697 694
698 for (j = 0; j < RANGE_NUM; j++) { 695 for (j = 0; j < RANGE_NUM; j++) {
699 if (!range[j].end) 696 if (!range[j].end)
@@ -747,46 +744,47 @@ static int __init cmp_range(const void *x1, const void *x2)
747} 744}
748 745
749struct var_mtrr_state { 746struct var_mtrr_state {
750 unsigned long range_startk, range_sizek; 747 unsigned long range_startk;
751 unsigned long chunk_sizek; 748 unsigned long range_sizek;
752 unsigned long gran_sizek; 749 unsigned long chunk_sizek;
753 unsigned int reg; 750 unsigned long gran_sizek;
754 unsigned address_bits; 751 unsigned int reg;
752 unsigned int address_bits;
755}; 753};
756 754
757static void __init set_var_mtrr( 755static void __init
758 unsigned int reg, unsigned long basek, unsigned long sizek, 756set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
759 unsigned char type, unsigned address_bits) 757 unsigned char type, unsigned address_bits)
760{ 758{
761 u32 base_lo, base_hi, mask_lo, mask_hi; 759 u32 base_lo, base_hi, mask_lo, mask_hi;
762 unsigned address_mask_high; 760 u64 base, mask;
763 761
764 if (!sizek) { 762 if (!sizek) {
765 fill_mtrr_var_range(reg, 0, 0, 0, 0); 763 fill_mtrr_var_range(reg, 0, 0, 0, 0);
766 return; 764 return;
767 } 765 }
768 766
769 address_mask_high = ((1u << (address_bits - 32u)) - 1u); 767 mask = (1ULL << address_bits) - 1;
768 mask &= ~((((u64)sizek) << 10) - 1);
770 769
771 base_hi = basek >> 22; 770 base = ((u64)basek) << 10;
772 base_lo = basek << 10;
773 771
774 if (sizek < 4*1024*1024) { 772 base |= type;
775 mask_hi = address_mask_high; 773 mask |= 0x800;
776 mask_lo = ~((sizek << 10) - 1); 774
777 } else { 775 base_lo = base & ((1ULL<<32) - 1);
778 mask_hi = address_mask_high & (~((sizek >> 22) - 1)); 776 base_hi = base >> 32;
779 mask_lo = 0; 777
780 } 778 mask_lo = mask & ((1ULL<<32) - 1);
779 mask_hi = mask >> 32;
781 780
782 base_lo |= type;
783 mask_lo |= 0x800;
784 fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi); 781 fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
785} 782}
786 783
787static unsigned int __init range_to_mtrr(unsigned int reg, 784static unsigned int __init
788 unsigned long range_startk, unsigned long range_sizek, 785range_to_mtrr(unsigned int reg, unsigned long range_startk,
789 unsigned char type, unsigned address_bits) 786 unsigned long range_sizek, unsigned char type,
787 unsigned address_bits)
790{ 788{
791 if (!range_sizek || (reg >= num_var_ranges)) 789 if (!range_sizek || (reg >= num_var_ranges))
792 return reg; 790 return reg;
@@ -794,6 +792,7 @@ static unsigned int __init range_to_mtrr(unsigned int reg,
794 while (range_sizek) { 792 while (range_sizek) {
795 unsigned long max_align, align; 793 unsigned long max_align, align;
796 unsigned long sizek; 794 unsigned long sizek;
795
797 /* Compute the maximum size I can make a range */ 796 /* Compute the maximum size I can make a range */
798 if (range_startk) 797 if (range_startk)
799 max_align = ffs(range_startk) - 1; 798 max_align = ffs(range_startk) - 1;
@@ -818,7 +817,8 @@ static unsigned int __init range_to_mtrr(unsigned int reg,
818 return reg; 817 return reg;
819} 818}
820 819
821static void __init range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek) 820static void __init
821range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek)
822{ 822{
823 unsigned long hole_basek, hole_sizek; 823 unsigned long hole_basek, hole_sizek;
824 unsigned long range0_basek, range0_sizek; 824 unsigned long range0_basek, range0_sizek;
@@ -848,23 +848,31 @@ static void __init range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigne
848 /* try to append some small hole */ 848 /* try to append some small hole */
849 range0_basek = state->range_startk; 849 range0_basek = state->range_startk;
850 range0_sizek = ALIGN(state->range_sizek, chunk_sizek); 850 range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
851 if ((range0_sizek == state->range_sizek) || 851 if (range0_sizek == state->range_sizek) {
852 ((range0_basek + range0_sizek - chunk_sizek > basek) && basek)) {
853 printk(KERN_INFO "rangeX: %016lx - %016lx\n", range0_basek<<10, (range0_basek + state->range_sizek)<<10); 852 printk(KERN_INFO "rangeX: %016lx - %016lx\n", range0_basek<<10, (range0_basek + state->range_sizek)<<10);
854 state->reg = range_to_mtrr(state->reg, range0_basek, 853 state->reg = range_to_mtrr(state->reg, range0_basek,
855 state->range_sizek, MTRR_TYPE_WRBACK, state->address_bits); 854 state->range_sizek, MTRR_TYPE_WRBACK, state->address_bits);
856 return; 855 return;
856 } else if (basek) {
857 while (range0_basek + range0_sizek - chunk_sizek > basek) {
858 range0_sizek -= chunk_sizek;
859 if (!range0_sizek)
860 break;
861 }
857 } 862 }
858 863
859 864
860 range0_sizek -= chunk_sizek; 865 if (range0_sizek > chunk_sizek)
866 range0_sizek -= chunk_sizek;
861 printk(KERN_INFO "range0: %016lx - %016lx\n", range0_basek<<10, (range0_basek + range0_sizek)<<10); 867 printk(KERN_INFO "range0: %016lx - %016lx\n", range0_basek<<10, (range0_basek + range0_sizek)<<10);
862 state->reg = range_to_mtrr(state->reg, range0_basek, 868 state->reg = range_to_mtrr(state->reg, range0_basek,
863 range0_sizek, MTRR_TYPE_WRBACK, state->address_bits); 869 range0_sizek, MTRR_TYPE_WRBACK, state->address_bits);
864 870
865 range_basek = range0_basek + range0_sizek; 871 range_basek = range0_basek + range0_sizek;
866 range_sizek = chunk_sizek; 872 range_sizek = chunk_sizek;
867 if (range_sizek - (state->range_sizek - range0_sizek) < (chunk_sizek >> 1)) { 873
874 if ((range_sizek - (state->range_sizek - range0_sizek) < (chunk_sizek >> 1)) &&
875 (range_basek + range_sizek <= basek)) {
868 hole_sizek = range_sizek - (state->range_sizek - range0_sizek); 876 hole_sizek = range_sizek - (state->range_sizek - range0_sizek);
869 hole_basek = range_basek + range_sizek - hole_sizek; 877 hole_basek = range_basek + range_sizek - hole_sizek;
870 } else 878 } else
@@ -880,7 +888,9 @@ static void __init range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigne
880 } 888 }
881} 889}
882 890
883static void __init set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn, unsigned long size_pfn) 891static void __init
892set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
893 unsigned long size_pfn)
884{ 894{
885 unsigned long basek, sizek; 895 unsigned long basek, sizek;
886 896
@@ -921,7 +931,7 @@ static int __init parse_mtrr_chunk_size_opt(char *p)
921early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt); 931early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
922 932
923/* granity of mtrr of block */ 933/* granity of mtrr of block */
924static u64 mtrr_gran_size __initdata = (64ULL<<20); 934static u64 mtrr_gran_size __initdata = (1ULL<<20);
925 935
926static int __init parse_mtrr_gran_size_opt(char *p) 936static int __init parse_mtrr_gran_size_opt(char *p)
927{ 937{
@@ -932,17 +942,19 @@ static int __init parse_mtrr_gran_size_opt(char *p)
932} 942}
933early_param("mtrr_gran_size", parse_mtrr_gran_size_opt); 943early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
934 944
935static void __init x86_setup_var_mtrrs(struct res_range *range, int nr_range, unsigned address_bits) 945static void __init
946x86_setup_var_mtrrs(struct res_range *range, int nr_range,
947 unsigned address_bits)
936{ 948{
937 struct var_mtrr_state var_state; 949 struct var_mtrr_state var_state;
938 int i; 950 int i;
939 951
940 var_state.range_startk = 0; 952 var_state.range_startk = 0;
941 var_state.range_sizek = 0; 953 var_state.range_sizek = 0;
942 var_state.reg = 0; 954 var_state.reg = 0;
943 var_state.address_bits = address_bits; 955 var_state.address_bits = address_bits;
944 var_state.chunk_sizek = mtrr_chunk_size >> 10; 956 var_state.chunk_sizek = mtrr_chunk_size >> 10;
945 var_state.gran_sizek = mtrr_gran_size >> 10; 957 var_state.gran_sizek = mtrr_gran_size >> 10;
946 958
947 /* Write the range etc */ 959 /* Write the range etc */
948 for (i = 0; i < nr_range; i++) 960 for (i = 0; i < nr_range; i++)
@@ -952,11 +964,16 @@ static void __init x86_setup_var_mtrrs(struct res_range *range, int nr_range, un
952 range_to_mtrr_with_hole(&var_state, 0); 964 range_to_mtrr_with_hole(&var_state, 0);
953 printk(KERN_INFO "DONE variable MTRRs\n"); 965 printk(KERN_INFO "DONE variable MTRRs\n");
954 /* Clear out the extra MTRR's */ 966 /* Clear out the extra MTRR's */
955 while (var_state.reg < num_var_ranges) 967 while (var_state.reg < num_var_ranges) {
956 set_var_mtrr(var_state.reg++, 0, 0, 0, var_state.address_bits); 968 set_var_mtrr(var_state.reg, 0, 0, 0, var_state.address_bits);
969 var_state.reg++;
970 }
957} 971}
958 972
959static int __init x86_get_mtrr_mem_range(struct res_range *range, int nr_range, unsigned long extra_remove_base, unsigned long extra_remove_size) 973static int __init
974x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
975 unsigned long extra_remove_base,
976 unsigned long extra_remove_size)
960{ 977{
961 unsigned long i, base, size; 978 unsigned long i, base, size;
962 mtrr_type type; 979 mtrr_type type;
@@ -965,7 +982,7 @@ static int __init x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
965 mtrr_if->get(i, &base, &size, &type); 982 mtrr_if->get(i, &base, &size, &type);
966 if (type != MTRR_TYPE_WRBACK) 983 if (type != MTRR_TYPE_WRBACK)
967 continue; 984 continue;
968 nr_range = add_range(range, nr_range, base, base + size - 1, 1); 985 nr_range = add_range_with_merge(range, nr_range, base, base + size - 1);
969 } 986 }
970 printk(KERN_INFO "After WB checking\n"); 987 printk(KERN_INFO "After WB checking\n");
971 for (i = 0; i < nr_range; i++) 988 for (i = 0; i < nr_range; i++)
@@ -1005,11 +1022,11 @@ static int __init x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
1005 1022
1006static int __init mtrr_cleanup(unsigned address_bits) 1023static int __init mtrr_cleanup(unsigned address_bits)
1007{ 1024{
1025 unsigned long extra_remove_base, extra_remove_size;
1008 unsigned long i, base, size, def, dummy; 1026 unsigned long i, base, size, def, dummy;
1009 mtrr_type type;
1010 struct res_range range[RANGE_NUM]; 1027 struct res_range range[RANGE_NUM];
1028 mtrr_type type;
1011 int nr_range; 1029 int nr_range;
1012 unsigned long extra_remove_base, extra_remove_size;
1013 1030
1014 /* extra one for all 0 */ 1031 /* extra one for all 0 */
1015 int num[MTRR_NUM_TYPES + 1]; 1032 int num[MTRR_NUM_TYPES + 1];
@@ -1053,7 +1070,6 @@ static int __init mtrr_cleanup(unsigned address_bits)
1053 x86_setup_var_mtrrs(range, nr_range, address_bits); 1070 x86_setup_var_mtrrs(range, nr_range, address_bits);
1054 1071
1055 return 1; 1072 return 1;
1056
1057} 1073}
1058 1074
1059static int disable_mtrr_trim; 1075static int disable_mtrr_trim;