Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: implement the new page table range API

Add PFN_PTE_SHIFT, update_mmu_cache_range(), flush_dcache_folio() and
flush_icache_pages(). Change the PG_dcache_clean flag from being per-page
to per-folio. Flush the entire folio containing the pages in
flush_icache_pages() for ease of implementation.

Link: https://lkml.kernel.org/r/20230802151406.3735276-25-willy@infradead.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Cc: Rich Felker <dalias@libc.org>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Matthew Wilcox (Oracle) and committed by
Andrew Morton
157efa29 843f9310

+89 -55
+14 -7
arch/sh/include/asm/cacheflush.h
··· 13 13 * - flush_cache_page(mm, vmaddr, pfn) flushes a single page 14 14 * - flush_cache_range(vma, start, end) flushes a range of pages 15 15 * 16 - * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache 16 + * - flush_dcache_folio(folio) flushes(wback&invalidates) a folio for dcache 17 17 * - flush_icache_range(start, end) flushes(invalidates) a range for icache 18 - * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache 18 + * - flush_icache_pages(vma, pg, nr) flushes(invalidates) pages for icache 19 19 * - flush_cache_sigtramp(vaddr) flushes the signal trampoline 20 20 */ 21 21 extern void (*local_flush_cache_all)(void *args); ··· 23 23 extern void (*local_flush_cache_dup_mm)(void *args); 24 24 extern void (*local_flush_cache_page)(void *args); 25 25 extern void (*local_flush_cache_range)(void *args); 26 - extern void (*local_flush_dcache_page)(void *args); 26 + extern void (*local_flush_dcache_folio)(void *args); 27 27 extern void (*local_flush_icache_range)(void *args); 28 - extern void (*local_flush_icache_page)(void *args); 28 + extern void (*local_flush_icache_folio)(void *args); 29 29 extern void (*local_flush_cache_sigtramp)(void *args); 30 30 31 31 static inline void cache_noop(void *args) { } ··· 42 42 extern void flush_cache_range(struct vm_area_struct *vma, 43 43 unsigned long start, unsigned long end); 44 44 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 45 - void flush_dcache_page(struct page *page); 45 + void flush_dcache_folio(struct folio *folio); 46 + #define flush_dcache_folio flush_dcache_folio 47 + static inline void flush_dcache_page(struct page *page) 48 + { 49 + flush_dcache_folio(page_folio(page)); 50 + } 51 + 46 52 extern void flush_icache_range(unsigned long start, unsigned long end); 47 53 #define flush_icache_user_range flush_icache_range 48 - extern void flush_icache_page(struct vm_area_struct *vma, 49 - struct page *page); 54 + void flush_icache_pages(struct vm_area_struct *vma, struct page *page, 55 + unsigned int nr); 56 + #define flush_icache_page(vma, page) flush_icache_pages(vma, page, 1) 50 57 extern void flush_cache_sigtramp(unsigned long address); 51 58 52 59 struct flusher_data {
+5 -2
arch/sh/include/asm/pgtable.h
··· 102 102 extern void __update_tlb(struct vm_area_struct *vma, 103 103 unsigned long address, pte_t pte); 104 104 105 - static inline void 106 - update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) 105 + static inline void update_mmu_cache_range(struct vm_fault *vmf, 106 + struct vm_area_struct *vma, unsigned long address, 107 + pte_t *ptep, unsigned int nr) 107 108 { 108 109 pte_t pte = *ptep; 109 110 __update_cache(vma, address, pte); 110 111 __update_tlb(vma, address, pte); 111 112 } 113 + #define update_mmu_cache(vma, addr, ptep) \ 114 + update_mmu_cache_range(NULL, vma, addr, ptep, 1) 112 115 113 116 extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; 114 117 extern void paging_init(void);
+2 -3
arch/sh/include/asm/pgtable_32.h
··· 307 307 #define set_pte(pteptr, pteval) (*(pteptr) = pteval) 308 308 #endif 309 309 310 - #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) 311 - 312 310 /* 313 311 * (pmds are folded into pgds so this doesn't get actually called, 314 312 * but the define is needed for a generic inline function.) 315 313 */ 316 314 #define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) 317 315 316 + #define PFN_PTE_SHIFT PAGE_SHIFT 318 317 #define pfn_pte(pfn, prot) \ 319 318 __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) 320 319 #define pfn_pmd(pfn, prot) \ ··· 322 323 #define pte_none(x) (!pte_val(x)) 323 324 #define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) 324 325 325 - #define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) 326 + #define pte_clear(mm, addr, ptep) set_pte(ptep, __pte(0)) 326 327 327 328 #define pmd_none(x) (!pmd_val(x)) 328 329 #define pmd_present(x) (pmd_val(x))
+2 -2
arch/sh/mm/cache-j2.c
··· 55 55 local_flush_cache_dup_mm = j2_flush_both; 56 56 local_flush_cache_page = j2_flush_both; 57 57 local_flush_cache_range = j2_flush_both; 58 - local_flush_dcache_page = j2_flush_dcache; 58 + local_flush_dcache_folio = j2_flush_dcache; 59 59 local_flush_icache_range = j2_flush_icache; 60 - local_flush_icache_page = j2_flush_icache; 60 + local_flush_icache_folio = j2_flush_icache; 61 61 local_flush_cache_sigtramp = j2_flush_icache; 62 62 63 63 pr_info("Initial J2 CCR is %.8x\n", __raw_readl(j2_ccr_base));
+18 -8
arch/sh/mm/cache-sh4.c
··· 107 107 * Write back & invalidate the D-cache of the page. 108 108 * (To avoid "alias" issues) 109 109 */ 110 - static void sh4_flush_dcache_page(void *arg) 110 + static void sh4_flush_dcache_folio(void *arg) 111 111 { 112 - struct page *page = arg; 113 - unsigned long addr = (unsigned long)page_address(page); 112 + struct folio *folio = arg; 114 113 #ifndef CONFIG_SMP 115 - struct address_space *mapping = page_mapping_file(page); 114 + struct address_space *mapping = folio_flush_mapping(folio); 116 115 117 116 if (mapping && !mapping_mapped(mapping)) 118 - clear_bit(PG_dcache_clean, &page->flags); 117 + clear_bit(PG_dcache_clean, &folio->flags); 119 118 else 120 119 #endif 121 - flush_cache_one(CACHE_OC_ADDRESS_ARRAY | 122 - (addr & shm_align_mask), page_to_phys(page)); 120 + { 121 + unsigned long pfn = folio_pfn(folio); 122 + unsigned long addr = (unsigned long)folio_address(folio); 123 + unsigned int i, nr = folio_nr_pages(folio); 124 + 125 + for (i = 0; i < nr; i++) { 126 + flush_cache_one(CACHE_OC_ADDRESS_ARRAY | 127 + (addr & shm_align_mask), 128 + pfn * PAGE_SIZE); 129 + addr += PAGE_SIZE; 130 + pfn++; 131 + } 132 + } 123 133 124 134 wmb(); 125 135 } ··· 389 379 __raw_readl(CCN_PRR)); 390 380 391 381 local_flush_icache_range = sh4_flush_icache_range; 392 - local_flush_dcache_page = sh4_flush_dcache_page; 382 + local_flush_dcache_folio = sh4_flush_dcache_folio; 393 383 local_flush_cache_all = sh4_flush_cache_all; 394 384 local_flush_cache_mm = sh4_flush_cache_mm; 395 385 local_flush_cache_dup_mm = sh4_flush_cache_mm;
+16 -10
arch/sh/mm/cache-sh7705.c
··· 132 132 * Write back & invalidate the D-cache of the page. 133 133 * (To avoid "alias" issues) 134 134 */ 135 - static void sh7705_flush_dcache_page(void *arg) 135 + static void sh7705_flush_dcache_folio(void *arg) 136 136 { 137 - struct page *page = arg; 138 - struct address_space *mapping = page_mapping_file(page); 137 + struct folio *folio = arg; 138 + struct address_space *mapping = folio_flush_mapping(folio); 139 139 140 140 if (mapping && !mapping_mapped(mapping)) 141 - clear_bit(PG_dcache_clean, &page->flags); 142 - else 143 - __flush_dcache_page(__pa(page_address(page))); 141 + clear_bit(PG_dcache_clean, &folio->flags); 142 + else { 143 + unsigned long pfn = folio_pfn(folio); 144 + unsigned int i, nr = folio_nr_pages(folio); 145 + 146 + for (i = 0; i < nr; i++) 147 + __flush_dcache_page((pfn + i) * PAGE_SIZE); 148 + } 144 149 } 145 150 146 151 static void sh7705_flush_cache_all(void *args) ··· 181 176 * Not entirely sure why this is necessary on SH3 with 32K cache but 182 177 * without it we get occasional "Memory fault" when loading a program. 183 178 */ 184 - static void sh7705_flush_icache_page(void *page) 179 + static void sh7705_flush_icache_folio(void *arg) 185 180 { 186 - __flush_purge_region(page_address(page), PAGE_SIZE); 181 + struct folio *folio = arg; 182 + __flush_purge_region(folio_address(folio), folio_size(folio)); 187 183 } 188 184 189 185 void __init sh7705_cache_init(void) 190 186 { 191 187 local_flush_icache_range = sh7705_flush_icache_range; 192 - local_flush_dcache_page = sh7705_flush_dcache_page; 188 + local_flush_dcache_folio = sh7705_flush_dcache_folio; 193 189 local_flush_cache_all = sh7705_flush_cache_all; 194 190 local_flush_cache_mm = sh7705_flush_cache_all; 195 191 local_flush_cache_dup_mm = sh7705_flush_cache_all; 196 192 local_flush_cache_range = sh7705_flush_cache_all; 197 193 local_flush_cache_page = sh7705_flush_cache_page; 198 - local_flush_icache_page = sh7705_flush_icache_page; 194 + local_flush_icache_folio = sh7705_flush_icache_folio; 199 195 }
+30 -22
arch/sh/mm/cache.c
··· 20 20 void (*local_flush_cache_dup_mm)(void *args) = cache_noop; 21 21 void (*local_flush_cache_page)(void *args) = cache_noop; 22 22 void (*local_flush_cache_range)(void *args) = cache_noop; 23 - void (*local_flush_dcache_page)(void *args) = cache_noop; 23 + void (*local_flush_dcache_folio)(void *args) = cache_noop; 24 24 void (*local_flush_icache_range)(void *args) = cache_noop; 25 - void (*local_flush_icache_page)(void *args) = cache_noop; 25 + void (*local_flush_icache_folio)(void *args) = cache_noop; 26 26 void (*local_flush_cache_sigtramp)(void *args) = cache_noop; 27 27 28 28 void (*__flush_wback_region)(void *start, int size); ··· 61 61 unsigned long vaddr, void *dst, const void *src, 62 62 unsigned long len) 63 63 { 64 - if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) && 65 - test_bit(PG_dcache_clean, &page->flags)) { 64 + struct folio *folio = page_folio(page); 65 + 66 + if (boot_cpu_data.dcache.n_aliases && folio_mapped(folio) && 67 + test_bit(PG_dcache_clean, &folio->flags)) { 66 68 void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 67 69 memcpy(vto, src, len); 68 70 kunmap_coherent(vto); 69 71 } else { 70 72 memcpy(dst, src, len); 71 73 if (boot_cpu_data.dcache.n_aliases) 72 - clear_bit(PG_dcache_clean, &page->flags); 74 + clear_bit(PG_dcache_clean, &folio->flags); 73 75 } 74 76 75 77 if (vma->vm_flags & VM_EXEC) ··· 82 80 unsigned long vaddr, void *dst, const void *src, 83 81 unsigned long len) 84 82 { 83 + struct folio *folio = page_folio(page); 84 + 85 85 if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) && 86 - test_bit(PG_dcache_clean, &page->flags)) { 86 + test_bit(PG_dcache_clean, &folio->flags)) { 87 87 void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 88 88 memcpy(dst, vfrom, len); 89 89 kunmap_coherent(vfrom); 90 90 } else { 91 91 memcpy(dst, src, len); 92 92 if (boot_cpu_data.dcache.n_aliases) 93 - clear_bit(PG_dcache_clean, &page->flags); 93 + clear_bit(PG_dcache_clean, &folio->flags); 94 94 } 95 95 } 96 96 97 97 void copy_user_highpage(struct page *to, struct page *from, 98 98 unsigned long vaddr, struct vm_area_struct *vma) 99 99 { 100 + struct folio *src = page_folio(from); 100 101 void *vfrom, *vto; 101 102 102 103 vto = kmap_atomic(to); 103 104 104 - if (boot_cpu_data.dcache.n_aliases && page_mapcount(from) && 105 - test_bit(PG_dcache_clean, &from->flags)) { 105 + if (boot_cpu_data.dcache.n_aliases && folio_mapped(src) && 106 + test_bit(PG_dcache_clean, &src->flags)) { 106 107 vfrom = kmap_coherent(from, vaddr); 107 108 copy_page(vto, vfrom); 108 109 kunmap_coherent(vfrom); ··· 141 136 void __update_cache(struct vm_area_struct *vma, 142 137 unsigned long address, pte_t pte) 143 138 { 144 - struct page *page; 145 139 unsigned long pfn = pte_pfn(pte); 146 140 147 141 if (!boot_cpu_data.dcache.n_aliases) 148 142 return; 149 143 150 - page = pfn_to_page(pfn); 151 144 if (pfn_valid(pfn)) { 152 - int dirty = !test_and_set_bit(PG_dcache_clean, &page->flags); 145 + struct folio *folio = page_folio(pfn_to_page(pfn)); 146 + int dirty = !test_and_set_bit(PG_dcache_clean, &folio->flags); 153 147 if (dirty) 154 - __flush_purge_region(page_address(page), PAGE_SIZE); 148 + __flush_purge_region(folio_address(folio), 149 + folio_size(folio)); 155 150 } 156 151 } 157 152 158 153 void __flush_anon_page(struct page *page, unsigned long vmaddr) 159 154 { 155 + struct folio *folio = page_folio(page); 160 156 unsigned long addr = (unsigned long) page_address(page); 161 157 162 158 if (pages_do_alias(addr, vmaddr)) { 163 - if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) && 164 - test_bit(PG_dcache_clean, &page->flags)) { 159 + if (boot_cpu_data.dcache.n_aliases && folio_mapped(folio) && 160 + test_bit(PG_dcache_clean, &folio->flags)) { 165 161 void *kaddr; 166 162 167 163 kaddr = kmap_coherent(page, vmaddr); ··· 170 164 /* __flush_purge_region((void *)kaddr, PAGE_SIZE); */ 171 165 kunmap_coherent(kaddr); 172 166 } else 173 - __flush_purge_region((void *)addr, PAGE_SIZE); 167 + __flush_purge_region(folio_address(folio), 168 + folio_size(folio)); 174 169 } 175 170 } 176 171 ··· 222 215 } 223 216 EXPORT_SYMBOL(flush_cache_range); 224 217 225 - void flush_dcache_page(struct page *page) 218 + void flush_dcache_folio(struct folio *folio) 226 219 { 227 - cacheop_on_each_cpu(local_flush_dcache_page, page, 1); 220 + cacheop_on_each_cpu(local_flush_dcache_folio, folio, 1); 228 221 } 229 - EXPORT_SYMBOL(flush_dcache_page); 222 + EXPORT_SYMBOL(flush_dcache_folio); 230 223 231 224 void flush_icache_range(unsigned long start, unsigned long end) 232 225 { ··· 240 233 } 241 234 EXPORT_SYMBOL(flush_icache_range); 242 235 243 - void flush_icache_page(struct vm_area_struct *vma, struct page *page) 236 + void flush_icache_pages(struct vm_area_struct *vma, struct page *page, 237 + unsigned int nr) 244 238 { 245 - /* Nothing uses the VMA, so just pass the struct page along */ 246 - cacheop_on_each_cpu(local_flush_icache_page, page, 1); 239 + /* Nothing uses the VMA, so just pass the folio along */ 240 + cacheop_on_each_cpu(local_flush_icache_folio, page_folio(page), 1); 247 241 } 248 242 249 243 void flush_cache_sigtramp(unsigned long address)
+2 -1
arch/sh/mm/kmap.c
··· 27 27 28 28 void *kmap_coherent(struct page *page, unsigned long addr) 29 29 { 30 + struct folio *folio = page_folio(page); 30 31 enum fixed_addresses idx; 31 32 unsigned long vaddr; 32 33 33 - BUG_ON(!test_bit(PG_dcache_clean, &page->flags)); 34 + BUG_ON(!test_bit(PG_dcache_clean, &folio->flags)); 34 35 35 36 preempt_disable(); 36 37 pagefault_disable();