diff options
| author | Yinghai Lu <yhlu.kernel.send@gmail.com> | 2008-04-29 23:25:58 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-25 04:55:10 -0400 |
| commit | f5098d62c1d1cede8ff23d01bbf50a421f110562 (patch) | |
| tree | 2e89344ba23d5af07fe5fe1c5bfbd19a8f7f1714 | |
| parent | 8a374026c265476b1acfc3c186a66d59ebdb2cda (diff) | |
x86: mtrr cleanup for converting continuous to discrete layout v8 - fix
v9: address format change requests by Ingo
more case handling in range_to_var_with_hole
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | arch/x86/Kconfig | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 164 |
2 files changed, 94 insertions, 79 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 97a1764a3d20..f417fe33d852 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -1110,13 +1110,12 @@ config MTRR_SANITIZER | |||
| 1110 | If unsure, say Y. | 1110 | If unsure, say Y. |
| 1111 | 1111 | ||
| 1112 | config MTRR_SANITIZER_ENABLE_DEFAULT | 1112 | config MTRR_SANITIZER_ENABLE_DEFAULT |
| 1113 | def_bool y | 1113 | int "MTRR cleanup enable value (0-1)" |
| 1114 | prompt "Enable MTRR cleanup by default" | 1114 | range 0 1 |
| 1115 | default "0" | ||
| 1115 | depends on MTRR_SANITIZER | 1116 | depends on MTRR_SANITIZER |
| 1116 | help | 1117 | help |
| 1117 | Enable mtrr cleanup by default | 1118 | Enable mtrr cleanup default value |
| 1118 | |||
| 1119 | If unsure, say Y. | ||
| 1120 | 1119 | ||
| 1121 | config X86_PAT | 1120 | config X86_PAT |
| 1122 | bool | 1121 | bool |
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; |
