diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2014-09-23 15:29:20 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-09-30 04:19:29 -0400 |
commit | cfb0b24143b4f587ff3e3bd829f9f471285d097b (patch) | |
tree | 217a325aaba02fa8b6a0c91d8dd2abe7b96fcb66 /arch/s390 | |
parent | 242a112af62ea73ce507cbe76c2c944c23b6a1e3 (diff) |
s390/mm: make use of ipte range facility
Invalidate several pte entries at once if the ipte range facility
is available. Currently this works only for DEBUG_PAGE_ALLOC where
several up to 2 ^ MAX_ORDER may be invalidated at once.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 16 | ||||
-rw-r--r-- | arch/s390/mm/pageattr.c | 38 |
2 files changed, 47 insertions, 7 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 7c4af56f2b73..2de229c1b467 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -1053,6 +1053,22 @@ static inline void __ptep_ipte_local(unsigned long address, pte_t *ptep) | |||
1053 | : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address)); | 1053 | : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address)); |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | static inline void __ptep_ipte_range(unsigned long address, int nr, pte_t *ptep) | ||
1057 | { | ||
1058 | unsigned long pto = (unsigned long) ptep; | ||
1059 | |||
1060 | #ifndef CONFIG_64BIT | ||
1061 | /* pto in ESA mode must point to the start of the segment table */ | ||
1062 | pto &= 0x7ffffc00; | ||
1063 | #endif | ||
1064 | /* Invalidate a range of ptes + global TLB flush of the ptes */ | ||
1065 | do { | ||
1066 | asm volatile( | ||
1067 | " .insn rrf,0xb2210000,%2,%0,%1,0" | ||
1068 | : "+a" (address), "+a" (nr) : "a" (pto) : "memory"); | ||
1069 | } while (nr != 255); | ||
1070 | } | ||
1071 | |||
1056 | static inline void ptep_flush_direct(struct mm_struct *mm, | 1072 | static inline void ptep_flush_direct(struct mm_struct *mm, |
1057 | unsigned long address, pte_t *ptep) | 1073 | unsigned long address, pte_t *ptep) |
1058 | { | 1074 | { |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 8400f494623f..3fef3b299665 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/mm.h> | 7 | #include <linux/mm.h> |
8 | #include <asm/cacheflush.h> | 8 | #include <asm/cacheflush.h> |
9 | #include <asm/facility.h> | ||
9 | #include <asm/pgtable.h> | 10 | #include <asm/pgtable.h> |
10 | #include <asm/page.h> | 11 | #include <asm/page.h> |
11 | 12 | ||
@@ -103,27 +104,50 @@ int set_memory_x(unsigned long addr, int numpages) | |||
103 | } | 104 | } |
104 | 105 | ||
105 | #ifdef CONFIG_DEBUG_PAGEALLOC | 106 | #ifdef CONFIG_DEBUG_PAGEALLOC |
107 | |||
108 | static void ipte_range(pte_t *pte, unsigned long address, int nr) | ||
109 | { | ||
110 | int i; | ||
111 | |||
112 | if (test_facility(13) && IS_ENABLED(CONFIG_64BIT)) { | ||
113 | __ptep_ipte_range(address, nr - 1, pte); | ||
114 | return; | ||
115 | } | ||
116 | for (i = 0; i < nr; i++) { | ||
117 | __ptep_ipte(address, pte); | ||
118 | address += PAGE_SIZE; | ||
119 | pte++; | ||
120 | } | ||
121 | } | ||
122 | |||
106 | void kernel_map_pages(struct page *page, int numpages, int enable) | 123 | void kernel_map_pages(struct page *page, int numpages, int enable) |
107 | { | 124 | { |
108 | unsigned long address; | 125 | unsigned long address; |
126 | int nr, i, j; | ||
109 | pgd_t *pgd; | 127 | pgd_t *pgd; |
110 | pud_t *pud; | 128 | pud_t *pud; |
111 | pmd_t *pmd; | 129 | pmd_t *pmd; |
112 | pte_t *pte; | 130 | pte_t *pte; |
113 | int i; | ||
114 | 131 | ||
115 | for (i = 0; i < numpages; i++) { | 132 | for (i = 0; i < numpages;) { |
116 | address = page_to_phys(page + i); | 133 | address = page_to_phys(page + i); |
117 | pgd = pgd_offset_k(address); | 134 | pgd = pgd_offset_k(address); |
118 | pud = pud_offset(pgd, address); | 135 | pud = pud_offset(pgd, address); |
119 | pmd = pmd_offset(pud, address); | 136 | pmd = pmd_offset(pud, address); |
120 | pte = pte_offset_kernel(pmd, address); | 137 | pte = pte_offset_kernel(pmd, address); |
121 | if (!enable) { | 138 | nr = (unsigned long)pte >> ilog2(sizeof(long)); |
122 | __ptep_ipte(address, pte); | 139 | nr = PTRS_PER_PTE - (nr & (PTRS_PER_PTE - 1)); |
123 | pte_val(*pte) = _PAGE_INVALID; | 140 | nr = min(numpages - i, nr); |
124 | continue; | 141 | if (enable) { |
142 | for (j = 0; j < nr; j++) { | ||
143 | pte_val(*pte) = __pa(address); | ||
144 | address += PAGE_SIZE; | ||
145 | pte++; | ||
146 | } | ||
147 | } else { | ||
148 | ipte_range(pte, address, nr); | ||
125 | } | 149 | } |
126 | pte_val(*pte) = __pa(address); | 150 | i += nr; |
127 | } | 151 | } |
128 | } | 152 | } |
129 | 153 | ||