diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-06 14:14:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-06 14:14:38 -0400 |
commit | dd287690b0aa4b0d22e8dd7dd2cb3055f5141a27 (patch) | |
tree | 58dbeb60b3fc9984220b75d268e4ad043f12bbfe | |
parent | 4883d11e06b5a02a73ee3a554168ec92ab44c0f5 (diff) | |
parent | 26f9d5fd82ca20fe536cb493ec7cf5628f8997e5 (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/Kconfig | 13 | ||||
-rw-r--r-- | arch/arc/include/asm/io.h | 27 | ||||
-rw-r--r-- | arch/arc/include/asm/mmzone.h | 43 | ||||
-rw-r--r-- | arch/arc/include/asm/page.h | 15 | ||||
-rw-r--r-- | arch/arc/include/asm/pgtable.h | 13 | ||||
-rw-r--r-- | arch/arc/mm/init.c | 54 |
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 | |||
58 | config RWSEM_GENERIC_SPINLOCK | 58 | config RWSEM_GENERIC_SPINLOCK |
59 | def_bool y | 59 | def_bool y |
60 | 60 | ||
61 | config ARCH_DISCONTIGMEM_ENABLE | ||
62 | def_bool y | ||
63 | |||
61 | config ARCH_FLATMEM_ENABLE | 64 | config ARCH_FLATMEM_ENABLE |
62 | def_bool y | 65 | def_bool y |
63 | 66 | ||
@@ -347,6 +350,15 @@ config ARC_HUGEPAGE_16M | |||
347 | 350 | ||
348 | endchoice | 351 | endchoice |
349 | 352 | ||
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 | |||
350 | if ISA_ARCOMPACT | 362 | if ISA_ARCOMPACT |
351 | 363 | ||
352 | config ARC_COMPACT_IRQ_LEVELS | 364 | config ARC_COMPACT_IRQ_LEVELS |
@@ -455,6 +467,7 @@ config LINUX_LINK_BASE | |||
455 | 467 | ||
456 | config HIGHMEM | 468 | config 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 | |||
16 | extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size); | 25 | extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size); |
17 | extern void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size, | 26 | extern 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 | |||
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 | ||
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 | ||
73 | typedef pte_t * pgtable_t; | 73 | typedef 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; | |||
30 | static unsigned long low_mem_sz; | 30 | static unsigned long low_mem_sz; |
31 | 31 | ||
32 | #ifdef CONFIG_HIGHMEM | 32 | #ifdef CONFIG_HIGHMEM |
33 | static unsigned long min_high_pfn; | 33 | static unsigned long min_high_pfn, max_high_pfn; |
34 | static u64 high_mem_start; | 34 | static u64 high_mem_start; |
35 | static u64 high_mem_sz; | 35 | static u64 high_mem_sz; |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #ifdef CONFIG_DISCONTIGMEM | ||
39 | struct pglist_data node_data[MAX_NUMNODES] __read_mostly; | ||
40 | EXPORT_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 */ |
39 | static int __init setup_mem_sz(char *str) | 44 | static 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 | ||