Skip to content

Commit 050b2da

Browse files
rppttorvalds
authored andcommitted
arc: use FLATMEM with freeing of unused memory map instead of DISCONTIGMEM
Currently ARC uses DISCONTIGMEM to cope with sparse physical memory address space on systems with 2 memory banks. While DISCONTIGMEM avoids wasting memory on unpopulated memory map, it adds both memory and CPU overhead relatively to FLATMEM. Moreover, DISCONTINGMEM is generally considered deprecated. The obvious replacement for DISCONTIGMEM would be SPARSEMEM, but it is also less efficient than FLATMEM in pfn_to_page() and page_to_pfn() conversions. Besides it requires tuning of SECTION_SIZE which is not trivial for possible ARC memory configuration. Since the memory map for both banks is always allocated from the "lowmem" bank, it is possible to use FLATMEM for two-bank configuration and simply free the unused hole in the memory map. All is required for that is to provide ARC-specific pfn_valid() that will take into account actual physical memory configuration and define HAVE_ARCH_PFN_VALID. The resulting kernel image configured with defconfig + HIGHMEM=y is smaller: $ size a/vmlinux b/vmlinux text data bss dec hex filename 4673503 1245456 279756 6198715 5e95bb a/vmlinux 4658706 1246864 279756 6185326 5e616e b/vmlinux $ ./scripts/bloat-o-meter a/vmlinux b/vmlinux add/remove: 28/30 grow/shrink: 42/399 up/down: 10986/-29025 (-18039) ... Total: Before=4709315, After = 4691276, chg -0.38% Booting nSIM with haps_ns.dts results in the following memory usage reports: a: Memory: 1559104K/1572864K available (3531K kernel code, 595K rwdata, 752K rodata, 136K init, 275K bss, 13760K reserved, 0K cma-reserved, 1048576K highmem) b: Memory: 1559112K/1572864K available (3519K kernel code, 594K rwdata, 752K rodata, 136K init, 280K bss, 13752K reserved, 0K cma-reserved, 1048576K highmem) Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Mike Rapoport <[email protected]> Cc: Alexey Dobriyan <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: Greg Ungerer <[email protected]> Cc: John Paul Adrian Glaubitz <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Matt Turner <[email protected]> Cc: Meelis Roos <[email protected]> Cc: Michael Schmitz <[email protected]> Cc: Russell King <[email protected]> Cc: Tony Luck <[email protected]> Cc: Vineet Gupta <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4f5b0c1 commit 050b2da

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

arch/arc/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ config GENERIC_CSUM
6767

6868
config ARCH_DISCONTIGMEM_ENABLE
6969
def_bool n
70+
depends on BROKEN
7071

7172
config ARCH_FLATMEM_ENABLE
7273
def_bool y
@@ -506,7 +507,7 @@ config LINUX_RAM_BASE
506507

507508
config HIGHMEM
508509
bool "High Memory Support"
509-
select ARCH_DISCONTIGMEM_ENABLE
510+
select HAVE_ARCH_PFN_VALID
510511
help
511512
With ARC 2G:2G address split, only upper 2G is directly addressable by
512513
kernel. Enable this to potentially allow access to rest of 2G and PAE

arch/arc/include/asm/page.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,25 @@ typedef pte_t * pgtable_t;
8282
*/
8383
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
8484

85-
#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_RAM_BASE)
85+
/*
86+
* When HIGHMEM is enabled we have holes in the memory map so we need
87+
* pfn_valid() that takes into account the actual extents of the physical
88+
* memory
89+
*/
90+
#ifdef CONFIG_HIGHMEM
91+
92+
extern unsigned long arch_pfn_offset;
93+
#define ARCH_PFN_OFFSET arch_pfn_offset
94+
95+
extern int pfn_valid(unsigned long pfn);
96+
#define pfn_valid pfn_valid
8697

87-
#ifdef CONFIG_FLATMEM
98+
#else /* CONFIG_HIGHMEM */
99+
100+
#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_RAM_BASE)
88101
#define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
89-
#endif
102+
103+
#endif /* CONFIG_HIGHMEM */
90104

91105
/*
92106
* __pa, __va, virt_to_page (ALERT: deprecated, don't use them)

arch/arc/mm/init.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ static unsigned long low_mem_sz;
2828
static unsigned long min_high_pfn, max_high_pfn;
2929
static phys_addr_t high_mem_start;
3030
static phys_addr_t high_mem_sz;
31+
unsigned long arch_pfn_offset;
32+
EXPORT_SYMBOL(arch_pfn_offset);
3133
#endif
3234

3335
#ifdef CONFIG_DISCONTIGMEM
@@ -98,16 +100,11 @@ void __init setup_arch_memory(void)
98100
init_mm.brk = (unsigned long)_end;
99101

100102
/* first page of system - kernel .vector starts here */
101-
min_low_pfn = ARCH_PFN_OFFSET;
103+
min_low_pfn = virt_to_pfn(CONFIG_LINUX_RAM_BASE);
102104

103105
/* Last usable page of low mem */
104106
max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz);
105107

106-
#ifdef CONFIG_FLATMEM
107-
/* pfn_valid() uses this */
108-
max_mapnr = max_low_pfn - min_low_pfn;
109-
#endif
110-
111108
/*------------- bootmem allocator setup -----------------------*/
112109

113110
/*
@@ -153,16 +150,25 @@ void __init setup_arch_memory(void)
153150
* DISCONTIGMEM in turns requires multiple nodes. node 0 above is
154151
* populated with normal memory zone while node 1 only has highmem
155152
*/
153+
#ifdef CONFIG_DISCONTIGMEM
156154
node_set_online(1);
155+
#endif
157156

158157
min_high_pfn = PFN_DOWN(high_mem_start);
159158
max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
160159

161160
max_zone_pfn[ZONE_HIGHMEM] = min_low_pfn;
162161

163162
high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
163+
164+
arch_pfn_offset = min(min_low_pfn, min_high_pfn);
164165
kmap_init();
165-
#endif
166+
167+
#else /* CONFIG_HIGHMEM */
168+
/* pfn_valid() uses this when FLATMEM=y and HIGHMEM=n */
169+
max_mapnr = max_low_pfn - min_low_pfn;
170+
171+
#endif /* CONFIG_HIGHMEM */
166172

167173
free_area_init(max_zone_pfn);
168174
}
@@ -190,3 +196,12 @@ void __init mem_init(void)
190196
highmem_init();
191197
mem_init_print_info(NULL);
192198
}
199+
200+
#ifdef CONFIG_HIGHMEM
201+
int pfn_valid(unsigned long pfn)
202+
{
203+
return (pfn >= min_high_pfn && pfn <= max_high_pfn) ||
204+
(pfn >= min_low_pfn && pfn <= max_low_pfn);
205+
}
206+
EXPORT_SYMBOL(pfn_valid);
207+
#endif

0 commit comments

Comments
 (0)