Skip to content

Commit 26f9d5f

Browse files
committed
ARC: support HIGHMEM even without PAE40
Initial HIGHMEM support on ARC was introduced for PAE40 where the low memory (0x8000_0000 based) and high memory (0x1_0000_0000) were physically contiguous. So CONFIG_FLATMEM sufficed (despite a peipheral hole in the middle, which wasted a bit of struct page memory, but things worked). However w/o PAE, highmem was not possible and we could only reach ~1.75GB of DDR. Now there is a use case to access ~4GB of DDR w/o PAE40 The idea is to have low memory at canonical 0x8000_0000 and highmem at 0 so enire 4GB address space is available for physical addressing This needs additional platform/interconnect mapping to convert the non contiguous physical addresses into linear bus adresses. From Linux point of view, non contiguous divide means FLATMEM no longer works and DISCONTIGMEM is needed to track the pfns in the 2 regions. This scheme would also work for PAE40, only better in that we don't waste struct page memory for the peripheral hole. The DT description will be something like memory { ... reg = <0x80000000 0x200000000 /* 512MB: lowmem */ 0x00000000 0x10000000>; /* 256MB: highmem */ } Signed-off-by: Noam Camus <noamc@ezchip.com> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
1 parent 2519d75 commit 26f9d5f

File tree

4 files changed

+98
-18
lines changed

4 files changed

+98
-18
lines changed

arch/arc/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ config GENERIC_CSUM
5858
config RWSEM_GENERIC_SPINLOCK
5959
def_bool y
6060

61+
config ARCH_DISCONTIGMEM_ENABLE
62+
def_bool y
63+
6164
config ARCH_FLATMEM_ENABLE
6265
def_bool y
6366

@@ -347,6 +350,15 @@ config ARC_HUGEPAGE_16M
347350

348351
endchoice
349352

353+
config NODES_SHIFT
354+
int "Maximum NUMA Nodes (as a power of 2)"
355+
default "1" if !DISCONTIGMEM
356+
default "2" if DISCONTIGMEM
357+
depends on NEED_MULTIPLE_NODES
358+
---help---
359+
Accessing memory beyond 1GB (with or w/o PAE) requires 2 memory
360+
zones.
361+
350362
if ISA_ARCOMPACT
351363

352364
config ARC_COMPACT_IRQ_LEVELS
@@ -455,6 +467,7 @@ config LINUX_LINK_BASE
455467

456468
config HIGHMEM
457469
bool "High Memory Support"
470+
select DISCONTIGMEM
458471
help
459472
With ARC 2G:2G address split, only upper 2G is directly addressable by
460473
kernel. Enable this to potentially allow access to rest of 2G and PAE

arch/arc/include/asm/mmzone.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation.
7+
*/
8+
9+
#ifndef _ASM_ARC_MMZONE_H
10+
#define _ASM_ARC_MMZONE_H
11+
12+
#ifdef CONFIG_DISCONTIGMEM
13+
14+
extern struct pglist_data node_data[];
15+
#define NODE_DATA(nid) (&node_data[nid])
16+
17+
static inline int pfn_to_nid(unsigned long pfn)
18+
{
19+
int is_end_low = 1;
20+
21+
if (IS_ENABLED(CONFIG_ARC_HAS_PAE40))
22+
is_end_low = pfn <= virt_to_pfn(0xFFFFFFFFUL);
23+
24+
/*
25+
* node 0: lowmem: 0x8000_0000 to 0xFFFF_FFFF
26+
* node 1: HIGHMEM w/o PAE40: 0x0 to 0x7FFF_FFFF
27+
* HIGHMEM with PAE40: 0x1_0000_0000 to ...
28+
*/
29+
if (pfn >= ARCH_PFN_OFFSET && is_end_low)
30+
return 0;
31+
32+
return 1;
33+
}
34+
35+
static inline int pfn_valid(unsigned long pfn)
36+
{
37+
int nid = pfn_to_nid(pfn);
38+
39+
return (pfn <= node_end_pfn(nid));
40+
}
41+
#endif /* CONFIG_DISCONTIGMEM */
42+
43+
#endif

arch/arc/include/asm/page.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ typedef pte_t * pgtable_t;
8383

8484
#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_LINK_BASE)
8585

86+
#ifdef CONFIG_FLATMEM
8687
#define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
88+
#endif
8789

8890
/*
8991
* __pa, __va, virt_to_page (ALERT: deprecated, don't use them)
@@ -95,9 +97,7 @@ typedef pte_t * pgtable_t;
9597
#define __pa(vaddr) ((unsigned long)(vaddr))
9698
#define __va(paddr) ((void *)((unsigned long)(paddr)))
9799

98-
#define virt_to_page(kaddr) \
99-
(mem_map + virt_to_pfn((kaddr) - CONFIG_LINUX_LINK_BASE))
100-
100+
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
101101
#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
102102

103103
/* Default Permissions for stack/heaps pages (Non Executable) */

arch/arc/mm/init.c

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,16 @@ static const unsigned long low_mem_start = CONFIG_LINUX_LINK_BASE;
3030
static unsigned long low_mem_sz;
3131

3232
#ifdef CONFIG_HIGHMEM
33-
static unsigned long min_high_pfn;
33+
static unsigned long min_high_pfn, max_high_pfn;
3434
static u64 high_mem_start;
3535
static u64 high_mem_sz;
3636
#endif
3737

38+
#ifdef CONFIG_DISCONTIGMEM
39+
struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
40+
EXPORT_SYMBOL(node_data);
41+
#endif
42+
3843
/* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
3944
static int __init setup_mem_sz(char *str)
4045
{
@@ -109,13 +114,11 @@ void __init setup_arch_memory(void)
109114
/* Last usable page of low mem */
110115
max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz);
111116

112-
#ifdef CONFIG_HIGHMEM
113-
min_high_pfn = PFN_DOWN(high_mem_start);
114-
max_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
117+
#ifdef CONFIG_FLATMEM
118+
/* pfn_valid() uses this */
119+
max_mapnr = max_low_pfn - min_low_pfn;
115120
#endif
116121

117-
max_mapnr = max_pfn - min_low_pfn;
118-
119122
/*------------- bootmem allocator setup -----------------------*/
120123

121124
/*
@@ -129,7 +132,7 @@ void __init setup_arch_memory(void)
129132
* the crash
130133
*/
131134

132-
memblock_add(low_mem_start, low_mem_sz);
135+
memblock_add_node(low_mem_start, low_mem_sz, 0);
133136
memblock_reserve(low_mem_start, __pa(_end) - low_mem_start);
134137

135138
#ifdef CONFIG_BLK_DEV_INITRD
@@ -149,13 +152,6 @@ void __init setup_arch_memory(void)
149152
zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
150153
zones_holes[ZONE_NORMAL] = 0;
151154

152-
#ifdef CONFIG_HIGHMEM
153-
zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
154-
155-
/* This handles the peripheral address space hole */
156-
zones_holes[ZONE_HIGHMEM] = min_high_pfn - max_low_pfn;
157-
#endif
158-
159155
/*
160156
* We can't use the helper free_area_init(zones[]) because it uses
161157
* PAGE_OFFSET to compute the @min_low_pfn which would be wrong
@@ -168,6 +164,34 @@ void __init setup_arch_memory(void)
168164
zones_holes); /* holes */
169165

170166
#ifdef CONFIG_HIGHMEM
167+
/*
168+
* Populate a new node with highmem
169+
*
170+
* On ARC (w/o PAE) HIGHMEM addresses are actually smaller (0 based)
171+
* than addresses in normal ala low memory (0x8000_0000 based).
172+
* Even with PAE, the huge peripheral space hole would waste a lot of
173+
* mem with single mem_map[]. This warrants a mem_map per region design.
174+
* Thus HIGHMEM on ARC is imlemented with DISCONTIGMEM.
175+
*
176+
* DISCONTIGMEM in turns requires multiple nodes. node 0 above is
177+
* populated with normal memory zone while node 1 only has highmem
178+
*/
179+
node_set_online(1);
180+
181+
min_high_pfn = PFN_DOWN(high_mem_start);
182+
max_high_pfn = PFN_DOWN(high_mem_start + high_mem_sz);
183+
184+
zones_size[ZONE_NORMAL] = 0;
185+
zones_holes[ZONE_NORMAL] = 0;
186+
187+
zones_size[ZONE_HIGHMEM] = max_high_pfn - min_high_pfn;
188+
zones_holes[ZONE_HIGHMEM] = 0;
189+
190+
free_area_init_node(1, /* node-id */
191+
zones_size, /* num pages per zone */
192+
min_high_pfn, /* first pfn of node */
193+
zones_holes); /* holes */
194+
171195
high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
172196
kmap_init();
173197
#endif
@@ -185,7 +209,7 @@ void __init mem_init(void)
185209
unsigned long tmp;
186210

187211
reset_all_zones_managed_pages();
188-
for (tmp = min_high_pfn; tmp < max_pfn; tmp++)
212+
for (tmp = min_high_pfn; tmp < max_high_pfn; tmp++)
189213
free_highmem_page(pfn_to_page(tmp));
190214
#endif
191215

0 commit comments

Comments
 (0)