]>
Commit | Line | Data |
---|---|---|
00a9730e GR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | |
3 | ||
4 | #include <linux/cache.h> | |
5 | #include <linux/highmem.h> | |
6 | #include <linux/mm.h> | |
7 | #include <asm/cache.h> | |
8 | ||
00a9730e GR |
9 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, |
10 | pte_t *pte) | |
11 | { | |
d936a7e7 | 12 | unsigned long addr; |
00a9730e | 13 | struct page *page; |
00a9730e | 14 | |
d936a7e7 GR |
15 | page = pfn_to_page(pte_pfn(*pte)); |
16 | if (page == ZERO_PAGE(0)) | |
00a9730e GR |
17 | return; |
18 | ||
d936a7e7 | 19 | if (test_and_set_bit(PG_dcache_clean, &page->flags)) |
00a9730e GR |
20 | return; |
21 | ||
981bbf27 | 22 | addr = (unsigned long) kmap_atomic(page); |
00a9730e | 23 | |
d936a7e7 GR |
24 | dcache_wb_range(addr, addr + PAGE_SIZE); |
25 | ||
26 | if (vma->vm_flags & VM_EXEC) | |
27 | icache_inv_range(addr, addr + PAGE_SIZE); | |
00a9730e | 28 | |
981bbf27 | 29 | kunmap_atomic((void *) addr); |
00a9730e | 30 | } |
997153b9 GR |
31 | |
32 | void flush_icache_deferred(struct mm_struct *mm) | |
33 | { | |
34 | unsigned int cpu = smp_processor_id(); | |
35 | cpumask_t *mask = &mm->context.icache_stale_mask; | |
36 | ||
37 | if (cpumask_test_cpu(cpu, mask)) { | |
38 | cpumask_clear_cpu(cpu, mask); | |
39 | /* | |
40 | * Ensure the remote hart's writes are visible to this hart. | |
41 | * This pairs with a barrier in flush_icache_mm. | |
42 | */ | |
43 | smp_mb(); | |
44 | local_icache_inv_all(NULL); | |
45 | } | |
46 | } | |
47 | ||
48 | void flush_icache_mm_range(struct mm_struct *mm, | |
49 | unsigned long start, unsigned long end) | |
50 | { | |
51 | unsigned int cpu; | |
52 | cpumask_t others, *mask; | |
53 | ||
54 | preempt_disable(); | |
55 | ||
56 | #ifdef CONFIG_CPU_HAS_ICACHE_INS | |
57 | if (mm == current->mm) { | |
58 | icache_inv_range(start, end); | |
59 | preempt_enable(); | |
60 | return; | |
61 | } | |
62 | #endif | |
63 | ||
64 | /* Mark every hart's icache as needing a flush for this MM. */ | |
65 | mask = &mm->context.icache_stale_mask; | |
66 | cpumask_setall(mask); | |
67 | ||
68 | /* Flush this hart's I$ now, and mark it as flushed. */ | |
69 | cpu = smp_processor_id(); | |
70 | cpumask_clear_cpu(cpu, mask); | |
71 | local_icache_inv_all(NULL); | |
72 | ||
73 | /* | |
74 | * Flush the I$ of other harts concurrently executing, and mark them as | |
75 | * flushed. | |
76 | */ | |
77 | cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); | |
78 | ||
79 | if (mm != current->active_mm || !cpumask_empty(&others)) { | |
80 | on_each_cpu_mask(&others, local_icache_inv_all, NULL, 1); | |
81 | cpumask_clear(mask); | |
82 | } | |
83 | ||
84 | preempt_enable(); | |
85 | } |