diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-08-25 16:39:17 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-08-27 14:12:29 -0400 |
commit | 72d7c3b33c980843e756681fb4867dc1efd62a76 (patch) | |
tree | 9607345d9fa055dd501aacf0772258fb72897035 | |
parent | 301ff3e88ef9ff4bdb92f36a3e6170fce4c9dd34 (diff) |
x86: Use memblock to replace early_res
1. replace find_e820_area with memblock_find_in_range
2. replace reserve_early with memblock_x86_reserve_range
3. replace free_early with memblock_x86_free_range.
4. NO_BOOTMEM will switch to use memblock too.
5. use _e820, _early wrap in the patch, in following patch, will
replace them all
6. because memblock_x86_free_range support partial free, we can remove some special care
7. Need to make sure that memblock_find_in_range() is called after memblock_x86_fill()
so adjust some calling later in setup.c::setup_arch()
-- corruption_check and mptable_update
-v2: Move reserve_brk() early
Before fill_memblock_area, to avoid overlap between brk and memblock_find_in_range()
that could happen We have more then 128 RAM entry in E820 tables, and
memblock_x86_fill() could use memblock_find_in_range() to find a new place for
memblock.memory.region array.
and We don't need to use extend_brk() after fill_memblock_area()
So move reserve_brk() early before fill_memblock_area().
-v3: Move find_smp_config early
To make sure memblock_find_in_range not find wrong place, if BIOS doesn't put mptable
in right place.
-v4: Treat RESERVED_KERN as RAM in memblock.memory. and they are already in
memblock.reserved already..
use __NOT_KEEP_MEMBLOCK to make sure memblock related code could be freed later.
-v5: Generic version __memblock_find_in_range() is going from high to low, and for 32bit
active_region for 32bit does include high pages
need to replace the limit with memblock.default_alloc_limit, aka get_max_mapped()
-v6: Use current_limit instead
-v7: check with MEMBLOCK_ERROR instead of -1ULL or -1L
-v8: Set memblock_can_resize early to handle EFI with more RAM entries
-v9: update after kmemleak changes in mainline
Suggested-by: David S. Miller <davem@davemloft.net>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | arch/x86/Kconfig | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/e820.h | 14 | ||||
-rw-r--r-- | arch/x86/kernel/check.c | 16 | ||||
-rw-r--r-- | arch/x86/kernel/e820.c | 159 | ||||
-rw-r--r-- | arch/x86/kernel/head.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/head32.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/head64.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/mpparse.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 46 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 6 | ||||
-rw-r--r-- | arch/x86/mm/numa_64.c | 9 | ||||
-rw-r--r-- | mm/bootmem.c | 3 | ||||
-rw-r--r-- | mm/page_alloc.c | 50 | ||||
-rw-r--r-- | mm/sparse-vmemmap.c | 11 |
14 files changed, 141 insertions, 199 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index dcb0593b4a66..542bb2610cbb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -27,6 +27,7 @@ config X86 | |||
27 | select HAVE_PERF_EVENTS if (!M386 && !M486) | 27 | select HAVE_PERF_EVENTS if (!M386 && !M486) |
28 | select HAVE_IOREMAP_PROT | 28 | select HAVE_IOREMAP_PROT |
29 | select HAVE_KPROBES | 29 | select HAVE_KPROBES |
30 | select HAVE_MEMBLOCK | ||
30 | select ARCH_WANT_OPTIONAL_GPIOLIB | 31 | select ARCH_WANT_OPTIONAL_GPIOLIB |
31 | select ARCH_WANT_FRAME_POINTERS | 32 | select ARCH_WANT_FRAME_POINTERS |
32 | select HAVE_DMA_ATTRS | 33 | select HAVE_DMA_ATTRS |
@@ -195,9 +196,6 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING | |||
195 | config ARCH_SUPPORTS_DEBUG_PAGEALLOC | 196 | config ARCH_SUPPORTS_DEBUG_PAGEALLOC |
196 | def_bool y | 197 | def_bool y |
197 | 198 | ||
198 | config HAVE_EARLY_RES | ||
199 | def_bool y | ||
200 | |||
201 | config HAVE_INTEL_TXT | 199 | config HAVE_INTEL_TXT |
202 | def_bool y | 200 | def_bool y |
203 | depends on EXPERIMENTAL && DMAR && ACPI | 201 | depends on EXPERIMENTAL && DMAR && ACPI |
@@ -590,14 +588,13 @@ config NO_BOOTMEM | |||
590 | default y | 588 | default y |
591 | bool "Disable Bootmem code" | 589 | bool "Disable Bootmem code" |
592 | ---help--- | 590 | ---help--- |
593 | Use early_res directly instead of bootmem before slab is ready. | 591 | Use memblock directly instead of bootmem before slab is ready. |
594 | - allocator (buddy) [generic] | 592 | - allocator (buddy) [generic] |
595 | - early allocator (bootmem) [generic] | 593 | - early allocator (bootmem) [generic] |
596 | - very early allocator (reserve_early*()) [x86] | 594 | - very early allocator (memblock) [some generic] |
597 | - very very early allocator (early brk model) [x86] | 595 | - very very early allocator (early brk model) [x86] |
598 | So reduce one layer between early allocator to final allocator | 596 | So reduce one layer between early allocator to final allocator |
599 | 597 | ||
600 | |||
601 | config MEMTEST | 598 | config MEMTEST |
602 | bool "Memtest" | 599 | bool "Memtest" |
603 | ---help--- | 600 | ---help--- |
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h index ec8a52d14ab1..388fed291467 100644 --- a/arch/x86/include/asm/e820.h +++ b/arch/x86/include/asm/e820.h | |||
@@ -117,24 +117,26 @@ extern unsigned long end_user_pfn; | |||
117 | extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align); | 117 | extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align); |
118 | extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align); | 118 | extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align); |
119 | extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); | 119 | extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); |
120 | #include <linux/early_res.h> | ||
121 | 120 | ||
122 | extern unsigned long e820_end_of_ram_pfn(void); | 121 | extern unsigned long e820_end_of_ram_pfn(void); |
123 | extern unsigned long e820_end_of_low_ram_pfn(void); | 122 | extern unsigned long e820_end_of_low_ram_pfn(void); |
124 | extern int e820_find_active_region(const struct e820entry *ei, | ||
125 | unsigned long start_pfn, | ||
126 | unsigned long last_pfn, | ||
127 | unsigned long *ei_startpfn, | ||
128 | unsigned long *ei_endpfn); | ||
129 | extern void e820_register_active_regions(int nid, unsigned long start_pfn, | 123 | extern void e820_register_active_regions(int nid, unsigned long start_pfn, |
130 | unsigned long end_pfn); | 124 | unsigned long end_pfn); |
131 | extern u64 e820_hole_size(u64 start, u64 end); | 125 | extern u64 e820_hole_size(u64 start, u64 end); |
126 | |||
127 | extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); | ||
128 | |||
129 | void memblock_x86_fill(void); | ||
130 | |||
132 | extern void finish_e820_parsing(void); | 131 | extern void finish_e820_parsing(void); |
133 | extern void e820_reserve_resources(void); | 132 | extern void e820_reserve_resources(void); |
134 | extern void e820_reserve_resources_late(void); | 133 | extern void e820_reserve_resources_late(void); |
135 | extern void setup_memory_map(void); | 134 | extern void setup_memory_map(void); |
136 | extern char *default_machine_specific_memory_setup(void); | 135 | extern char *default_machine_specific_memory_setup(void); |
137 | 136 | ||
137 | void reserve_early(u64 start, u64 end, char *name); | ||
138 | void free_early(u64 start, u64 end); | ||
139 | |||
138 | /* | 140 | /* |
139 | * Returns true iff the specified range [s,e) is completely contained inside | 141 | * Returns true iff the specified range [s,e) is completely contained inside |
140 | * the ISA region. | 142 | * the ISA region. |
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c index fc999e6fc46a..13a389179514 100644 --- a/arch/x86/kernel/check.c +++ b/arch/x86/kernel/check.c | |||
@@ -2,7 +2,8 @@ | |||
2 | #include <linux/sched.h> | 2 | #include <linux/sched.h> |
3 | #include <linux/kthread.h> | 3 | #include <linux/kthread.h> |
4 | #include <linux/workqueue.h> | 4 | #include <linux/workqueue.h> |
5 | #include <asm/e820.h> | 5 | #include <linux/memblock.h> |
6 | |||
6 | #include <asm/proto.h> | 7 | #include <asm/proto.h> |
7 | 8 | ||
8 | /* | 9 | /* |
@@ -18,10 +19,12 @@ static int __read_mostly memory_corruption_check = -1; | |||
18 | static unsigned __read_mostly corruption_check_size = 64*1024; | 19 | static unsigned __read_mostly corruption_check_size = 64*1024; |
19 | static unsigned __read_mostly corruption_check_period = 60; /* seconds */ | 20 | static unsigned __read_mostly corruption_check_period = 60; /* seconds */ |
20 | 21 | ||
21 | static struct e820entry scan_areas[MAX_SCAN_AREAS]; | 22 | static struct scan_area { |
23 | u64 addr; | ||
24 | u64 size; | ||
25 | } scan_areas[MAX_SCAN_AREAS]; | ||
22 | static int num_scan_areas; | 26 | static int num_scan_areas; |
23 | 27 | ||
24 | |||
25 | static __init int set_corruption_check(char *arg) | 28 | static __init int set_corruption_check(char *arg) |
26 | { | 29 | { |
27 | char *end; | 30 | char *end; |
@@ -81,9 +84,9 @@ void __init setup_bios_corruption_check(void) | |||
81 | 84 | ||
82 | while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { | 85 | while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { |
83 | u64 size; | 86 | u64 size; |
84 | addr = find_e820_area_size(addr, &size, PAGE_SIZE); | 87 | addr = memblock_x86_find_in_range_size(addr, &size, PAGE_SIZE); |
85 | 88 | ||
86 | if (!(addr + 1)) | 89 | if (addr == MEMBLOCK_ERROR) |
87 | break; | 90 | break; |
88 | 91 | ||
89 | if (addr >= corruption_check_size) | 92 | if (addr >= corruption_check_size) |
@@ -92,7 +95,7 @@ void __init setup_bios_corruption_check(void) | |||
92 | if ((addr + size) > corruption_check_size) | 95 | if ((addr + size) > corruption_check_size) |
93 | size = corruption_check_size - addr; | 96 | size = corruption_check_size - addr; |
94 | 97 | ||
95 | e820_update_range(addr, size, E820_RAM, E820_RESERVED); | 98 | memblock_x86_reserve_range(addr, addr + size, "SCAN RAM"); |
96 | scan_areas[num_scan_areas].addr = addr; | 99 | scan_areas[num_scan_areas].addr = addr; |
97 | scan_areas[num_scan_areas].size = size; | 100 | scan_areas[num_scan_areas].size = size; |
98 | num_scan_areas++; | 101 | num_scan_areas++; |
@@ -105,7 +108,6 @@ void __init setup_bios_corruption_check(void) | |||
105 | 108 | ||
106 | printk(KERN_INFO "Scanning %d areas for low memory corruption\n", | 109 | printk(KERN_INFO "Scanning %d areas for low memory corruption\n", |
107 | num_scan_areas); | 110 | num_scan_areas); |
108 | update_e820(); | ||
109 | } | 111 | } |
110 | 112 | ||
111 | 113 | ||
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 0d6fc71bedb1..a9221d18a5ed 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/pfn.h> | 15 | #include <linux/pfn.h> |
16 | #include <linux/suspend.h> | 16 | #include <linux/suspend.h> |
17 | #include <linux/firmware-map.h> | 17 | #include <linux/firmware-map.h> |
18 | #include <linux/memblock.h> | ||
18 | 19 | ||
19 | #include <asm/e820.h> | 20 | #include <asm/e820.h> |
20 | #include <asm/proto.h> | 21 | #include <asm/proto.h> |
@@ -742,69 +743,29 @@ core_initcall(e820_mark_nvs_memory); | |||
742 | */ | 743 | */ |
743 | u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align) | 744 | u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align) |
744 | { | 745 | { |
745 | int i; | 746 | u64 mem = memblock_find_in_range(start, end, size, align); |
746 | |||
747 | for (i = 0; i < e820.nr_map; i++) { | ||
748 | struct e820entry *ei = &e820.map[i]; | ||
749 | u64 addr; | ||
750 | u64 ei_start, ei_last; | ||
751 | 747 | ||
752 | if (ei->type != E820_RAM) | 748 | if (mem == MEMBLOCK_ERROR) |
753 | continue; | 749 | return -1ULL; |
754 | |||
755 | ei_last = ei->addr + ei->size; | ||
756 | ei_start = ei->addr; | ||
757 | addr = find_early_area(ei_start, ei_last, start, end, | ||
758 | size, align); | ||
759 | |||
760 | if (addr != -1ULL) | ||
761 | return addr; | ||
762 | } | ||
763 | return -1ULL; | ||
764 | } | ||
765 | 750 | ||
766 | u64 __init find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align) | 751 | return mem; |
767 | { | ||
768 | return find_e820_area(start, end, size, align); | ||
769 | } | 752 | } |
770 | 753 | ||
771 | u64 __init get_max_mapped(void) | ||
772 | { | ||
773 | u64 end = max_pfn_mapped; | ||
774 | |||
775 | end <<= PAGE_SHIFT; | ||
776 | |||
777 | return end; | ||
778 | } | ||
779 | /* | 754 | /* |
780 | * Find next free range after *start | 755 | * Find next free range after *start |
781 | */ | 756 | */ |
782 | u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align) | 757 | u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align) |
783 | { | 758 | { |
784 | int i; | 759 | u64 mem = memblock_x86_find_in_range_size(start, sizep, align); |
785 | 760 | ||
786 | for (i = 0; i < e820.nr_map; i++) { | 761 | if (mem == MEMBLOCK_ERROR) |
787 | struct e820entry *ei = &e820.map[i]; | 762 | return -1ULL |
788 | u64 addr; | ||
789 | u64 ei_start, ei_last; | ||
790 | |||
791 | if (ei->type != E820_RAM) | ||
792 | continue; | ||
793 | |||
794 | ei_last = ei->addr + ei->size; | ||
795 | ei_start = ei->addr; | ||
796 | addr = find_early_area_size(ei_start, ei_last, start, | ||
797 | sizep, align); | ||
798 | 763 | ||
799 | if (addr != -1ULL) | 764 | return mem; |
800 | return addr; | ||
801 | } | ||
802 | |||
803 | return -1ULL; | ||
804 | } | 765 | } |
805 | 766 | ||
806 | /* | 767 | /* |
807 | * pre allocated 4k and reserved it in e820 | 768 | * pre allocated 4k and reserved it in memblock and e820_saved |
808 | */ | 769 | */ |
809 | u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) | 770 | u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) |
810 | { | 771 | { |
@@ -813,8 +774,8 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) | |||
813 | u64 start; | 774 | u64 start; |
814 | 775 | ||
815 | for (start = startt; ; start += size) { | 776 | for (start = startt; ; start += size) { |
816 | start = find_e820_area_size(start, &size, align); | 777 | start = memblock_x86_find_in_range_size(start, &size, align); |
817 | if (!(start + 1)) | 778 | if (start == MEMBLOCK_ERROR) |
818 | return 0; | 779 | return 0; |
819 | if (size >= sizet) | 780 | if (size >= sizet) |
820 | break; | 781 | break; |
@@ -830,10 +791,9 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) | |||
830 | addr = round_down(start + size - sizet, align); | 791 | addr = round_down(start + size - sizet, align); |
831 | if (addr < start) | 792 | if (addr < start) |
832 | return 0; | 793 | return 0; |
833 | e820_update_range(addr, sizet, E820_RAM, E820_RESERVED); | 794 | memblock_x86_reserve_range(addr, addr + sizet, "new next"); |
834 | e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED); | 795 | e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED); |
835 | printk(KERN_INFO "update e820 for early_reserve_e820\n"); | 796 | printk(KERN_INFO "update e820_saved for early_reserve_e820\n"); |
836 | update_e820(); | ||
837 | update_e820_saved(); | 797 | update_e820_saved(); |
838 | 798 | ||
839 | return addr; | 799 | return addr; |
@@ -895,52 +855,12 @@ unsigned long __init e820_end_of_low_ram_pfn(void) | |||
895 | { | 855 | { |
896 | return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM); | 856 | return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM); |
897 | } | 857 | } |
898 | /* | ||
899 | * Finds an active region in the address range from start_pfn to last_pfn and | ||
900 | * returns its range in ei_startpfn and ei_endpfn for the e820 entry. | ||
901 | */ | ||
902 | int __init e820_find_active_region(const struct e820entry *ei, | ||
903 | unsigned long start_pfn, | ||
904 | unsigned long last_pfn, | ||
905 | unsigned long *ei_startpfn, | ||
906 | unsigned long *ei_endpfn) | ||
907 | { | ||
908 | u64 align = PAGE_SIZE; | ||
909 | |||
910 | *ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT; | ||
911 | *ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT; | ||
912 | |||
913 | /* Skip map entries smaller than a page */ | ||
914 | if (*ei_startpfn >= *ei_endpfn) | ||
915 | return 0; | ||
916 | |||
917 | /* Skip if map is outside the node */ | ||
918 | if (ei->type != E820_RAM || *ei_endpfn <= start_pfn || | ||
919 | *ei_startpfn >= last_pfn) | ||
920 | return 0; | ||
921 | |||
922 | /* Check for overlaps */ | ||
923 | if (*ei_startpfn < start_pfn) | ||
924 | *ei_startpfn = start_pfn; | ||
925 | if (*ei_endpfn > last_pfn) | ||
926 | *ei_endpfn = last_pfn; | ||
927 | |||
928 | return 1; | ||
929 | } | ||
930 | 858 | ||
931 | /* Walk the e820 map and register active regions within a node */ | 859 | /* Walk the e820 map and register active regions within a node */ |
932 | void __init e820_register_active_regions(int nid, unsigned long start_pfn, | 860 | void __init e820_register_active_regions(int nid, unsigned long start_pfn, |
933 | unsigned long last_pfn) | 861 | unsigned long last_pfn) |
934 | { | 862 | { |
935 | unsigned long ei_startpfn; | 863 | memblock_x86_register_active_regions(nid, start_pfn, last_pfn); |
936 | unsigned long ei_endpfn; | ||
937 | int i; | ||
938 | |||
939 | for (i = 0; i < e820.nr_map; i++) | ||
940 | if (e820_find_active_region(&e820.map[i], | ||
941 | start_pfn, last_pfn, | ||
942 | &ei_startpfn, &ei_endpfn)) | ||
943 | add_active_range(nid, ei_startpfn, ei_endpfn); | ||
944 | } | 864 | } |
945 | 865 | ||
946 | /* | 866 | /* |
@@ -950,18 +870,16 @@ void __init e820_register_active_regions(int nid, unsigned long start_pfn, | |||
950 | */ | 870 | */ |
951 | u64 __init e820_hole_size(u64 start, u64 end) | 871 | u64 __init e820_hole_size(u64 start, u64 end) |
952 | { | 872 | { |
953 | unsigned long start_pfn = start >> PAGE_SHIFT; | 873 | return memblock_x86_hole_size(start, end); |
954 | unsigned long last_pfn = end >> PAGE_SHIFT; | 874 | } |
955 | unsigned long ei_startpfn, ei_endpfn, ram = 0; | ||
956 | int i; | ||
957 | 875 | ||
958 | for (i = 0; i < e820.nr_map; i++) { | 876 | void reserve_early(u64 start, u64 end, char *name) |
959 | if (e820_find_active_region(&e820.map[i], | 877 | { |
960 | start_pfn, last_pfn, | 878 | memblock_x86_reserve_range(start, end, name); |
961 | &ei_startpfn, &ei_endpfn)) | 879 | } |
962 | ram += ei_endpfn - ei_startpfn; | 880 | void free_early(u64 start, u64 end) |
963 | } | 881 | { |
964 | return end - start - ((u64)ram << PAGE_SHIFT); | 882 | memblock_x86_free_range(start, end); |
965 | } | 883 | } |
966 | 884 | ||
967 | static void early_panic(char *msg) | 885 | static void early_panic(char *msg) |
@@ -1210,3 +1128,32 @@ void __init setup_memory_map(void) | |||
1210 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | 1128 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); |
1211 | e820_print_map(who); | 1129 | e820_print_map(who); |
1212 | } | 1130 | } |
1131 | |||
1132 | void __init memblock_x86_fill(void) | ||
1133 | { | ||
1134 | int i; | ||
1135 | u64 end; | ||
1136 | |||
1137 | /* | ||
1138 | * EFI may have more than 128 entries | ||
1139 | * We are safe to enable resizing, beause memblock_x86_fill() | ||
1140 | * is rather later for x86 | ||
1141 | */ | ||
1142 | memblock_can_resize = 1; | ||
1143 | |||
1144 | for (i = 0; i < e820.nr_map; i++) { | ||
1145 | struct e820entry *ei = &e820.map[i]; | ||
1146 | |||
1147 | end = ei->addr + ei->size; | ||
1148 | if (end != (resource_size_t)end) | ||
1149 | continue; | ||
1150 | |||
1151 | if (ei->type != E820_RAM && ei->type != E820_RESERVED_KERN) | ||
1152 | continue; | ||
1153 | |||
1154 | memblock_add(ei->addr, ei->size); | ||
1155 | } | ||
1156 | |||
1157 | memblock_analyze(); | ||
1158 | memblock_dump_all(); | ||
1159 | } | ||
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c index 3e66bd364a9d..af0699ba48cf 100644 --- a/arch/x86/kernel/head.c +++ b/arch/x86/kernel/head.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | #include <linux/memblock.h> | ||
3 | 4 | ||
4 | #include <asm/setup.h> | 5 | #include <asm/setup.h> |
5 | #include <asm/bios_ebda.h> | 6 | #include <asm/bios_ebda.h> |
@@ -51,5 +52,5 @@ void __init reserve_ebda_region(void) | |||
51 | lowmem = 0x9f000; | 52 | lowmem = 0x9f000; |
52 | 53 | ||
53 | /* reserve all memory between lowmem and the 1MB mark */ | 54 | /* reserve all memory between lowmem and the 1MB mark */ |
54 | reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved"); | 55 | memblock_x86_reserve_range(lowmem, 0x100000, "* BIOS reserved"); |
55 | } | 56 | } |
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index b2e246037392..da60aa8a850f 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/start_kernel.h> | 9 | #include <linux/start_kernel.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/memblock.h> | ||
11 | 12 | ||
12 | #include <asm/setup.h> | 13 | #include <asm/setup.h> |
13 | #include <asm/sections.h> | 14 | #include <asm/sections.h> |
@@ -30,14 +31,15 @@ static void __init i386_default_early_setup(void) | |||
30 | 31 | ||
31 | void __init i386_start_kernel(void) | 32 | void __init i386_start_kernel(void) |
32 | { | 33 | { |
34 | memblock_init(); | ||
35 | |||
33 | #ifdef CONFIG_X86_TRAMPOLINE | 36 | #ifdef CONFIG_X86_TRAMPOLINE |
34 | /* | 37 | /* |
35 | * But first pinch a few for the stack/trampoline stuff | 38 | * But first pinch a few for the stack/trampoline stuff |
36 | * FIXME: Don't need the extra page at 4K, but need to fix | 39 | * FIXME: Don't need the extra page at 4K, but need to fix |
37 | * trampoline before removing it. (see the GDT stuff) | 40 | * trampoline before removing it. (see the GDT stuff) |
38 | */ | 41 | */ |
39 | reserve_early_overlap_ok(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, | 42 | memblock_x86_reserve_range(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE"); |
40 | "EX TRAMPOLINE"); | ||
41 | #endif | 43 | #endif |
42 | 44 | ||
43 | reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); | 45 | reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); |
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 7147143fd614..8ee930fdeeb9 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/percpu.h> | 12 | #include <linux/percpu.h> |
13 | #include <linux/start_kernel.h> | 13 | #include <linux/start_kernel.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/memblock.h> | ||
15 | 16 | ||
16 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
17 | #include <asm/proto.h> | 18 | #include <asm/proto.h> |
@@ -98,6 +99,8 @@ void __init x86_64_start_reservations(char *real_mode_data) | |||
98 | { | 99 | { |
99 | copy_bootdata(__va(real_mode_data)); | 100 | copy_bootdata(__va(real_mode_data)); |
100 | 101 | ||
102 | memblock_init(); | ||
103 | |||
101 | reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); | 104 | reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS"); |
102 | 105 | ||
103 | #ifdef CONFIG_BLK_DEV_INITRD | 106 | #ifdef CONFIG_BLK_DEV_INITRD |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index d86dbf7e54be..8252545ae6f3 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
13 | #include <linux/bootmem.h> | 13 | #include <linux/bootmem.h> |
14 | #include <linux/memblock.h> | ||
14 | #include <linux/kernel_stat.h> | 15 | #include <linux/kernel_stat.h> |
15 | #include <linux/mc146818rtc.h> | 16 | #include <linux/mc146818rtc.h> |
16 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
@@ -641,7 +642,7 @@ static void __init smp_reserve_memory(struct mpf_intel *mpf) | |||
641 | { | 642 | { |
642 | unsigned long size = get_mpc_size(mpf->physptr); | 643 | unsigned long size = get_mpc_size(mpf->physptr); |
643 | 644 | ||
644 | reserve_early_overlap_ok(mpf->physptr, mpf->physptr+size, "MP-table mpc"); | 645 | memblock_x86_reserve_range(mpf->physptr, mpf->physptr+size, "* MP-table mpc"); |
645 | } | 646 | } |
646 | 647 | ||
647 | static int __init smp_scan_config(unsigned long base, unsigned long length) | 648 | static int __init smp_scan_config(unsigned long base, unsigned long length) |
@@ -670,7 +671,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) | |||
670 | mpf, (u64)virt_to_phys(mpf)); | 671 | mpf, (u64)virt_to_phys(mpf)); |
671 | 672 | ||
672 | mem = virt_to_phys(mpf); | 673 | mem = virt_to_phys(mpf); |
673 | reserve_early_overlap_ok(mem, mem + sizeof(*mpf), "MP-table mpf"); | 674 | memblock_x86_reserve_range(mem, mem + sizeof(*mpf), "* MP-table mpf"); |
674 | if (mpf->physptr) | 675 | if (mpf->physptr) |
675 | smp_reserve_memory(mpf); | 676 | smp_reserve_memory(mpf); |
676 | 677 | ||
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b4ae4acbd031..bbe0aaf77494 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/apm_bios.h> | 31 | #include <linux/apm_bios.h> |
32 | #include <linux/initrd.h> | 32 | #include <linux/initrd.h> |
33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
34 | #include <linux/memblock.h> | ||
34 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
35 | #include <linux/console.h> | 36 | #include <linux/console.h> |
36 | #include <linux/mca.h> | 37 | #include <linux/mca.h> |
@@ -614,7 +615,7 @@ static __init void reserve_ibft_region(void) | |||
614 | addr = find_ibft_region(&size); | 615 | addr = find_ibft_region(&size); |
615 | 616 | ||
616 | if (size) | 617 | if (size) |
617 | reserve_early_overlap_ok(addr, addr + size, "ibft"); | 618 | memblock_x86_reserve_range(addr, addr + size, "* ibft"); |
618 | } | 619 | } |
619 | 620 | ||
620 | #ifdef CONFIG_X86_RESERVE_LOW_64K | 621 | #ifdef CONFIG_X86_RESERVE_LOW_64K |
@@ -708,6 +709,15 @@ static void __init trim_bios_range(void) | |||
708 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 709 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
709 | } | 710 | } |
710 | 711 | ||
712 | static u64 __init get_max_mapped(void) | ||
713 | { | ||
714 | u64 end = max_pfn_mapped; | ||
715 | |||
716 | end <<= PAGE_SHIFT; | ||
717 | |||
718 | return end; | ||
719 | } | ||
720 | |||
711 | /* | 721 | /* |
712 | * Determine if we were loaded by an EFI loader. If so, then we have also been | 722 | * Determine if we were loaded by an EFI loader. If so, then we have also been |
713 | * passed the efi memmap, systab, etc., so we should use these data structures | 723 | * passed the efi memmap, systab, etc., so we should use these data structures |
@@ -891,8 +901,6 @@ void __init setup_arch(char **cmdline_p) | |||
891 | */ | 901 | */ |
892 | max_pfn = e820_end_of_ram_pfn(); | 902 | max_pfn = e820_end_of_ram_pfn(); |
893 | 903 | ||
894 | /* preallocate 4k for mptable mpc */ | ||
895 | early_reserve_e820_mpc_new(); | ||
896 | /* update e820 for memory not covered by WB MTRRs */ | 904 | /* update e820 for memory not covered by WB MTRRs */ |
897 | mtrr_bp_init(); | 905 | mtrr_bp_init(); |
898 | if (mtrr_trim_uncached_memory(max_pfn)) | 906 | if (mtrr_trim_uncached_memory(max_pfn)) |
@@ -917,15 +925,6 @@ void __init setup_arch(char **cmdline_p) | |||
917 | max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT; | 925 | max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT; |
918 | #endif | 926 | #endif |
919 | 927 | ||
920 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
921 | setup_bios_corruption_check(); | ||
922 | #endif | ||
923 | |||
924 | printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n", | ||
925 | max_pfn_mapped<<PAGE_SHIFT); | ||
926 | |||
927 | reserve_brk(); | ||
928 | |||
929 | /* | 928 | /* |
930 | * Find and reserve possible boot-time SMP configuration: | 929 | * Find and reserve possible boot-time SMP configuration: |
931 | */ | 930 | */ |
@@ -933,6 +932,26 @@ void __init setup_arch(char **cmdline_p) | |||
933 | 932 | ||
934 | reserve_ibft_region(); | 933 | reserve_ibft_region(); |
935 | 934 | ||
935 | /* | ||
936 | * Need to conclude brk, before memblock_x86_fill() | ||
937 | * it could use memblock_find_in_range, could overlap with | ||
938 | * brk area. | ||
939 | */ | ||
940 | reserve_brk(); | ||
941 | |||
942 | memblock.current_limit = get_max_mapped(); | ||
943 | memblock_x86_fill(); | ||
944 | |||
945 | /* preallocate 4k for mptable mpc */ | ||
946 | early_reserve_e820_mpc_new(); | ||
947 | |||
948 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | ||
949 | setup_bios_corruption_check(); | ||
950 | #endif | ||
951 | |||
952 | printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n", | ||
953 | max_pfn_mapped<<PAGE_SHIFT); | ||
954 | |||
936 | reserve_trampoline_memory(); | 955 | reserve_trampoline_memory(); |
937 | 956 | ||
938 | #ifdef CONFIG_ACPI_SLEEP | 957 | #ifdef CONFIG_ACPI_SLEEP |
@@ -956,6 +975,7 @@ void __init setup_arch(char **cmdline_p) | |||
956 | max_low_pfn = max_pfn; | 975 | max_low_pfn = max_pfn; |
957 | } | 976 | } |
958 | #endif | 977 | #endif |
978 | memblock.current_limit = get_max_mapped(); | ||
959 | 979 | ||
960 | /* | 980 | /* |
961 | * NOTE: On x86-32, only from this point on, fixmaps are ready for use. | 981 | * NOTE: On x86-32, only from this point on, fixmaps are ready for use. |
@@ -995,7 +1015,7 @@ void __init setup_arch(char **cmdline_p) | |||
995 | 1015 | ||
996 | initmem_init(0, max_pfn, acpi, k8); | 1016 | initmem_init(0, max_pfn, acpi, k8); |
997 | #ifndef CONFIG_NO_BOOTMEM | 1017 | #ifndef CONFIG_NO_BOOTMEM |
998 | early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT); | 1018 | memblock_x86_to_bootmem(0, max_low_pfn<<PAGE_SHIFT); |
999 | #endif | 1019 | #endif |
1000 | 1020 | ||
1001 | dma32_reserve_bootmem(); | 1021 | dma32_reserve_bootmem(); |
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index a60df9ae6454..42e2633f369e 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -131,13 +131,7 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align) | |||
131 | 131 | ||
132 | static void __init pcpu_fc_free(void *ptr, size_t size) | 132 | static void __init pcpu_fc_free(void *ptr, size_t size) |
133 | { | 133 | { |
134 | #ifdef CONFIG_NO_BOOTMEM | ||
135 | u64 start = __pa(ptr); | ||
136 | u64 end = start + size; | ||
137 | free_early_partial(start, end); | ||
138 | #else | ||
139 | free_bootmem(__pa(ptr), size); | 134 | free_bootmem(__pa(ptr), size); |
140 | #endif | ||
141 | } | 135 | } |
142 | 136 | ||
143 | static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) | 137 | static int __init pcpu_cpu_distance(unsigned int from, unsigned int to) |
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index a7bcc23ef96c..3d54f9f95d46 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/string.h> | 7 | #include <linux/string.h> |
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/bootmem.h> | 9 | #include <linux/bootmem.h> |
10 | #include <linux/memblock.h> | ||
10 | #include <linux/mmzone.h> | 11 | #include <linux/mmzone.h> |
11 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
@@ -171,8 +172,8 @@ static void * __init early_node_mem(int nodeid, unsigned long start, | |||
171 | if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) && | 172 | if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) && |
172 | end > (MAX_DMA32_PFN<<PAGE_SHIFT)) | 173 | end > (MAX_DMA32_PFN<<PAGE_SHIFT)) |
173 | start = MAX_DMA32_PFN<<PAGE_SHIFT; | 174 | start = MAX_DMA32_PFN<<PAGE_SHIFT; |
174 | mem = find_e820_area(start, end, size, align); | 175 | mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align); |
175 | if (mem != -1L) | 176 | if (mem != MEMBLOCK_ERROR) |
176 | return __va(mem); | 177 | return __va(mem); |
177 | 178 | ||
178 | /* extend the search scope */ | 179 | /* extend the search scope */ |
@@ -181,8 +182,8 @@ static void * __init early_node_mem(int nodeid, unsigned long start, | |||
181 | start = MAX_DMA32_PFN<<PAGE_SHIFT; | 182 | start = MAX_DMA32_PFN<<PAGE_SHIFT; |
182 | else | 183 | else |
183 | start = MAX_DMA_PFN<<PAGE_SHIFT; | 184 | start = MAX_DMA_PFN<<PAGE_SHIFT; |
184 | mem = find_e820_area(start, end, size, align); | 185 | mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align); |
185 | if (mem != -1L) | 186 | if (mem != MEMBLOCK_ERROR) |
186 | return __va(mem); | 187 | return __va(mem); |
187 | 188 | ||
188 | printk(KERN_ERR "Cannot find %lu bytes in node %d\n", | 189 | printk(KERN_ERR "Cannot find %lu bytes in node %d\n", |
diff --git a/mm/bootmem.c b/mm/bootmem.c index bde170dd2fde..fda01a2c31af 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/kmemleak.h> | 16 | #include <linux/kmemleak.h> |
17 | #include <linux/range.h> | 17 | #include <linux/range.h> |
18 | #include <linux/memblock.h> | ||
18 | 19 | ||
19 | #include <asm/bug.h> | 20 | #include <asm/bug.h> |
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
@@ -434,6 +435,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, | |||
434 | unsigned long size) | 435 | unsigned long size) |
435 | { | 436 | { |
436 | #ifdef CONFIG_NO_BOOTMEM | 437 | #ifdef CONFIG_NO_BOOTMEM |
438 | kmemleak_free_part(__va(physaddr), size); | ||
437 | free_early(physaddr, physaddr + size); | 439 | free_early(physaddr, physaddr + size); |
438 | #else | 440 | #else |
439 | unsigned long start, end; | 441 | unsigned long start, end; |
@@ -459,6 +461,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, | |||
459 | void __init free_bootmem(unsigned long addr, unsigned long size) | 461 | void __init free_bootmem(unsigned long addr, unsigned long size) |
460 | { | 462 | { |
461 | #ifdef CONFIG_NO_BOOTMEM | 463 | #ifdef CONFIG_NO_BOOTMEM |
464 | kmemleak_free_part(__va(addr), size); | ||
462 | free_early(addr, addr + size); | 465 | free_early(addr, addr + size); |
463 | #else | 466 | #else |
464 | unsigned long start, end; | 467 | unsigned long start, end; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8c9b34674d83..f2cd7450fa76 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -3667,46 +3667,26 @@ int __init add_from_early_node_map(struct range *range, int az, | |||
3667 | void * __init __alloc_memory_core_early(int nid, u64 size, u64 align, | 3667 | void * __init __alloc_memory_core_early(int nid, u64 size, u64 align, |
3668 | u64 goal, u64 limit) | 3668 | u64 goal, u64 limit) |
3669 | { | 3669 | { |
3670 | int i; | ||
3671 | void *ptr; | 3670 | void *ptr; |
3671 | u64 addr; | ||
3672 | 3672 | ||
3673 | if (limit > get_max_mapped()) | 3673 | if (limit > memblock.current_limit) |
3674 | limit = get_max_mapped(); | 3674 | limit = memblock.current_limit; |
3675 | 3675 | ||
3676 | /* need to go over early_node_map to find out good range for node */ | 3676 | addr = find_memory_core_early(nid, size, align, goal, limit); |
3677 | for_each_active_range_index_in_nid(i, nid) { | ||
3678 | u64 addr; | ||
3679 | u64 ei_start, ei_last; | ||
3680 | 3677 | ||
3681 | ei_last = early_node_map[i].end_pfn; | 3678 | if (addr == MEMBLOCK_ERROR) |
3682 | ei_last <<= PAGE_SHIFT; | 3679 | return NULL; |
3683 | ei_start = early_node_map[i].start_pfn; | ||
3684 | ei_start <<= PAGE_SHIFT; | ||
3685 | addr = find_early_area(ei_start, ei_last, | ||
3686 | goal, limit, size, align); | ||
3687 | |||
3688 | if (addr == -1ULL) | ||
3689 | continue; | ||
3690 | |||
3691 | #if 0 | ||
3692 | printk(KERN_DEBUG "alloc (nid=%d %llx - %llx) (%llx - %llx) %llx %llx => %llx\n", | ||
3693 | nid, | ||
3694 | ei_start, ei_last, goal, limit, size, | ||
3695 | align, addr); | ||
3696 | #endif | ||
3697 | |||
3698 | ptr = phys_to_virt(addr); | ||
3699 | memset(ptr, 0, size); | ||
3700 | reserve_early_without_check(addr, addr + size, "BOOTMEM"); | ||
3701 | /* | ||
3702 | * The min_count is set to 0 so that bootmem allocated blocks | ||
3703 | * are never reported as leaks. | ||
3704 | */ | ||
3705 | kmemleak_alloc(ptr, size, 0, 0); | ||
3706 | return ptr; | ||
3707 | } | ||
3708 | 3680 | ||
3709 | return NULL; | 3681 | ptr = phys_to_virt(addr); |
3682 | memset(ptr, 0, size); | ||
3683 | memblock_x86_reserve_range(addr, addr + size, "BOOTMEM"); | ||
3684 | /* | ||
3685 | * The min_count is set to 0 so that bootmem allocated blocks | ||
3686 | * are never reported as leaks. | ||
3687 | */ | ||
3688 | kmemleak_alloc(ptr, size, 0, 0); | ||
3689 | return ptr; | ||
3710 | } | 3690 | } |
3711 | #endif | 3691 | #endif |
3712 | 3692 | ||
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index aa33fd67fa41..29d6cbffb283 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c | |||
@@ -220,18 +220,7 @@ void __init sparse_mem_maps_populate_node(struct page **map_map, | |||
220 | 220 | ||
221 | if (vmemmap_buf_start) { | 221 | if (vmemmap_buf_start) { |
222 | /* need to free left buf */ | 222 | /* need to free left buf */ |
223 | #ifdef CONFIG_NO_BOOTMEM | ||
224 | free_early(__pa(vmemmap_buf_start), __pa(vmemmap_buf_end)); | ||
225 | if (vmemmap_buf_start < vmemmap_buf) { | ||
226 | char name[15]; | ||
227 | |||
228 | snprintf(name, sizeof(name), "MEMMAP %d", nodeid); | ||
229 | reserve_early_without_check(__pa(vmemmap_buf_start), | ||
230 | __pa(vmemmap_buf), name); | ||
231 | } | ||
232 | #else | ||
233 | free_bootmem(__pa(vmemmap_buf), vmemmap_buf_end - vmemmap_buf); | 223 | free_bootmem(__pa(vmemmap_buf), vmemmap_buf_end - vmemmap_buf); |
234 | #endif | ||
235 | vmemmap_buf = NULL; | 224 | vmemmap_buf = NULL; |
236 | vmemmap_buf_end = NULL; | 225 | vmemmap_buf_end = NULL; |
237 | } | 226 | } |