diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/cris/mm/tlb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/cris/mm/tlb.c')
-rw-r--r-- | arch/cris/mm/tlb.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c new file mode 100644 index 000000000000..23eca5ad7389 --- /dev/null +++ b/arch/cris/mm/tlb.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/mm/tlb.c | ||
3 | * | ||
4 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
5 | * | ||
6 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <asm/tlb.h> | ||
12 | |||
13 | #define D(x) | ||
14 | |||
15 | /* The TLB can host up to 64 different mm contexts at the same time. | ||
16 | * The running context is R_MMU_CONTEXT, and each TLB entry contains a | ||
17 | * page_id that has to match to give a hit. In page_id_map, we keep track | ||
18 | * of which mm's we have assigned which page_id's, so that we know when | ||
19 | * to invalidate TLB entries. | ||
20 | * | ||
21 | * The last page_id is never running - it is used as an invalid page_id | ||
22 | * so we can make TLB entries that will never match. | ||
23 | * | ||
24 | * Notice that we need to make the flushes atomic, otherwise an interrupt | ||
25 | * handler that uses vmalloced memory might cause a TLB load in the middle | ||
26 | * of a flush causing. | ||
27 | */ | ||
28 | |||
29 | struct mm_struct *page_id_map[NUM_PAGEID]; | ||
30 | static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ | ||
31 | |||
32 | /* | ||
33 | * Initialize the context related info for a new mm_struct | ||
34 | * instance. | ||
35 | */ | ||
36 | |||
37 | int | ||
38 | init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
39 | { | ||
40 | mm->context = NO_CONTEXT; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* the following functions are similar to those used in the PPC port */ | ||
45 | |||
46 | static inline void | ||
47 | alloc_context(struct mm_struct *mm) | ||
48 | { | ||
49 | struct mm_struct *old_mm; | ||
50 | |||
51 | D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); | ||
52 | |||
53 | /* did we replace an mm ? */ | ||
54 | |||
55 | old_mm = page_id_map[map_replace_ptr]; | ||
56 | |||
57 | if(old_mm) { | ||
58 | /* throw out any TLB entries belonging to the mm we replace | ||
59 | * in the map | ||
60 | */ | ||
61 | flush_tlb_mm(old_mm); | ||
62 | |||
63 | old_mm->context = NO_CONTEXT; | ||
64 | } | ||
65 | |||
66 | /* insert it into the page_id_map */ | ||
67 | |||
68 | mm->context = map_replace_ptr; | ||
69 | page_id_map[map_replace_ptr] = mm; | ||
70 | |||
71 | map_replace_ptr++; | ||
72 | |||
73 | if(map_replace_ptr == INVALID_PAGEID) | ||
74 | map_replace_ptr = 0; /* wrap around */ | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * if needed, get a new MMU context for the mm. otherwise nothing is done. | ||
79 | */ | ||
80 | |||
81 | void | ||
82 | get_mmu_context(struct mm_struct *mm) | ||
83 | { | ||
84 | if(mm->context == NO_CONTEXT) | ||
85 | alloc_context(mm); | ||
86 | } | ||
87 | |||
88 | /* called by __exit_mm to destroy the used MMU context if any before | ||
89 | * destroying the mm itself. this is only called when the last user of the mm | ||
90 | * drops it. | ||
91 | * | ||
92 | * the only thing we really need to do here is mark the used PID slot | ||
93 | * as empty. | ||
94 | */ | ||
95 | |||
96 | void | ||
97 | destroy_context(struct mm_struct *mm) | ||
98 | { | ||
99 | if(mm->context != NO_CONTEXT) { | ||
100 | D(printk("destroy_context %d (%p)\n", mm->context, mm)); | ||
101 | flush_tlb_mm(mm); /* TODO this might be redundant ? */ | ||
102 | page_id_map[mm->context] = NULL; | ||
103 | /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /* called once during VM initialization, from init.c */ | ||
108 | |||
109 | void __init | ||
110 | tlb_init(void) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | /* clear the page_id map */ | ||
115 | |||
116 | for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) | ||
117 | page_id_map[i] = NULL; | ||
118 | |||
119 | /* invalidate the entire TLB */ | ||
120 | |||
121 | flush_tlb_all(); | ||
122 | |||
123 | /* the init_mm has context 0 from the boot */ | ||
124 | |||
125 | page_id_map[0] = &init_mm; | ||
126 | } | ||