1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Hexagon Virtual Machine TLB functions |
4 | * |
5 | * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. |
6 | */ |
7 | |
8 | /* |
9 | * The Hexagon Virtual Machine conceals the real workings of |
10 | * the TLB, but there are one or two functions that need to |
11 | * be instantiated for it, differently from a native build. |
12 | */ |
13 | #include <linux/mm.h> |
14 | #include <linux/sched.h> |
15 | #include <asm/page.h> |
16 | #include <asm/hexagon_vm.h> |
17 | #include <asm/tlbflush.h> |
18 | |
19 | /* |
20 | * Initial VM implementation has only one map active at a time, with |
21 | * TLB purgings on changes. So either we're nuking the current map, |
22 | * or it's a no-op. This operation is messy on true SMPs where other |
23 | * processors must be induced to flush the copies in their local TLBs, |
24 | * but Hexagon thread-based virtual processors share the same MMU. |
25 | */ |
26 | void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, |
27 | unsigned long end) |
28 | { |
29 | struct mm_struct *mm = vma->vm_mm; |
30 | |
31 | if (mm->context.ptbase == current->active_mm->context.ptbase) |
32 | __vmclrmap((void *)start, end - start); |
33 | } |
34 | |
35 | /* |
36 | * Flush a page from the kernel virtual map - used by highmem |
37 | */ |
38 | void flush_tlb_one(unsigned long vaddr) |
39 | { |
40 | __vmclrmap((void *)vaddr, PAGE_SIZE); |
41 | } |
42 | |
43 | /* |
44 | * Flush all TLBs across all CPUs, virtual or real. |
45 | * A single Hexagon core has 6 thread contexts but |
46 | * only one TLB. |
47 | */ |
48 | void tlb_flush_all(void) |
49 | { |
50 | /* should probably use that fixaddr end or whateve label */ |
51 | __vmclrmap(0, 0xffff0000); |
52 | } |
53 | |
54 | /* |
55 | * Flush TLB entries associated with a given mm_struct mapping. |
56 | */ |
57 | void flush_tlb_mm(struct mm_struct *mm) |
58 | { |
59 | /* Current Virtual Machine has only one map active at a time */ |
60 | if (current->active_mm->context.ptbase == mm->context.ptbase) |
61 | tlb_flush_all(); |
62 | } |
63 | |
64 | /* |
65 | * Flush TLB state associated with a page of a vma. |
66 | */ |
67 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long vaddr) |
68 | { |
69 | struct mm_struct *mm = vma->vm_mm; |
70 | |
71 | if (mm->context.ptbase == current->active_mm->context.ptbase) |
72 | __vmclrmap((void *)vaddr, PAGE_SIZE); |
73 | } |
74 | |
75 | /* |
76 | * Flush TLB entries associated with a kernel address range. |
77 | * Like flush range, but without the check on the vma->vm_mm. |
78 | */ |
79 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
80 | { |
81 | __vmclrmap((void *)start, end - start); |
82 | } |
83 | |