aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2015-11-21 18:07:06 -0500
committerHelge Deller <deller@gmx.de>2015-11-22 06:23:10 -0500
commit736d2169338a50c8814efc186b5423aee43b0c68 (patch)
tree69165c38eafe94a26675eae70e4f09bae4863fa4 /arch/parisc
parent337685e556c6f080bf4775950e3b9493852715f8 (diff)
parisc: Add Huge Page and HUGETLBFS support
This patch adds huge page support to allow userspace to allocate huge pages and to use hugetlbfs filesystem on 32- and 64-bit Linux kernels. A later patch will add kernel support to map kernel text and data on huge pages. The only requirement is, that the kernel needs to be compiled for a PA8X00 CPU (PA2.0 architecture). Older PA1.X CPUs do not support variable page sizes. 64bit Kernels are compiled for PA2.0 by default. Technically on parisc multiple physical huge pages may be needed to emulate standard 2MB huge pages. Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/Kconfig3
-rw-r--r--arch/parisc/include/asm/hugetlb.h85
-rw-r--r--arch/parisc/kernel/entry.S45
-rw-r--r--arch/parisc/kernel/setup.c11
-rw-r--r--arch/parisc/mm/Makefile1
-rw-r--r--arch/parisc/mm/hugetlbpage.c161
6 files changed, 291 insertions, 15 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index c36546959e86..729f89163bc3 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -108,6 +108,9 @@ config PGTABLE_LEVELS
108 default 3 if 64BIT && PARISC_PAGE_SIZE_4KB 108 default 3 if 64BIT && PARISC_PAGE_SIZE_4KB
109 default 2 109 default 2
110 110
111config SYS_SUPPORTS_HUGETLBFS
112 def_bool y if PA20
113
111source "init/Kconfig" 114source "init/Kconfig"
112 115
113source "kernel/Kconfig.freezer" 116source "kernel/Kconfig.freezer"
diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h
new file mode 100644
index 000000000000..7d56a9ccb752
--- /dev/null
+++ b/arch/parisc/include/asm/hugetlb.h
@@ -0,0 +1,85 @@
1#ifndef _ASM_PARISC64_HUGETLB_H
2#define _ASM_PARISC64_HUGETLB_H
3
4#include <asm/page.h>
5#include <asm-generic/hugetlb.h>
6
7
8void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
9 pte_t *ptep, pte_t pte);
10
11pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
12 pte_t *ptep);
13
14static inline int is_hugepage_only_range(struct mm_struct *mm,
15 unsigned long addr,
16 unsigned long len) {
17 return 0;
18}
19
20/*
21 * If the arch doesn't supply something else, assume that hugepage
22 * size aligned regions are ok without further preparation.
23 */
24static inline int prepare_hugepage_range(struct file *file,
25 unsigned long addr, unsigned long len)
26{
27 if (len & ~HPAGE_MASK)
28 return -EINVAL;
29 if (addr & ~HPAGE_MASK)
30 return -EINVAL;
31 return 0;
32}
33
34static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
35 unsigned long addr, unsigned long end,
36 unsigned long floor,
37 unsigned long ceiling)
38{
39 free_pgd_range(tlb, addr, end, floor, ceiling);
40}
41
42static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
43 unsigned long addr, pte_t *ptep)
44{
45}
46
47static inline int huge_pte_none(pte_t pte)
48{
49 return pte_none(pte);
50}
51
52static inline pte_t huge_pte_wrprotect(pte_t pte)
53{
54 return pte_wrprotect(pte);
55}
56
57static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
58 unsigned long addr, pte_t *ptep)
59{
60 pte_t old_pte = *ptep;
61 set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
62}
63
64static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
65 unsigned long addr, pte_t *ptep,
66 pte_t pte, int dirty)
67{
68 int changed = !pte_same(*ptep, pte);
69 if (changed) {
70 set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
71 flush_tlb_page(vma, addr);
72 }
73 return changed;
74}
75
76static inline pte_t huge_ptep_get(pte_t *ptep)
77{
78 return *ptep;
79}
80
81static inline void arch_clear_hugepage_flags(struct page *page)
82{
83}
84
85#endif /* _ASM_PARISC64_HUGETLB_H */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index b2fdc44da0d5..623496c11756 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -502,21 +502,38 @@
502 STREG \pte,0(\ptp) 502 STREG \pte,0(\ptp)
503 .endm 503 .endm
504 504
505 /* We have (depending on the page size):
506 * - 38 to 52-bit Physical Page Number
507 * - 12 to 26-bit page offset
508 */
505 /* bitshift difference between a PFN (based on kernel's PAGE_SIZE) 509 /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
506 * to a CPU TLB 4k PFN (4k => 12 bits to shift) */ 510 * to a CPU TLB 4k PFN (4k => 12 bits to shift) */
507 #define PAGE_ADD_SHIFT (PAGE_SHIFT-12) 511 #define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
512 #define PAGE_ADD_HUGE_SHIFT (REAL_HPAGE_SHIFT-12)
508 513
509 /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ 514 /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
510 .macro convert_for_tlb_insert20 pte 515 .macro convert_for_tlb_insert20 pte,tmp
516#ifdef CONFIG_HUGETLB_PAGE
517 copy \pte,\tmp
518 extrd,u \tmp,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
519 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
520
521 depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
522 (63-58)+PAGE_ADD_SHIFT,\pte
523 extrd,u,*= \tmp,_PAGE_HPAGE_BIT+32,1,%r0
524 depdi _HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\
525 (63-58)+PAGE_ADD_HUGE_SHIFT,\pte
526#else /* Huge pages disabled */
511 extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\ 527 extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
512 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte 528 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
513 depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\ 529 depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
514 (63-58)+PAGE_ADD_SHIFT,\pte 530 (63-58)+PAGE_ADD_SHIFT,\pte
531#endif
515 .endm 532 .endm
516 533
517 /* Convert the pte and prot to tlb insertion values. How 534 /* Convert the pte and prot to tlb insertion values. How
518 * this happens is quite subtle, read below */ 535 * this happens is quite subtle, read below */
519 .macro make_insert_tlb spc,pte,prot 536 .macro make_insert_tlb spc,pte,prot,tmp
520 space_to_prot \spc \prot /* create prot id from space */ 537 space_to_prot \spc \prot /* create prot id from space */
521 /* The following is the real subtlety. This is depositing 538 /* The following is the real subtlety. This is depositing
522 * T <-> _PAGE_REFTRAP 539 * T <-> _PAGE_REFTRAP
@@ -553,7 +570,7 @@
553 depdi 1,12,1,\prot 570 depdi 1,12,1,\prot
554 571
555 /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ 572 /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
556 convert_for_tlb_insert20 \pte 573 convert_for_tlb_insert20 \pte \tmp
557 .endm 574 .endm
558 575
559 /* Identical macro to make_insert_tlb above, except it 576 /* Identical macro to make_insert_tlb above, except it
@@ -1142,7 +1159,7 @@ dtlb_miss_20w:
1142 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20w 1159 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20w
1143 update_accessed ptp,pte,t0,t1 1160 update_accessed ptp,pte,t0,t1
1144 1161
1145 make_insert_tlb spc,pte,prot 1162 make_insert_tlb spc,pte,prot,t1
1146 1163
1147 idtlbt pte,prot 1164 idtlbt pte,prot
1148 1165
@@ -1168,7 +1185,7 @@ nadtlb_miss_20w:
1168 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20w 1185 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
1169 update_accessed ptp,pte,t0,t1 1186 update_accessed ptp,pte,t0,t1
1170 1187
1171 make_insert_tlb spc,pte,prot 1188 make_insert_tlb spc,pte,prot,t1
1172 1189
1173 idtlbt pte,prot 1190 idtlbt pte,prot
1174 1191
@@ -1262,7 +1279,7 @@ dtlb_miss_20:
1262 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20 1279 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20
1263 update_accessed ptp,pte,t0,t1 1280 update_accessed ptp,pte,t0,t1
1264 1281
1265 make_insert_tlb spc,pte,prot 1282 make_insert_tlb spc,pte,prot,t1
1266 1283
1267 f_extend pte,t1 1284 f_extend pte,t1
1268 1285
@@ -1290,7 +1307,7 @@ nadtlb_miss_20:
1290 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20 1307 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20
1291 update_accessed ptp,pte,t0,t1 1308 update_accessed ptp,pte,t0,t1
1292 1309
1293 make_insert_tlb spc,pte,prot 1310 make_insert_tlb spc,pte,prot,t1
1294 1311
1295 f_extend pte,t1 1312 f_extend pte,t1
1296 1313
@@ -1399,7 +1416,7 @@ itlb_miss_20w:
1399 tlb_lock spc,ptp,pte,t0,t1,itlb_fault 1416 tlb_lock spc,ptp,pte,t0,t1,itlb_fault
1400 update_accessed ptp,pte,t0,t1 1417 update_accessed ptp,pte,t0,t1
1401 1418
1402 make_insert_tlb spc,pte,prot 1419 make_insert_tlb spc,pte,prot,t1
1403 1420
1404 iitlbt pte,prot 1421 iitlbt pte,prot
1405 1422
@@ -1423,7 +1440,7 @@ naitlb_miss_20w:
1423 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20w 1440 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20w
1424 update_accessed ptp,pte,t0,t1 1441 update_accessed ptp,pte,t0,t1
1425 1442
1426 make_insert_tlb spc,pte,prot 1443 make_insert_tlb spc,pte,prot,t1
1427 1444
1428 iitlbt pte,prot 1445 iitlbt pte,prot
1429 1446
@@ -1509,7 +1526,7 @@ itlb_miss_20:
1509 tlb_lock spc,ptp,pte,t0,t1,itlb_fault 1526 tlb_lock spc,ptp,pte,t0,t1,itlb_fault
1510 update_accessed ptp,pte,t0,t1 1527 update_accessed ptp,pte,t0,t1
1511 1528
1512 make_insert_tlb spc,pte,prot 1529 make_insert_tlb spc,pte,prot,t1
1513 1530
1514 f_extend pte,t1 1531 f_extend pte,t1
1515 1532
@@ -1529,7 +1546,7 @@ naitlb_miss_20:
1529 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20 1546 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20
1530 update_accessed ptp,pte,t0,t1 1547 update_accessed ptp,pte,t0,t1
1531 1548
1532 make_insert_tlb spc,pte,prot 1549 make_insert_tlb spc,pte,prot,t1
1533 1550
1534 f_extend pte,t1 1551 f_extend pte,t1
1535 1552
@@ -1561,7 +1578,7 @@ dbit_trap_20w:
1561 tlb_lock spc,ptp,pte,t0,t1,dbit_fault 1578 tlb_lock spc,ptp,pte,t0,t1,dbit_fault
1562 update_dirty ptp,pte,t1 1579 update_dirty ptp,pte,t1
1563 1580
1564 make_insert_tlb spc,pte,prot 1581 make_insert_tlb spc,pte,prot,t1
1565 1582
1566 idtlbt pte,prot 1583 idtlbt pte,prot
1567 1584
@@ -1605,7 +1622,7 @@ dbit_trap_20:
1605 tlb_lock spc,ptp,pte,t0,t1,dbit_fault 1622 tlb_lock spc,ptp,pte,t0,t1,dbit_fault
1606 update_dirty ptp,pte,t1 1623 update_dirty ptp,pte,t1
1607 1624
1608 make_insert_tlb spc,pte,prot 1625 make_insert_tlb spc,pte,prot,t1
1609 1626
1610 f_extend pte,t1 1627 f_extend pte,t1
1611 1628
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index f097762d3922..f7ea626e29c9 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -130,7 +130,16 @@ void __init setup_arch(char **cmdline_p)
130 printk(KERN_INFO "The 32-bit Kernel has started...\n"); 130 printk(KERN_INFO "The 32-bit Kernel has started...\n");
131#endif 131#endif
132 132
133 printk(KERN_INFO "Default page size is %dKB.\n", (int)(PAGE_SIZE / 1024)); 133 printk(KERN_INFO "Kernel default page size is %d KB. Huge pages ",
134 (int)(PAGE_SIZE / 1024));
135#ifdef CONFIG_HUGETLB_PAGE
136 printk(KERN_CONT "enabled with %d MB physical and %d MB virtual size",
137 1 << (REAL_HPAGE_SHIFT - 20), 1 << (HPAGE_SHIFT - 20));
138#else
139 printk(KERN_CONT "disabled");
140#endif
141 printk(KERN_CONT ".\n");
142
134 143
135 pdc_console_init(); 144 pdc_console_init();
136 145
diff --git a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile
index 758ceefb373a..134393de69d2 100644
--- a/arch/parisc/mm/Makefile
+++ b/arch/parisc/mm/Makefile
@@ -3,3 +3,4 @@
3# 3#
4 4
5obj-y := init.o fault.o ioremap.o 5obj-y := init.o fault.o ioremap.o
6obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c
new file mode 100644
index 000000000000..f6fdc77a72bd
--- /dev/null
+++ b/arch/parisc/mm/hugetlbpage.c
@@ -0,0 +1,161 @@
1/*
2 * PARISC64 Huge TLB page support.
3 *
4 * This parisc implementation is heavily based on the SPARC and x86 code.
5 *
6 * Copyright (C) 2015 Helge Deller <deller@gmx.de>
7 */
8
9#include <linux/fs.h>
10#include <linux/mm.h>
11#include <linux/hugetlb.h>
12#include <linux/pagemap.h>
13#include <linux/sysctl.h>
14
15#include <asm/mman.h>
16#include <asm/pgalloc.h>
17#include <asm/tlb.h>
18#include <asm/tlbflush.h>
19#include <asm/cacheflush.h>
20#include <asm/mmu_context.h>
21
22
23unsigned long
24hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
25 unsigned long len, unsigned long pgoff, unsigned long flags)
26{
27 struct hstate *h = hstate_file(file);
28
29 if (len & ~huge_page_mask(h))
30 return -EINVAL;
31 if (len > TASK_SIZE)
32 return -ENOMEM;
33
34 if (flags & MAP_FIXED)
35 if (prepare_hugepage_range(file, addr, len))
36 return -EINVAL;
37
38 if (addr)
39 addr = ALIGN(addr, huge_page_size(h));
40
41 /* we need to make sure the colouring is OK */
42 return arch_get_unmapped_area(file, addr, len, pgoff, flags);
43}
44
45
46pte_t *huge_pte_alloc(struct mm_struct *mm,
47 unsigned long addr, unsigned long sz)
48{
49 pgd_t *pgd;
50 pud_t *pud;
51 pmd_t *pmd;
52 pte_t *pte = NULL;
53
54 /* We must align the address, because our caller will run
55 * set_huge_pte_at() on whatever we return, which writes out
56 * all of the sub-ptes for the hugepage range. So we have
57 * to give it the first such sub-pte.
58 */
59 addr &= HPAGE_MASK;
60
61 pgd = pgd_offset(mm, addr);
62 pud = pud_alloc(mm, pgd, addr);
63 if (pud) {
64 pmd = pmd_alloc(mm, pud, addr);
65 if (pmd)
66 pte = pte_alloc_map(mm, NULL, pmd, addr);
67 }
68 return pte;
69}
70
71pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
72{
73 pgd_t *pgd;
74 pud_t *pud;
75 pmd_t *pmd;
76 pte_t *pte = NULL;
77
78 addr &= HPAGE_MASK;
79
80 pgd = pgd_offset(mm, addr);
81 if (!pgd_none(*pgd)) {
82 pud = pud_offset(pgd, addr);
83 if (!pud_none(*pud)) {
84 pmd = pmd_offset(pud, addr);
85 if (!pmd_none(*pmd))
86 pte = pte_offset_map(pmd, addr);
87 }
88 }
89 return pte;
90}
91
92/* Purge data and instruction TLB entries. Must be called holding
93 * the pa_tlb_lock. The TLB purge instructions are slow on SMP
94 * machines since the purge must be broadcast to all CPUs.
95 */
96static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long addr)
97{
98 int i;
99
100 /* We may use multiple physical huge pages (e.g. 2x1 MB) to emulate
101 * Linux standard huge pages (e.g. 2 MB) */
102 BUILD_BUG_ON(REAL_HPAGE_SHIFT > HPAGE_SHIFT);
103
104 addr &= HPAGE_MASK;
105 addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
106
107 for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
108 mtsp(mm->context, 1);
109 pdtlb(addr);
110 if (unlikely(split_tlb))
111 pitlb(addr);
112 addr += (1UL << REAL_HPAGE_SHIFT);
113 }
114}
115
116void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
117 pte_t *ptep, pte_t entry)
118{
119 unsigned long addr_start;
120 int i;
121
122 addr &= HPAGE_MASK;
123 addr_start = addr;
124
125 for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
126 /* Directly write pte entry. We could call set_pte_at(mm, addr, ptep, entry)
127 * instead, but then we get double locking on pa_tlb_lock. */
128 *ptep = entry;
129 ptep++;
130
131 /* Drop the PAGE_SIZE/non-huge tlb entry */
132 purge_tlb_entries(mm, addr);
133
134 addr += PAGE_SIZE;
135 pte_val(entry) += PAGE_SIZE;
136 }
137
138 purge_tlb_entries_huge(mm, addr_start);
139}
140
141
142pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
143 pte_t *ptep)
144{
145 pte_t entry;
146
147 entry = *ptep;
148 set_huge_pte_at(mm, addr, ptep, __pte(0));
149
150 return entry;
151}
152
153int pmd_huge(pmd_t pmd)
154{
155 return 0;
156}
157
158int pud_huge(pud_t pud)
159{
160 return 0;
161}