summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2019-04-09 15:52:35 -0400
committerHelge Deller <deller@gmx.de>2019-05-03 17:47:40 -0400
commitdbdf0760990583649bfaca75fd98f76afd5f3905 (patch)
tree7caa3387834d951c5c55aad14b1dfd78cd262257
parent6b1370ae392b79ac3e2d053205f4107d4a55c102 (diff)
parisc: Switch from DISCONTIGMEM to SPARSEMEM
The commit 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs") breaks memory management on a parisc c8000 workstation with this memory layout: 0) Start 0x0000000000000000 End 0x000000003fffffff Size 1024 MB 1) Start 0x0000000100000000 End 0x00000001bfdfffff Size 3070 MB 2) Start 0x0000004040000000 End 0x00000040ffffffff Size 3072 MB With the patch 1c30844d2dfe, the kernel will incorrectly reclaim the first zone when it fills up, ignoring the fact that there are two completely free zones. Basiscally, it limits cache size to 1GiB. The parisc kernel is currently using the DISCONTIGMEM implementation, but isn't NUMA. Avoid this issue or strange work-arounds by switching to the more commonly used SPARSEMEM implementation. Reported-by: Mikulas Patocka <mpatocka@redhat.com> Fixes: 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs") Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--arch/parisc/Kconfig12
-rw-r--r--arch/parisc/include/asm/mmzone.h58
-rw-r--r--arch/parisc/include/asm/page.h4
-rw-r--r--arch/parisc/include/asm/sparsemem.h14
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c6
-rw-r--r--arch/parisc/mm/init.c102
6 files changed, 68 insertions, 128 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index c8038165b81f..26c215570adf 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -36,6 +36,7 @@ config PARISC
36 select GENERIC_STRNCPY_FROM_USER 36 select GENERIC_STRNCPY_FROM_USER
37 select SYSCTL_ARCH_UNALIGN_ALLOW 37 select SYSCTL_ARCH_UNALIGN_ALLOW
38 select SYSCTL_EXCEPTION_TRACE 38 select SYSCTL_EXCEPTION_TRACE
39 select ARCH_DISCARD_MEMBLOCK
39 select HAVE_MOD_ARCH_SPECIFIC 40 select HAVE_MOD_ARCH_SPECIFIC
40 select VIRT_TO_BUS 41 select VIRT_TO_BUS
41 select MODULES_USE_ELF_RELA 42 select MODULES_USE_ELF_RELA
@@ -314,21 +315,16 @@ config ARCH_SELECT_MEMORY_MODEL
314 def_bool y 315 def_bool y
315 depends on 64BIT 316 depends on 64BIT
316 317
317config ARCH_DISCONTIGMEM_ENABLE 318config ARCH_SPARSEMEM_ENABLE
318 def_bool y 319 def_bool y
319 depends on 64BIT 320 depends on 64BIT
320 321
321config ARCH_FLATMEM_ENABLE 322config ARCH_FLATMEM_ENABLE
322 def_bool y 323 def_bool y
323 324
324config ARCH_DISCONTIGMEM_DEFAULT 325config ARCH_SPARSEMEM_DEFAULT
325 def_bool y 326 def_bool y
326 depends on ARCH_DISCONTIGMEM_ENABLE 327 depends on ARCH_SPARSEMEM_ENABLE
327
328config NODES_SHIFT
329 int
330 default "3"
331 depends on NEED_MULTIPLE_NODES
332 328
333source "kernel/Kconfig.hz" 329source "kernel/Kconfig.hz"
334 330
diff --git a/arch/parisc/include/asm/mmzone.h b/arch/parisc/include/asm/mmzone.h
index fafa3893fd70..8d390406d862 100644
--- a/arch/parisc/include/asm/mmzone.h
+++ b/arch/parisc/include/asm/mmzone.h
@@ -2,62 +2,6 @@
2#ifndef _PARISC_MMZONE_H 2#ifndef _PARISC_MMZONE_H
3#define _PARISC_MMZONE_H 3#define _PARISC_MMZONE_H
4 4
5#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */ 5#define MAX_PHYSMEM_RANGES 4 /* Fix the size for now (current known max is 3) */
6 6
7#ifdef CONFIG_DISCONTIGMEM
8
9extern int npmem_ranges;
10
11struct node_map_data {
12 pg_data_t pg_data;
13};
14
15extern struct node_map_data node_data[];
16
17#define NODE_DATA(nid) (&node_data[nid].pg_data)
18
19/* We have these possible memory map layouts:
20 * Astro: 0-3.75, 67.75-68, 4-64
21 * zx1: 0-1, 257-260, 4-256
22 * Stretch (N-class): 0-2, 4-32, 34-xxx
23 */
24
25/* Since each 1GB can only belong to one region (node), we can create
26 * an index table for pfn to nid lookup; each entry in pfnnid_map
27 * represents 1GB, and contains the node that the memory belongs to. */
28
29#define PFNNID_SHIFT (30 - PAGE_SHIFT)
30#define PFNNID_MAP_MAX 512 /* support 512GB */
31extern signed char pfnnid_map[PFNNID_MAP_MAX];
32
33#ifndef CONFIG_64BIT
34#define pfn_is_io(pfn) ((pfn & (0xf0000000UL >> PAGE_SHIFT)) == (0xf0000000UL >> PAGE_SHIFT))
35#else
36/* io can be 0xf0f0f0f0f0xxxxxx or 0xfffffffff0000000 */
37#define pfn_is_io(pfn) ((pfn & (0xf000000000000000UL >> PAGE_SHIFT)) == (0xf000000000000000UL >> PAGE_SHIFT))
38#endif
39
40static inline int pfn_to_nid(unsigned long pfn)
41{
42 unsigned int i;
43
44 if (unlikely(pfn_is_io(pfn)))
45 return 0;
46
47 i = pfn >> PFNNID_SHIFT;
48 BUG_ON(i >= ARRAY_SIZE(pfnnid_map));
49
50 return pfnnid_map[i];
51}
52
53static inline int pfn_valid(int pfn)
54{
55 int nid = pfn_to_nid(pfn);
56
57 if (nid >= 0)
58 return (pfn < node_end_pfn(nid));
59 return 0;
60}
61
62#endif
63#endif /* _PARISC_MMZONE_H */ 7#endif /* _PARISC_MMZONE_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index b77f49ce6220..93caf17ac5e2 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -147,9 +147,9 @@ extern int npmem_ranges;
147#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) 147#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
148#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) 148#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
149 149
150#ifndef CONFIG_DISCONTIGMEM 150#ifndef CONFIG_SPARSEMEM
151#define pfn_valid(pfn) ((pfn) < max_mapnr) 151#define pfn_valid(pfn) ((pfn) < max_mapnr)
152#endif /* CONFIG_DISCONTIGMEM */ 152#endif
153 153
154#ifdef CONFIG_HUGETLB_PAGE 154#ifdef CONFIG_HUGETLB_PAGE
155#define HPAGE_SHIFT PMD_SHIFT /* fixed for transparent huge pages */ 155#define HPAGE_SHIFT PMD_SHIFT /* fixed for transparent huge pages */
diff --git a/arch/parisc/include/asm/sparsemem.h b/arch/parisc/include/asm/sparsemem.h
new file mode 100644
index 000000000000..b5c3a79045b4
--- /dev/null
+++ b/arch/parisc/include/asm/sparsemem.h
@@ -0,0 +1,14 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef ASM_PARISC_SPARSEMEM_H
3#define ASM_PARISC_SPARSEMEM_H
4
5/* We have these possible memory map layouts:
6 * Astro: 0-3.75, 67.75-68, 4-64
7 * zx1: 0-1, 257-260, 4-256
8 * Stretch (N-class): 0-2, 4-32, 34-xxx
9 */
10
11#define MAX_PHYSMEM_BITS 39 /* 512 GB */
12#define SECTION_SIZE_BITS 27 /* 128 MB */
13
14#endif
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 7baa2265d439..174213b1716e 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -138,12 +138,6 @@ extern void $$dyncall(void);
138EXPORT_SYMBOL($$dyncall); 138EXPORT_SYMBOL($$dyncall);
139#endif 139#endif
140 140
141#ifdef CONFIG_DISCONTIGMEM
142#include <asm/mmzone.h>
143EXPORT_SYMBOL(node_data);
144EXPORT_SYMBOL(pfnnid_map);
145#endif
146
147#ifdef CONFIG_FUNCTION_TRACER 141#ifdef CONFIG_FUNCTION_TRACER
148extern void _mcount(void); 142extern void _mcount(void);
149EXPORT_SYMBOL(_mcount); 143EXPORT_SYMBOL(_mcount);
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index b2b52de2b82b..513f747b0d9d 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -32,6 +32,7 @@
32#include <asm/mmzone.h> 32#include <asm/mmzone.h>
33#include <asm/sections.h> 33#include <asm/sections.h>
34#include <asm/msgbuf.h> 34#include <asm/msgbuf.h>
35#include <asm/sparsemem.h>
35 36
36extern int data_start; 37extern int data_start;
37extern void parisc_kernel_start(void); /* Kernel entry point in head.S */ 38extern void parisc_kernel_start(void); /* Kernel entry point in head.S */
@@ -48,11 +49,6 @@ pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data..vm0.pmd"), aligned
48pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data..vm0.pgd"), aligned(PAGE_SIZE))); 49pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data..vm0.pgd"), aligned(PAGE_SIZE)));
49pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data..vm0.pte"), aligned(PAGE_SIZE))); 50pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data..vm0.pte"), aligned(PAGE_SIZE)));
50 51
51#ifdef CONFIG_DISCONTIGMEM
52struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
53signed char pfnnid_map[PFNNID_MAP_MAX] __read_mostly;
54#endif
55
56static struct resource data_resource = { 52static struct resource data_resource = {
57 .name = "Kernel data", 53 .name = "Kernel data",
58 .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM, 54 .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
@@ -76,11 +72,11 @@ static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __read_mostly;
76 * information retrieved in kernel/inventory.c. 72 * information retrieved in kernel/inventory.c.
77 */ 73 */
78 74
79physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __read_mostly; 75physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __initdata;
80int npmem_ranges __read_mostly; 76int npmem_ranges __initdata;
81 77
82#ifdef CONFIG_64BIT 78#ifdef CONFIG_64BIT
83#define MAX_MEM (~0UL) 79#define MAX_MEM (1UL << MAX_PHYSMEM_BITS)
84#else /* !CONFIG_64BIT */ 80#else /* !CONFIG_64BIT */
85#define MAX_MEM (3584U*1024U*1024U) 81#define MAX_MEM (3584U*1024U*1024U)
86#endif /* !CONFIG_64BIT */ 82#endif /* !CONFIG_64BIT */
@@ -119,7 +115,7 @@ static void __init mem_limit_func(void)
119static void __init setup_bootmem(void) 115static void __init setup_bootmem(void)
120{ 116{
121 unsigned long mem_max; 117 unsigned long mem_max;
122#ifndef CONFIG_DISCONTIGMEM 118#ifndef CONFIG_SPARSEMEM
123 physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1]; 119 physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
124 int npmem_holes; 120 int npmem_holes;
125#endif 121#endif
@@ -137,23 +133,20 @@ static void __init setup_bootmem(void)
137 int j; 133 int j;
138 134
139 for (j = i; j > 0; j--) { 135 for (j = i; j > 0; j--) {
140 unsigned long tmp; 136 physmem_range_t tmp;
141 137
142 if (pmem_ranges[j-1].start_pfn < 138 if (pmem_ranges[j-1].start_pfn <
143 pmem_ranges[j].start_pfn) { 139 pmem_ranges[j].start_pfn) {
144 140
145 break; 141 break;
146 } 142 }
147 tmp = pmem_ranges[j-1].start_pfn; 143 tmp = pmem_ranges[j-1];
148 pmem_ranges[j-1].start_pfn = pmem_ranges[j].start_pfn; 144 pmem_ranges[j-1] = pmem_ranges[j];
149 pmem_ranges[j].start_pfn = tmp; 145 pmem_ranges[j] = tmp;
150 tmp = pmem_ranges[j-1].pages;
151 pmem_ranges[j-1].pages = pmem_ranges[j].pages;
152 pmem_ranges[j].pages = tmp;
153 } 146 }
154 } 147 }
155 148
156#ifndef CONFIG_DISCONTIGMEM 149#ifndef CONFIG_SPARSEMEM
157 /* 150 /*
158 * Throw out ranges that are too far apart (controlled by 151 * Throw out ranges that are too far apart (controlled by
159 * MAX_GAP). 152 * MAX_GAP).
@@ -165,7 +158,7 @@ static void __init setup_bootmem(void)
165 pmem_ranges[i-1].pages) > MAX_GAP) { 158 pmem_ranges[i-1].pages) > MAX_GAP) {
166 npmem_ranges = i; 159 npmem_ranges = i;
167 printk("Large gap in memory detected (%ld pages). " 160 printk("Large gap in memory detected (%ld pages). "
168 "Consider turning on CONFIG_DISCONTIGMEM\n", 161 "Consider turning on CONFIG_SPARSEMEM\n",
169 pmem_ranges[i].start_pfn - 162 pmem_ranges[i].start_pfn -
170 (pmem_ranges[i-1].start_pfn + 163 (pmem_ranges[i-1].start_pfn +
171 pmem_ranges[i-1].pages)); 164 pmem_ranges[i-1].pages));
@@ -230,9 +223,8 @@ static void __init setup_bootmem(void)
230 223
231 printk(KERN_INFO "Total Memory: %ld MB\n",mem_max >> 20); 224 printk(KERN_INFO "Total Memory: %ld MB\n",mem_max >> 20);
232 225
233#ifndef CONFIG_DISCONTIGMEM 226#ifndef CONFIG_SPARSEMEM
234 /* Merge the ranges, keeping track of the holes */ 227 /* Merge the ranges, keeping track of the holes */
235
236 { 228 {
237 unsigned long end_pfn; 229 unsigned long end_pfn;
238 unsigned long hole_pages; 230 unsigned long hole_pages;
@@ -255,18 +247,6 @@ static void __init setup_bootmem(void)
255 } 247 }
256#endif 248#endif
257 249
258#ifdef CONFIG_DISCONTIGMEM
259 for (i = 0; i < MAX_PHYSMEM_RANGES; i++) {
260 memset(NODE_DATA(i), 0, sizeof(pg_data_t));
261 }
262 memset(pfnnid_map, 0xff, sizeof(pfnnid_map));
263
264 for (i = 0; i < npmem_ranges; i++) {
265 node_set_state(i, N_NORMAL_MEMORY);
266 node_set_online(i);
267 }
268#endif
269
270 /* 250 /*
271 * Initialize and free the full range of memory in each range. 251 * Initialize and free the full range of memory in each range.
272 */ 252 */
@@ -314,7 +294,7 @@ static void __init setup_bootmem(void)
314 memblock_reserve(__pa(KERNEL_BINARY_TEXT_START), 294 memblock_reserve(__pa(KERNEL_BINARY_TEXT_START),
315 (unsigned long)(_end - KERNEL_BINARY_TEXT_START)); 295 (unsigned long)(_end - KERNEL_BINARY_TEXT_START));
316 296
317#ifndef CONFIG_DISCONTIGMEM 297#ifndef CONFIG_SPARSEMEM
318 298
319 /* reserve the holes */ 299 /* reserve the holes */
320 300
@@ -360,6 +340,9 @@ static void __init setup_bootmem(void)
360 340
361 /* Initialize Page Deallocation Table (PDT) and check for bad memory. */ 341 /* Initialize Page Deallocation Table (PDT) and check for bad memory. */
362 pdc_pdt_init(); 342 pdc_pdt_init();
343
344 memblock_allow_resize();
345 memblock_dump_all();
363} 346}
364 347
365static int __init parisc_text_address(unsigned long vaddr) 348static int __init parisc_text_address(unsigned long vaddr)
@@ -713,37 +696,46 @@ static void __init gateway_init(void)
713 PAGE_SIZE, PAGE_GATEWAY, 1); 696 PAGE_SIZE, PAGE_GATEWAY, 1);
714} 697}
715 698
716void __init paging_init(void) 699static void __init parisc_bootmem_free(void)
717{ 700{
701 unsigned long zones_size[MAX_NR_ZONES] = { 0, };
702 unsigned long holes_size[MAX_NR_ZONES] = { 0, };
703 unsigned long mem_start_pfn = ~0UL, mem_end_pfn = 0, mem_size_pfn = 0;
718 int i; 704 int i;
719 705
706 for (i = 0; i < npmem_ranges; i++) {
707 unsigned long start = pmem_ranges[i].start_pfn;
708 unsigned long size = pmem_ranges[i].pages;
709 unsigned long end = start + size;
710
711 if (mem_start_pfn > start)
712 mem_start_pfn = start;
713 if (mem_end_pfn < end)
714 mem_end_pfn = end;
715 mem_size_pfn += size;
716 }
717
718 zones_size[0] = mem_end_pfn - mem_start_pfn;
719 holes_size[0] = zones_size[0] - mem_size_pfn;
720
721 free_area_init_node(0, zones_size, mem_start_pfn, holes_size);
722}
723
724void __init paging_init(void)
725{
720 setup_bootmem(); 726 setup_bootmem();
721 pagetable_init(); 727 pagetable_init();
722 gateway_init(); 728 gateway_init();
723 flush_cache_all_local(); /* start with known state */ 729 flush_cache_all_local(); /* start with known state */
724 flush_tlb_all_local(NULL); 730 flush_tlb_all_local(NULL);
725 731
726 for (i = 0; i < npmem_ranges; i++) { 732 /*
727 unsigned long zones_size[MAX_NR_ZONES] = { 0, }; 733 * Mark all memblocks as present for sparsemem using
728 734 * memory_present() and then initialize sparsemem.
729 zones_size[ZONE_NORMAL] = pmem_ranges[i].pages; 735 */
730 736 memblocks_present();
731#ifdef CONFIG_DISCONTIGMEM 737 sparse_init();
732 /* Need to initialize the pfnnid_map before we can initialize 738 parisc_bootmem_free();
733 the zone */
734 {
735 int j;
736 for (j = (pmem_ranges[i].start_pfn >> PFNNID_SHIFT);
737 j <= ((pmem_ranges[i].start_pfn + pmem_ranges[i].pages) >> PFNNID_SHIFT);
738 j++) {
739 pfnnid_map[j] = i;
740 }
741 }
742#endif
743
744 free_area_init_node(i, zones_size,
745 pmem_ranges[i].start_pfn, NULL);
746 }
747} 739}
748 740
749#ifdef CONFIG_PA20 741#ifdef CONFIG_PA20