diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mtrr/main.c')
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 164 |
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 | 614 | static int enable_mtrr_cleanup __initdata = CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT; | |
615 | #ifdef CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT | ||
616 | static int enable_mtrr_cleanup __initdata = 1; | ||
617 | #else | ||
618 | static int enable_mtrr_cleanup __initdata; | ||
619 | #endif | ||
620 | |||
621 | #else | 615 | #else |
622 | |||
623 | static int enable_mtrr_cleanup __initdata = -1; | 616 | static int enable_mtrr_cleanup __initdata = -1; |
624 | |||
625 | #endif | 617 | #endif |
626 | 618 | ||
627 | static int __init disable_mtrr_cleanup_setup(char *str) | 619 | static int __init disable_mtrr_cleanup_setup(char *str) |
@@ -640,6 +632,7 @@ static int __init enable_mtrr_cleanup_setup(char *str) | |||
640 | } | 632 | } |
641 | early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup); | 633 | early_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 | ||
645 | struct res_range { | 638 | struct res_range { |
@@ -647,13 +640,27 @@ struct res_range { | |||
647 | unsigned long end; | 640 | unsigned long end; |
648 | }; | 641 | }; |
649 | 642 | ||
650 | static int __init add_range(struct res_range *range, int nr_range, unsigned long start, | 643 | static int __init |
651 | unsigned long end, int merge) | 644 | add_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 | |||
659 | static int __init | ||
660 | add_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 | ||
679 | addit: | ||
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 | } |
692 | static void __init subtract_range(struct res_range *range, unsigned long start, | 689 | |
693 | unsigned long end) | 690 | static void __init |
691 | subtract_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 | ||
749 | struct var_mtrr_state { | 746 | struct 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 | ||
757 | static void __init set_var_mtrr( | 755 | static void __init |
758 | unsigned int reg, unsigned long basek, unsigned long sizek, | 756 | set_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 | ||
787 | static unsigned int __init range_to_mtrr(unsigned int reg, | 784 | static unsigned int __init |
788 | unsigned long range_startk, unsigned long range_sizek, | 785 | range_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 | ||
821 | static void __init range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek) | 820 | static void __init |
821 | range_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 | ||
883 | static void __init set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn, unsigned long size_pfn) | 891 | static void __init |
892 | set_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) | |||
921 | early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt); | 931 | early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt); |
922 | 932 | ||
923 | /* granity of mtrr of block */ | 933 | /* granity of mtrr of block */ |
924 | static u64 mtrr_gran_size __initdata = (64ULL<<20); | 934 | static u64 mtrr_gran_size __initdata = (1ULL<<20); |
925 | 935 | ||
926 | static int __init parse_mtrr_gran_size_opt(char *p) | 936 | static 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 | } |
933 | early_param("mtrr_gran_size", parse_mtrr_gran_size_opt); | 943 | early_param("mtrr_gran_size", parse_mtrr_gran_size_opt); |
934 | 944 | ||
935 | static void __init x86_setup_var_mtrrs(struct res_range *range, int nr_range, unsigned address_bits) | 945 | static void __init |
946 | x86_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 | ||
959 | static int __init x86_get_mtrr_mem_range(struct res_range *range, int nr_range, unsigned long extra_remove_base, unsigned long extra_remove_size) | 973 | static int __init |
974 | x86_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 | ||
1006 | static int __init mtrr_cleanup(unsigned address_bits) | 1023 | static 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 | ||
1059 | static int disable_mtrr_trim; | 1075 | static int disable_mtrr_trim; |