History

parisc: Rewrite cache flush code for PA8800/PA8900

Originally, I was convinced that we needed to use tmpalias flushes everwhere, for both user and kernel flushes. However, when I modified flush_kernel_dcache_page_addr, to use a tmpalias flush, my c8000 would crash quite early when booting. The PDC returns alias values of 0 for the icache and dcache. This indicates that either the alias boundary is greater than 16MB or equivalent aliasing doesn't work. I modified the tmpalias code to make it easy to try alternate boundaries. I tried boundaries up to 128MB but still kernel tmpalias flushes didn't work on c8000. This led me to conclude that tmpalias flushes don't work on PA8800 and PA8900 machines, and that we needed to flush directly using the virtual address of user and kernel pages. This is likely the major cause of instability on the c8000 and rp34xx machines. Flushing user pages requires doing a temporary context switch as we have to flush pages that don't belong to the current context. Further, we have to deal with pages that aren't present. If a page isn't present, the flush instructions fault on every line. Other code has been rearranged and simplified based on testing. For example, I introduced a flush_cache_dup_mm routine. flush_cache_mm and flush_cache_dup_mm differ in that flush_cache_mm calls purge_cache_pages and flush_cache_dup_mm calls flush_cache_pages. In some implementations, pdc is more efficient than fdc. Based on my testing, I don't believe there's any performance benefit on the c8000.

John David Anglin committed 4 years ago

Commit 2de8b4c1 parent 67c35a33 files · +236 −127Browse files

Showing the changes to arch/parisc/include (2 of 3 files). Show all

Unified · Split

2 files
  1. arch/parisc/include/asm/cacheflush.h +7 −24
  2. arch/parisc/include/asm/page.h +4 −2
arch/parisc/include/asm/cacheflush.h+7−24
@@ -59,20 +59,12 @@ void flush_dcache_page(struct page *page); · 58 unmodified lines
59 flush_kernel_icache_range_asm(s,e); \59 flush_kernel_icache_range_asm(s,e); \
60} while (0)60} while (0)
61 61
62#define copy_to_user_page(vma, page, vaddr, dst, src, len) \62void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
63do { \63 unsigned long user_vaddr, void *dst, void *src, int len);
64 flush_cache_page(vma, vaddr, page_to_pfn(page)); \64void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
65 memcpy(dst, src, len); \65 unsigned long user_vaddr, void *dst, void *src, int len);
66 flush_kernel_dcache_range_asm((unsigned long)dst, (unsigned long)dst + len); \66void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
67} while (0)67 unsigned long pfn);
68
69#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
70do { \
71 flush_cache_page(vma, vaddr, page_to_pfn(page)); \
72 memcpy(dst, src, len); \
73} while (0)
74
75void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn);
76void flush_cache_range(struct vm_area_struct *vma,68void flush_cache_range(struct vm_area_struct *vma,
77 unsigned long start, unsigned long end);69 unsigned long start, unsigned long end);
78 70
@@ -80,16 +72,7 @@ void flush_cache_range(struct vm_area_struct *vma, · 1 unmodified line
80void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);72void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
81 73
82#define ARCH_HAS_FLUSH_ANON_PAGE74#define ARCH_HAS_FLUSH_ANON_PAGE
83static inline void75void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr);
84flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
85{
86 if (PageAnon(page)) {
87 flush_tlb_page(vma, vmaddr);
88 preempt_disable();
89 flush_dcache_page_asm(page_to_phys(page), vmaddr);
90 preempt_enable();
91 }
92}
93 76
94#define ARCH_HAS_FLUSH_ON_KUNMAP77#define ARCH_HAS_FLUSH_ON_KUNMAP
95static inline void kunmap_flush_on_unmap(void *addr)78static inline void kunmap_flush_on_unmap(void *addr)
arch/parisc/include/asm/page.h+4−2
@@ -26,12 +26,14 @@ · 25 unmodified lines
26#define copy_page(to, from) copy_page_asm((void *)(to), (void *)(from))26#define copy_page(to, from) copy_page_asm((void *)(to), (void *)(from))
27 27
28struct page;28struct page;
29struct vm_area_struct;
29 30
30void clear_page_asm(void *page);31void clear_page_asm(void *page);
31void copy_page_asm(void *to, void *from);32void copy_page_asm(void *to, void *from);
32#define clear_user_page(vto, vaddr, page) clear_page_asm(vto)33#define clear_user_page(vto, vaddr, page) clear_page_asm(vto)
33void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,34void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr,
34 struct page *pg);35 struct vm_area_struct *vma);
36#define __HAVE_ARCH_COPY_USER_HIGHPAGE
35 37
36/*38/*
37 * These are used to make use of C type-checking..39 * These are used to make use of C type-checking..