Skip to content

Commit dd28769

Browse files
committed
Merge tag 'arc-4.6-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
Pull ARC fixes from Vineet Gupta: "Late in the cycle, but this has fixes for couple of issues: a PAE40 boot crash and Arnd spotting lack of barriers in BE io-accessors. The 3rd patch for enabling highmem in low physical mem ;-) honestly is more than a "fix" but its been in works for some time, seems to be stable in testing and enables 2 of our customers to go forward with 4.6 kernel. - Fix for PTE truncation in PAE40 builds - Fix for big endian IO accessors lacking IO barrier - Allow HIGHMEM to work with low physical addresses" * tag 'arc-4.6-rc7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc: ARC: support HIGHMEM even without PAE40 ARC: Fix PAE40 boot failures due to PTE truncation ARC: Add missing io barriers to io{read,write}{16,32}be()
2 parents 4883d11 + 26f9d5f commit dd28769

File tree

6 files changed

+130
-35
lines changed

6 files changed

+130
-35
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/io.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
#include <asm/byteorder.h>
1414
#include <asm/page.h>
1515

16+
#ifdef CONFIG_ISA_ARCV2
17+
#include <asm/barrier.h>
18+
#define __iormb() rmb()
19+
#define __iowmb() wmb()
20+
#else
21+
#define __iormb() do { } while (0)
22+
#define __iowmb() do { } while (0)
23+
#endif
24+
1625
extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size);
1726
extern void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
1827
unsigned long flags);
@@ -31,6 +40,15 @@ extern void iounmap(const void __iomem *addr);
3140
#define ioremap_wc(phy, sz) ioremap(phy, sz)
3241
#define ioremap_wt(phy, sz) ioremap(phy, sz)
3342

43+
/*
44+
* io{read,write}{16,32}be() macros
45+
*/
46+
#define ioread16be(p) ({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
47+
#define ioread32be(p) ({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
48+
49+
#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); })
50+
#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); })
51+
3452
/* Change struct page to physical address */
3553
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
3654

@@ -108,15 +126,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
108126

109127
}
110128

111-
#ifdef CONFIG_ISA_ARCV2
112-
#include <asm/barrier.h>
113-
#define __iormb() rmb()
114-
#define __iowmb() wmb()
115-
#else
116-
#define __iormb() do { } while (0)
117-
#define __iowmb() do { } while (0)
118-
#endif
119-
120129
/*
121130
* MMIO can also get buffered/optimized in micro-arch, so barriers needed
122131
* Based on ARM model for the typical use case

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: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,20 @@ typedef unsigned long pgprot_t;
7272

7373
typedef pte_t * pgtable_t;
7474

75+
/*
76+
* Use virt_to_pfn with caution:
77+
* If used in pte or paddr related macros, it could cause truncation
78+
* in PAE40 builds
79+
* As a rule of thumb, only use it in helpers starting with virt_
80+
* You have been warned !
81+
*/
7582
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
7683

7784
#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_LINK_BASE)
7885

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

8190
/*
8291
* __pa, __va, virt_to_page (ALERT: deprecated, don't use them)
@@ -85,12 +94,10 @@ typedef pte_t * pgtable_t;
8594
* virt here means link-address/program-address as embedded in object code.
8695
* And for ARC, link-addr = physical address
8796
*/
88-
#define __pa(vaddr) ((unsigned long)vaddr)
97+
#define __pa(vaddr) ((unsigned long)(vaddr))
8998
#define __va(paddr) ((void *)((unsigned long)(paddr)))
9099

91-
#define virt_to_page(kaddr) \
92-
(mem_map + virt_to_pfn((kaddr) - CONFIG_LINUX_LINK_BASE))
93-
100+
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
94101
#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
95102

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

arch/arc/include/asm/pgtable.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,14 +278,13 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
278278
#define pmd_present(x) (pmd_val(x))
279279
#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0)
280280

281-
#define pte_page(pte) \
282-
(mem_map + virt_to_pfn(pte_val(pte) - CONFIG_LINUX_LINK_BASE))
283-
281+
#define pte_page(pte) pfn_to_page(pte_pfn(pte))
284282
#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
285-
#define pte_pfn(pte) virt_to_pfn(pte_val(pte))
286-
#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | \
287-
pgprot_val(prot)))
288-
#define __pte_index(addr) (virt_to_pfn(addr) & (PTRS_PER_PTE - 1))
283+
#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
284+
285+
/* Don't use virt_to_pfn for macros below: could cause truncations for PAE40*/
286+
#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
287+
#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
289288

290289
/*
291290
* pte_offset gets a @ptr to PMD entry (PGD in our 2-tier paging system)

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)