diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-12-29 00:00:23 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-31 17:06:04 -0500 |
commit | 6fc5bae797a6632bbccdd49a1b6a96121368a4b9 (patch) | |
tree | b9bb72c869cd993d7b40794402effce3cfa902e0 | |
parent | bfff6e92a33dce6121a3d83ef3809e9063b2734e (diff) |
[SPARC64]: Fix "mem=xxx" handling.
We were not being careful enough. When we trim the physical
memory areas, we have to make sure we don't remove the kernel
image or initial ramdisk image ranges.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/mm/init.c | 147 |
1 files changed, 124 insertions, 23 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index a8e8802eed4d..054822a3e05e 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -872,6 +872,115 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, | |||
872 | prom_halt(); | 872 | prom_halt(); |
873 | } | 873 | } |
874 | 874 | ||
875 | static void __init trim_pavail(unsigned long *cur_size_p, | ||
876 | unsigned long *end_of_phys_p) | ||
877 | { | ||
878 | unsigned long to_trim = *cur_size_p - cmdline_memory_size; | ||
879 | unsigned long avoid_start, avoid_end; | ||
880 | int i; | ||
881 | |||
882 | to_trim = PAGE_ALIGN(to_trim); | ||
883 | |||
884 | avoid_start = avoid_end = 0; | ||
885 | #ifdef CONFIG_BLK_DEV_INITRD | ||
886 | avoid_start = initrd_start; | ||
887 | avoid_end = PAGE_ALIGN(initrd_end); | ||
888 | #endif | ||
889 | |||
890 | /* Trim some pavail[] entries in order to satisfy the | ||
891 | * requested "mem=xxx" kernel command line specification. | ||
892 | * | ||
893 | * We must not trim off the kernel image area nor the | ||
894 | * initial ramdisk range (if any). Also, we must not trim | ||
895 | * any pavail[] entry down to zero in order to preserve | ||
896 | * the invariant that all pavail[] entries have a non-zero | ||
897 | * size which is assumed by all of the code in here. | ||
898 | */ | ||
899 | for (i = 0; i < pavail_ents; i++) { | ||
900 | unsigned long start, end, kern_end; | ||
901 | unsigned long trim_low, trim_high, n; | ||
902 | |||
903 | kern_end = PAGE_ALIGN(kern_base + kern_size); | ||
904 | |||
905 | trim_low = start = pavail[i].phys_addr; | ||
906 | trim_high = end = start + pavail[i].reg_size; | ||
907 | |||
908 | if (kern_base >= start && | ||
909 | kern_base < end) { | ||
910 | trim_low = kern_base; | ||
911 | if (kern_end >= end) | ||
912 | continue; | ||
913 | } | ||
914 | if (kern_end >= start && | ||
915 | kern_end < end) { | ||
916 | trim_high = kern_end; | ||
917 | } | ||
918 | if (avoid_start && | ||
919 | avoid_start >= start && | ||
920 | avoid_start < end) { | ||
921 | if (trim_low > avoid_start) | ||
922 | trim_low = avoid_start; | ||
923 | if (avoid_end >= end) | ||
924 | continue; | ||
925 | } | ||
926 | if (avoid_end && | ||
927 | avoid_end >= start && | ||
928 | avoid_end < end) { | ||
929 | if (trim_high < avoid_end) | ||
930 | trim_high = avoid_end; | ||
931 | } | ||
932 | |||
933 | if (trim_high <= trim_low) | ||
934 | continue; | ||
935 | |||
936 | if (trim_low == start && trim_high == end) { | ||
937 | /* Whole chunk is available for trimming. | ||
938 | * Trim all except one page, in order to keep | ||
939 | * entry non-empty. | ||
940 | */ | ||
941 | n = (end - start) - PAGE_SIZE; | ||
942 | if (n > to_trim) | ||
943 | n = to_trim; | ||
944 | |||
945 | if (n) { | ||
946 | pavail[i].phys_addr += n; | ||
947 | pavail[i].reg_size -= n; | ||
948 | to_trim -= n; | ||
949 | } | ||
950 | } else { | ||
951 | n = (trim_low - start); | ||
952 | if (n > to_trim) | ||
953 | n = to_trim; | ||
954 | |||
955 | if (n) { | ||
956 | pavail[i].phys_addr += n; | ||
957 | pavail[i].reg_size -= n; | ||
958 | to_trim -= n; | ||
959 | } | ||
960 | if (to_trim) { | ||
961 | n = end - trim_high; | ||
962 | if (n > to_trim) | ||
963 | n = to_trim; | ||
964 | if (n) { | ||
965 | pavail[i].reg_size -= n; | ||
966 | to_trim -= n; | ||
967 | } | ||
968 | } | ||
969 | } | ||
970 | |||
971 | if (!to_trim) | ||
972 | break; | ||
973 | } | ||
974 | |||
975 | /* Recalculate. */ | ||
976 | *cur_size_p = 0UL; | ||
977 | for (i = 0; i < pavail_ents; i++) { | ||
978 | *end_of_phys_p = pavail[i].phys_addr + | ||
979 | pavail[i].reg_size; | ||
980 | *cur_size_p += pavail[i].reg_size; | ||
981 | } | ||
982 | } | ||
983 | |||
875 | static unsigned long __init bootmem_init(unsigned long *pages_avail, | 984 | static unsigned long __init bootmem_init(unsigned long *pages_avail, |
876 | unsigned long phys_base) | 985 | unsigned long phys_base) |
877 | { | 986 | { |
@@ -889,31 +998,13 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, | |||
889 | end_of_phys_memory = pavail[i].phys_addr + | 998 | end_of_phys_memory = pavail[i].phys_addr + |
890 | pavail[i].reg_size; | 999 | pavail[i].reg_size; |
891 | bytes_avail += pavail[i].reg_size; | 1000 | bytes_avail += pavail[i].reg_size; |
892 | if (cmdline_memory_size) { | ||
893 | if (bytes_avail > cmdline_memory_size) { | ||
894 | unsigned long slack = bytes_avail - cmdline_memory_size; | ||
895 | |||
896 | bytes_avail -= slack; | ||
897 | end_of_phys_memory -= slack; | ||
898 | |||
899 | pavail[i].reg_size -= slack; | ||
900 | if ((long)pavail[i].reg_size <= 0L) { | ||
901 | pavail[i].phys_addr = 0xdeadbeefUL; | ||
902 | pavail[i].reg_size = 0UL; | ||
903 | pavail_ents = i; | ||
904 | } else { | ||
905 | pavail[i+1].reg_size = 0Ul; | ||
906 | pavail[i+1].phys_addr = 0xdeadbeefUL; | ||
907 | pavail_ents = i + 1; | ||
908 | } | ||
909 | break; | ||
910 | } | ||
911 | } | ||
912 | } | 1001 | } |
913 | 1002 | ||
914 | *pages_avail = bytes_avail >> PAGE_SHIFT; | 1003 | /* Determine the location of the initial ramdisk before trying |
915 | 1004 | * to honor the "mem=xxx" command line argument. We must know | |
916 | end_pfn = end_of_phys_memory >> PAGE_SHIFT; | 1005 | * where the kernel image and the ramdisk image are so that we |
1006 | * do not trim those two areas from the physical memory map. | ||
1007 | */ | ||
917 | 1008 | ||
918 | #ifdef CONFIG_BLK_DEV_INITRD | 1009 | #ifdef CONFIG_BLK_DEV_INITRD |
919 | /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ | 1010 | /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ |
@@ -932,6 +1023,16 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, | |||
932 | } | 1023 | } |
933 | } | 1024 | } |
934 | #endif | 1025 | #endif |
1026 | |||
1027 | if (cmdline_memory_size && | ||
1028 | bytes_avail > cmdline_memory_size) | ||
1029 | trim_pavail(&bytes_avail, | ||
1030 | &end_of_phys_memory); | ||
1031 | |||
1032 | *pages_avail = bytes_avail >> PAGE_SHIFT; | ||
1033 | |||
1034 | end_pfn = end_of_phys_memory >> PAGE_SHIFT; | ||
1035 | |||
935 | /* Initialize the boot-time allocator. */ | 1036 | /* Initialize the boot-time allocator. */ |
936 | max_pfn = max_low_pfn = end_pfn; | 1037 | max_pfn = max_low_pfn = end_pfn; |
937 | min_low_pfn = (phys_base >> PAGE_SHIFT); | 1038 | min_low_pfn = (phys_base >> PAGE_SHIFT); |