aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-06 14:14:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-06 14:14:38 -0400
commitdd287690b0aa4b0d22e8dd7dd2cb3055f5141a27 (patch)
tree58dbeb60b3fc9984220b75d268e4ad043f12bbfe
parent4883d11e06b5a02a73ee3a554168ec92ab44c0f5 (diff)
parent26f9d5fd82ca20fe536cb493ec7cf5628f8997e5 (diff)
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()
-rw-r--r--arch/arc/Kconfig13
-rw-r--r--arch/arc/include/asm/io.h27
-rw-r--r--arch/arc/include/asm/mmzone.h43
-rw-r--r--arch/arc/include/asm/page.h15
-rw-r--r--arch/arc/include/asm/pgtable.h13
-rw-r--r--arch/arc/mm/init.c54
6 files changed, 130 insertions, 35 deletions
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index ec4791ea6911..a8767430df7d 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -58,6 +58,9 @@ config GENERIC_CSUM
58config RWSEM_GENERIC_SPINLOCK 58config RWSEM_GENERIC_SPINLOCK
59 def_bool y 59 def_bool y
60 60
61config ARCH_DISCONTIGMEM_ENABLE
62 def_bool y
63
61config ARCH_FLATMEM_ENABLE 64config ARCH_FLATMEM_ENABLE
62 def_bool y 65 def_bool y
63 66
@@ -347,6 +350,15 @@ config ARC_HUGEPAGE_16M
347 350
348endchoice 351endchoice
349 352
353config 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
350if ISA_ARCOMPACT 362if ISA_ARCOMPACT
351 363
352config ARC_COMPACT_IRQ_LEVELS 364config ARC_COMPACT_IRQ_LEVELS
@@ -455,6 +467,7 @@ config LINUX_LINK_BASE
455 467
456config HIGHMEM 468config HIGHMEM
457 bool "High Memory Support" 469 bool "High Memory Support"
470 select DISCONTIGMEM
458 help 471 help
459 With ARC 2G:2G address split, only upper 2G is directly addressable by 472 With ARC 2G:2G address split, only upper 2G is directly addressable by
460 kernel. Enable this to potentially allow access to rest of 2G and PAE 473 kernel. Enable this to potentially allow access to rest of 2G and PAE
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index 17f85c9c73cf..c22b181e8206 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -13,6 +13,15 @@
13#include <asm/byteorder.h> 13#include <asm/byteorder.h>
14#include <asm/page.h> 14#include <asm/page.h>
15 15
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
16extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size); 25extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size);
17extern void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size, 26extern void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
18 unsigned long flags); 27 unsigned long flags);
@@ -31,6 +40,15 @@ extern void iounmap(const void __iomem *addr);
31#define ioremap_wc(phy, sz) ioremap(phy, sz) 40#define ioremap_wc(phy, sz) ioremap(phy, sz)
32#define ioremap_wt(phy, sz) ioremap(phy, sz) 41#define ioremap_wt(phy, sz) ioremap(phy, sz)
33 42
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
34/* Change struct page to physical address */ 52/* Change struct page to physical address */
35#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) 53#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
36 54
@@ -108,15 +126,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
108 126
109} 127}
110 128
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
120/* 129/*
121 * MMIO can also get buffered/optimized in micro-arch, so barriers needed 130 * MMIO can also get buffered/optimized in micro-arch, so barriers needed
122 * Based on ARM model for the typical use case 131 * Based on ARM model for the typical use case
diff --git a/arch/arc/include/asm/mmzone.h b/arch/arc/include/asm/mmzone.h
new file mode 100644
index 000000000000..8e97136413d9
--- /dev/null
+++ b/arch/arc/include/asm/mmzone.h
@@ -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
14extern struct pglist_data node_data[];
15#define NODE_DATA(nid) (&node_data[nid])
16
17static 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
35static 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
diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
index 36da89e2c853..0d53854884d0 100644
--- a/arch/arc/include/asm/page.h
+++ b/arch/arc/include/asm/page.h
@@ -72,11 +72,20 @@ typedef unsigned long pgprot_t;
72 72
73typedef pte_t * pgtable_t; 73typedef pte_t * pgtable_t;
74 74
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 */
75#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 82#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
76 83
77#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_LINK_BASE) 84#define ARCH_PFN_OFFSET virt_to_pfn(CONFIG_LINUX_LINK_BASE)
78 85
86#ifdef CONFIG_FLATMEM
79#define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr) 87#define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
88#endif
80 89
81/* 90/*
82 * __pa, __va, virt_to_page (ALERT: deprecated, don't use them) 91 * __pa, __va, virt_to_page (ALERT: deprecated, don't use them)
@@ -85,12 +94,10 @@ typedef pte_t * pgtable_t;
85 * virt here means link-address/program-address as embedded in object code. 94 * virt here means link-address/program-address as embedded in object code.
86 * And for ARC, link-addr = physical address 95 * And for ARC, link-addr = physical address
87 */ 96 */
88#define __pa(vaddr) ((unsigned long)vaddr) 97#define __pa(vaddr) ((unsigned long)(vaddr))
89#define __va(paddr) ((void *)((unsigned long)(paddr))) 98#define __va(paddr) ((void *)((unsigned long)(paddr)))
90 99
91#define virt_to_page(kaddr) \ 100#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
92 (mem_map + virt_to_pfn((kaddr) - CONFIG_LINUX_LINK_BASE))
93
94#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) 101#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
95 102
96/* Default Permissions for stack/heaps pages (Non Executable) */ 103/* Default Permissions for stack/heaps pages (Non Executable) */
diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h
index 7d6c93e63adf..10d4b8b8e545 100644
--- a/arch/arc/include/asm/pgtable.h
+++ b/arch/arc/include/asm/pgtable.h
@@ -278,14 +278,13 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
278#define pmd_present(x) (pmd_val(x)) 278#define pmd_present(x) (pmd_val(x))
279#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) 279#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0)
280 280
281#define pte_page(pte) \ 281#define pte_page(pte) pfn_to_page(pte_pfn(pte))
282 (mem_map + virt_to_pfn(pte_val(pte) - CONFIG_LINUX_LINK_BASE))
283
284#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) 282#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
285#define pte_pfn(pte) virt_to_pfn(pte_val(pte)) 283#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
286#define pfn_pte(pfn, prot) (__pte(((pte_t)(pfn) << PAGE_SHIFT) | \ 284
287 pgprot_val(prot))) 285/* Don't use virt_to_pfn for macros below: could cause truncations for PAE40*/
288#define __pte_index(addr) (virt_to_pfn(addr) & (PTRS_PER_PTE - 1)) 286#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
287#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
289 288
290/* 289/*
291 * pte_offset gets a @ptr to PMD entry (PGD in our 2-tier paging system) 290 * pte_offset gets a @ptr to PMD entry (PGD in our 2-tier paging system)
diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c
index 5487d0b97400..8be930394750 100644
--- a/arch/arc/mm/init.c
+++ b/arch/arc/mm/init.c
@@ -30,11 +30,16 @@ static const unsigned long low_mem_start = CONFIG_LINUX_LINK_BASE;
30static unsigned long low_mem_sz; 30static unsigned long low_mem_sz;
31 31
32#ifdef CONFIG_HIGHMEM 32#ifdef CONFIG_HIGHMEM
33static unsigned long min_high_pfn; 33static unsigned long min_high_pfn, max_high_pfn;
34static u64 high_mem_start; 34static u64 high_mem_start;
35static u64 high_mem_sz; 35static u64 high_mem_sz;
36#endif 36#endif
37 37
38#ifdef CONFIG_DISCONTIGMEM
39struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
40EXPORT_SYMBOL(node_data);
41#endif
42
38/* User can over-ride above with "mem=nnn[KkMm]" in cmdline */ 43/* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
39static int __init setup_mem_sz(char *str) 44static int __init setup_mem_sz(char *str)
40{ 45{
@@ -109,13 +114,11 @@ void __init setup_arch_memory(void)
109 /* Last usable page of low mem */ 114 /* Last usable page of low mem */
110 max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz); 115 max_low_pfn = max_pfn = PFN_DOWN(low_mem_start + low_mem_sz);
111 116
112#ifdef CONFIG_HIGHMEM 117#ifdef CONFIG_FLATMEM
113 min_high_pfn = PFN_DOWN(high_mem_start); 118 /* pfn_valid() uses this */
114 max_pfn = PFN_DOWN(high_mem_start + high_mem_sz); 119 max_mapnr = max_low_pfn - min_low_pfn;
115#endif 120#endif
116 121
117 max_mapnr = max_pfn - min_low_pfn;
118
119 /*------------- bootmem allocator setup -----------------------*/ 122 /*------------- bootmem allocator setup -----------------------*/
120 123
121 /* 124 /*
@@ -129,7 +132,7 @@ void __init setup_arch_memory(void)
129 * the crash 132 * the crash
130 */ 133 */
131 134
132 memblock_add(low_mem_start, low_mem_sz); 135 memblock_add_node(low_mem_start, low_mem_sz, 0);
133 memblock_reserve(low_mem_start, __pa(_end) - low_mem_start); 136 memblock_reserve(low_mem_start, __pa(_end) - low_mem_start);
134 137
135#ifdef CONFIG_BLK_DEV_INITRD 138#ifdef CONFIG_BLK_DEV_INITRD
@@ -149,13 +152,6 @@ void __init setup_arch_memory(void)
149 zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; 152 zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
150 zones_holes[ZONE_NORMAL] = 0; 153 zones_holes[ZONE_NORMAL] = 0;
151 154
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
159 /* 155 /*
160 * We can't use the helper free_area_init(zones[]) because it uses 156 * We can't use the helper free_area_init(zones[]) because it uses
161 * PAGE_OFFSET to compute the @min_low_pfn which would be wrong 157 * PAGE_OFFSET to compute the @min_low_pfn which would be wrong
@@ -168,6 +164,34 @@ void __init setup_arch_memory(void)
168 zones_holes); /* holes */ 164 zones_holes); /* holes */
169 165
170#ifdef CONFIG_HIGHMEM 166#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
171 high_memory = (void *)(min_high_pfn << PAGE_SHIFT); 195 high_memory = (void *)(min_high_pfn << PAGE_SHIFT);
172 kmap_init(); 196 kmap_init();
173#endif 197#endif
@@ -185,7 +209,7 @@ void __init mem_init(void)
185 unsigned long tmp; 209 unsigned long tmp;
186 210
187 reset_all_zones_managed_pages(); 211 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++)
189 free_highmem_page(pfn_to_page(tmp)); 213 free_highmem_page(pfn_to_page(tmp));
190#endif 214#endif
191 215