1 | /* |
---|
2 | * Routines to manipulate e500 TLBs; TLB0 (fixed 4k page size) |
---|
3 | * is not very useful so we mostly focus on TLB1 (variable page size). |
---|
4 | * |
---|
5 | * TLB0's 256 entries are 2-way set associative which means that |
---|
6 | * only 2 entries for page index numbers with matching 7 LSBs |
---|
7 | * are available. |
---|
8 | * |
---|
9 | * E.g., look at EA = 0xAAAyy000. 0xAAAyy is the page index. |
---|
10 | * |
---|
11 | * The least-significant 7 bits in 'yy' determine the 'way' |
---|
12 | * in the TLB 0 array. At most two EAs with matching 'yy' bits |
---|
13 | * (the 7 LSBs, that is) can be mapped with TLB0 since there |
---|
14 | * are only two entries per 'way'. |
---|
15 | * |
---|
16 | * Since this is a real-time OS we want to stay away from |
---|
17 | * software TLB replacement. |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
21 | * Authorship |
---|
22 | * ---------- |
---|
23 | * This software was created by |
---|
24 | * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, |
---|
25 | * Stanford Linear Accelerator Center, Stanford University. |
---|
26 | * |
---|
27 | * Acknowledgement of sponsorship |
---|
28 | * ------------------------------ |
---|
29 | * This software was produced by |
---|
30 | * the Stanford Linear Accelerator Center, Stanford University, |
---|
31 | * under Contract DE-AC03-76SFO0515 with the Department of Energy. |
---|
32 | * |
---|
33 | * Government disclaimer of liability |
---|
34 | * ---------------------------------- |
---|
35 | * Neither the United States nor the United States Department of Energy, |
---|
36 | * nor any of their employees, makes any warranty, express or implied, or |
---|
37 | * assumes any legal liability or responsibility for the accuracy, |
---|
38 | * completeness, or usefulness of any data, apparatus, product, or process |
---|
39 | * disclosed, or represents that its use would not infringe privately owned |
---|
40 | * rights. |
---|
41 | * |
---|
42 | * Stanford disclaimer of liability |
---|
43 | * -------------------------------- |
---|
44 | * Stanford University makes no representations or warranties, express or |
---|
45 | * implied, nor assumes any liability for the use of this software. |
---|
46 | * |
---|
47 | * Stanford disclaimer of copyright |
---|
48 | * -------------------------------- |
---|
49 | * Stanford University, owner of the copyright, hereby disclaims its |
---|
50 | * copyright and all other rights in this software. Hence, anyone may |
---|
51 | * freely use it for any purpose without restriction. |
---|
52 | * |
---|
53 | * Maintenance of notices |
---|
54 | * ---------------------- |
---|
55 | * In the interest of clarity regarding the origin and status of this |
---|
56 | * SLAC software, this and all the preceding Stanford University notices |
---|
57 | * are to remain affixed to any copy or derivative of this software made |
---|
58 | * or distributed by the recipient and are to be affixed to any copy of |
---|
59 | * software made or distributed by the recipient that contains a copy or |
---|
60 | * derivative of this software. |
---|
61 | * |
---|
62 | * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 |
---|
63 | */ |
---|
64 | |
---|
65 | /* 8450 MSR definitions; note that there are *substantial* differences |
---|
66 | * compared to classic powerpc; in particular, IS/DS are *different* |
---|
67 | * from IR/DR; the e500 MMU can not be switched off! |
---|
68 | * |
---|
69 | * Also: To disable/enable all external interrupts, CE and EE must both be |
---|
70 | * controlled. |
---|
71 | */ |
---|
72 | #include <rtems.h> |
---|
73 | #include <rtems/bspIo.h> |
---|
74 | #include <inttypes.h> |
---|
75 | #include <stdio.h> |
---|
76 | |
---|
77 | #include <libcpu/e500_mmu.h> |
---|
78 | |
---|
79 | #define TLBIVAX_TLBSEL (1<<(63-60)) |
---|
80 | #define TLBIVAX_INV_ALL (1<<(63-61)) |
---|
81 | |
---|
82 | #define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f) /* includes user bits */ |
---|
83 | #define E500_TLB_ATTR_WIMGE_GET(x) ((x)&0x7f) |
---|
84 | #define E500_TLB_ATTR_TS (1<<7) |
---|
85 | #define E500_TLB_ATTR_PERM(x) (((x)&0x3ff)<<8) |
---|
86 | #define E500_TLB_ATTR_PERM_GET(x) (((x)>>8)&0x3ff) |
---|
87 | #define E500_TLB_ATTR_TID(x) (((x)&0xfff)<<20) |
---|
88 | #define E500_TLB_ATTR_TID_GET(x) (((x)>>20)&0xfff) |
---|
89 | |
---|
90 | |
---|
91 | #ifdef DEBUG |
---|
92 | #define STATIC |
---|
93 | #else |
---|
94 | #define STATIC static |
---|
95 | #endif |
---|
96 | |
---|
97 | /* Factory to generate inline macros for accessing the MAS registers */ |
---|
98 | #define __RDWRMAS(mas,rmas) \ |
---|
99 | static inline uint32_t _read_MAS##mas(void) \ |
---|
100 | { uint32_t x; __asm__ volatile("mfspr %0, %1": "=r"(x):"i"(rmas)); return x; } \ |
---|
101 | static inline void _write_MAS##mas(uint32_t x) \ |
---|
102 | { __asm__ volatile("mtspr %1, %0":: "r"(x),"i"(rmas)); } |
---|
103 | |
---|
104 | __RDWRMAS(0,FSL_EIS_MAS0) |
---|
105 | __RDWRMAS(1,FSL_EIS_MAS1) |
---|
106 | __RDWRMAS(2,FSL_EIS_MAS2) |
---|
107 | __RDWRMAS(3,FSL_EIS_MAS3) |
---|
108 | __RDWRMAS(4,FSL_EIS_MAS4) |
---|
109 | __RDWRMAS(6,FSL_EIS_MAS6) |
---|
110 | |
---|
111 | #undef __RDWRMAS |
---|
112 | |
---|
113 | static int initialized = 0; |
---|
114 | |
---|
115 | E500_tlb_va_cache_t rtems_e500_tlb_va_cache[16]; |
---|
116 | |
---|
117 | /* Since it is likely that these routines are used during |
---|
118 | * early initialization when stdio is not available yet |
---|
119 | * we provide a helper that resorts to 'printk()' |
---|
120 | */ |
---|
121 | static void |
---|
122 | myprintf(FILE *f, char *fmt, ...) |
---|
123 | { |
---|
124 | va_list ap; |
---|
125 | va_start(ap, fmt); |
---|
126 | |
---|
127 | if (!f || !_impure_ptr->__sdidinit) { |
---|
128 | /* |
---|
129 | * Might be called at an early stage when |
---|
130 | * stdio is not yet initialized. |
---|
131 | */ |
---|
132 | vprintk(fmt,ap); |
---|
133 | } else { |
---|
134 | vfprintf(f,fmt,ap); |
---|
135 | } |
---|
136 | va_end(ap); |
---|
137 | } |
---|
138 | |
---|
139 | |
---|
140 | void |
---|
141 | rtems_e500_dmptlbc(FILE *f) |
---|
142 | { |
---|
143 | int i; |
---|
144 | if ( !initialized ) { |
---|
145 | myprintf(stderr,"TLB cache not initialized\n"); |
---|
146 | return; |
---|
147 | } |
---|
148 | for ( i=0; i<16; i++ ) { |
---|
149 | if ( !rtems_e500_tlb_va_cache[i].att.v ) |
---|
150 | continue; |
---|
151 | myprintf(f,"#%2i: TID 0x%03x, TS %i, ea 0x%08x .. 0x%08x\n", |
---|
152 | i, |
---|
153 | rtems_e500_tlb_va_cache[i].va.va_tid, |
---|
154 | rtems_e500_tlb_va_cache[i].att.ts, |
---|
155 | rtems_e500_tlb_va_cache[i].va.va_epn<<12, |
---|
156 | (rtems_e500_tlb_va_cache[i].va.va_epn<<12) + (1024<<(2*rtems_e500_tlb_va_cache[i].att.sz))-1); |
---|
157 | myprintf(f,"PA 0x%08"PRIx32", PERM 0x%03x, WIMGE 0x%02x\n", |
---|
158 | rtems_e500_tlb_va_cache[i].rpn<<12, |
---|
159 | rtems_e500_tlb_va_cache[i].att.perm, |
---|
160 | rtems_e500_tlb_va_cache[i].att.wimge); |
---|
161 | } |
---|
162 | } |
---|
163 | |
---|
164 | #define E500_SELTLB_1 0x1000 |
---|
165 | |
---|
166 | static void seltlb(rtems_e500_tlb_idx key) |
---|
167 | { |
---|
168 | int idx = key & ~E500_SELTLB_1; |
---|
169 | |
---|
170 | if ( key & E500_SELTLB_1 ) { |
---|
171 | _write_MAS0( FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(idx) ); |
---|
172 | } else { |
---|
173 | _write_MAS0( (idx & 128) ? FSL_EIS_MAS0_ESEL(1) : FSL_EIS_MAS0_ESEL(0) ); |
---|
174 | _write_MAS2( FSL_EIS_MAS2_EPN( idx & 127 ) ); |
---|
175 | } |
---|
176 | } |
---|
177 | |
---|
178 | /* |
---|
179 | * Read a TLB entry from the hardware; if it is a TLB1 entry |
---|
180 | * then the current settings are stored in the |
---|
181 | * rtems_e500_tlb_va_cache[] structure. |
---|
182 | * |
---|
183 | * The routine can perform this operation quietly or |
---|
184 | * print information to a file. |
---|
185 | * |
---|
186 | * 'sel': which TLB array to use; TLB0 (4k) if zero, |
---|
187 | * TLB1 (variable) if nonzero. |
---|
188 | * 'idx': which TLB entry to access. |
---|
189 | * 'quiet': perform operation silently (no info printed) |
---|
190 | * if nonzero. |
---|
191 | * 'f': open FILE where to print information. May be |
---|
192 | * NULL in which case 'stdout' is used. |
---|
193 | * |
---|
194 | * RETURNS: |
---|
195 | * 0: success; TLB entry is VALID |
---|
196 | * +1: success but TLB entry is INVALID |
---|
197 | * < 0: error (-1: invalid argument) |
---|
198 | */ |
---|
199 | int |
---|
200 | rtems_e500_prtlb(rtems_e500_tlb_idx key, int quiet, FILE *f) |
---|
201 | { |
---|
202 | uint32_t mas1, mas2, mas3; |
---|
203 | rtems_interrupt_level lvl; |
---|
204 | E500_tlb_va_cache_t *tlb; |
---|
205 | E500_tlb_va_cache_t buf; |
---|
206 | int sel, idx; |
---|
207 | |
---|
208 | sel = (key & E500_SELTLB_1) ? 1 : 0; |
---|
209 | idx = key & ~E500_SELTLB_1; |
---|
210 | |
---|
211 | if ( idx < 0 || idx > 255 || ( idx > 15 && sel ) ) |
---|
212 | return -1; |
---|
213 | |
---|
214 | rtems_interrupt_disable(lvl); |
---|
215 | |
---|
216 | seltlb( key ); |
---|
217 | |
---|
218 | asm volatile("tlbre"); |
---|
219 | |
---|
220 | /* not manipulating MAS0, skip reading it */ |
---|
221 | mas1 = _read_MAS1(); |
---|
222 | mas2 = _read_MAS2(); |
---|
223 | mas3 = _read_MAS3(); |
---|
224 | |
---|
225 | rtems_interrupt_enable(lvl); |
---|
226 | |
---|
227 | tlb = sel ? rtems_e500_tlb_va_cache + idx : &buf; |
---|
228 | |
---|
229 | if ( (tlb->att.v = (FSL_EIS_MAS1_V & mas1) ? 1 : 0) ) { |
---|
230 | tlb->va.va_epn = FSL_EIS_MAS2_EPN_GET(mas2); |
---|
231 | tlb->rpn = FSL_EIS_MAS3_RPN_GET(mas3); |
---|
232 | tlb->va.va_tid = FSL_EIS_MAS1_TID_GET(mas1); |
---|
233 | tlb->att.ts = (FSL_EIS_MAS1_TS & mas1) ? 1 : 0; |
---|
234 | tlb->att.sz = sel ? FSL_EIS_MAS1_TSIZE_GET(mas1) : 1 /* 4k size */; |
---|
235 | tlb->att.wimge = FSL_EIS_MAS2_ATTR_GET(mas2); |
---|
236 | tlb->att.perm = FSL_EIS_MAS3_PERM_GET(mas3); |
---|
237 | } |
---|
238 | |
---|
239 | if ( tlb->att.v ) { |
---|
240 | if ( !quiet ) { |
---|
241 | /* |
---|
242 | "TLB[1] Entry # 0 spans EA range 0x00000000 .. 0x00000000 |
---|
243 | "Mapping: VA [TS 0/TID 0x00/EPN 0x00000] -> RPN 0x00000" |
---|
244 | "Size: TSIZE 0x0 ( 4^ts KiB = 000000 KiB = 0x00000000 B) |
---|
245 | "Attributes: PERM 0x000 (ux/sx/uw/sw/ur/sr) WIMGE 0x00 IPROT 0" |
---|
246 | */ |
---|
247 | myprintf(f, |
---|
248 | "TLB[%i] Entry # %d spans EA range 0x%08x .. 0x%08x\r\n", |
---|
249 | sel, |
---|
250 | idx, |
---|
251 | (tlb->va.va_epn << 12), |
---|
252 | (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1 |
---|
253 | ); |
---|
254 | |
---|
255 | myprintf(f, |
---|
256 | "Mapping: VA [TS %d/TID 0x%02x/EPN 0x%05x] -> RPN 0x%05"PRIx32"\r\n", |
---|
257 | tlb->att.ts, tlb->va.va_tid, tlb->va.va_epn, tlb->rpn |
---|
258 | ); |
---|
259 | myprintf(f, |
---|
260 | "Size: TSIZE 0x%x ( 4^ts KiB = %6d KiB = 0x%08x B)\r\n", |
---|
261 | tlb->att.sz, (1<<(2*tlb->att.sz)), (1024<<(2*tlb->att.sz)) |
---|
262 | ); |
---|
263 | myprintf(f, |
---|
264 | "Attributes: PERM 0x%03x (ux/sx/uw/sw/ur/sr) WIMGE 0x%02x IPROT %i\r\n", |
---|
265 | tlb->att.perm, tlb->att.wimge, (sel && (mas1 & FSL_EIS_MAS1_IPROT) ? 1 : 0) |
---|
266 | ); |
---|
267 | myprintf(f, |
---|
268 | "EA range 0x%08x .. 0x%08x\r\n", |
---|
269 | (tlb->va.va_epn << 12), |
---|
270 | (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1 |
---|
271 | ); |
---|
272 | } |
---|
273 | } else { |
---|
274 | if ( !quiet ) { |
---|
275 | myprintf(f, "TLB[%i] Entry #%i <OFF> (size 0x%x = 0x%xb)\n", sel, idx, tlb->att.sz, (1024<<(2*tlb->att.sz))); |
---|
276 | } |
---|
277 | return 1; |
---|
278 | } |
---|
279 | return 0; |
---|
280 | } |
---|
281 | |
---|
282 | /* Initialize cache; verify that TLB0 is unused; |
---|
283 | * |
---|
284 | * RETURNS: zero on success, nonzero on error (TLB0 |
---|
285 | * seems to be in use); in this case the |
---|
286 | * driver will refuse to change TLB1 entries |
---|
287 | * (other than disabling them). |
---|
288 | */ |
---|
289 | int rtems_e500_initlb() |
---|
290 | { |
---|
291 | int i; |
---|
292 | int rval = 0; |
---|
293 | for (i=0; i<16; i++) |
---|
294 | rtems_e500_prtlb(E500_SELTLB_1 | i, 1, 0); |
---|
295 | for (i=0; i<256; i++) { |
---|
296 | /* refuse to enable operations that change TLB entries |
---|
297 | * if anything in TLB[0] is valid (because we currently |
---|
298 | * don't check against overlap with TLB[0] when we |
---|
299 | * write a new entry). |
---|
300 | */ |
---|
301 | if ( rtems_e500_prtlb(E500_SELTLB_0 | i, 1, 0) <=0 ) { |
---|
302 | myprintf(stderr,"WARNING: 4k TLB #%i seems to be valid; UNSUPPORTED configuration\n", i); |
---|
303 | rval = -1; |
---|
304 | } |
---|
305 | } |
---|
306 | if ( !rval ) |
---|
307 | initialized = 1; |
---|
308 | return rval; |
---|
309 | } |
---|
310 | |
---|
311 | /* |
---|
312 | * Write TLB1 entry (can also be used to disable an entry). |
---|
313 | * |
---|
314 | * The routine checks against the cached data in |
---|
315 | * rtems_e500_tlb_va[] to prevent the user from generating |
---|
316 | * overlapping entries. |
---|
317 | * |
---|
318 | * 'idx': TLB 1 entry # to manipulate |
---|
319 | * 'ea': Effective address (must be page aligned) |
---|
320 | * 'pa': Physical address (must be page aligned) |
---|
321 | * 'sz': Page size selector; page size is |
---|
322 | * 1024 * 2^(2*sz) bytes. |
---|
323 | * 'sz' may also be one of the following: |
---|
324 | * - page size in bytes ( >= 1024 ); the selector |
---|
325 | * value is then computed by this routine. |
---|
326 | * However, 'sz' must be a valid page size |
---|
327 | * or -1 will be returned. |
---|
328 | * - a value < 0 to invalidate/disable the |
---|
329 | * TLB entry. |
---|
330 | * 'attr': Page attributes; ORed combination of WIMGE, |
---|
331 | * PERMissions, TID and TS. Use ATTR_xxx macros |
---|
332 | * |
---|
333 | * RETURNS: 0 on success, nonzero on error: |
---|
334 | * |
---|
335 | * >0: requested mapping would overlap with |
---|
336 | * existing mapping in other entry. Return |
---|
337 | * value gives conflicting entry + 1; i.e., |
---|
338 | * if a value of 4 is returned then the request |
---|
339 | * conflicts with existing mapping in entry 3. |
---|
340 | * -1: invalid argument |
---|
341 | * -3: driver not initialized (or initialization |
---|
342 | * failed because TLB0 is in use). |
---|
343 | * <0: other error |
---|
344 | * |
---|
345 | */ |
---|
346 | #define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f) /* includes user bits */ |
---|
347 | #define E500_TLB_ATTR_WIMGE_GET(x) ((x)&0x7f) |
---|
348 | #define E500_TLB_ATTR_TS (1<<7) |
---|
349 | #define E500_TLB_ATTR_PERM(x) (((x)&0x3ff)<<8) |
---|
350 | #define E500_TLB_ATTR_PERM_GET(x) (((x)>>8)&0x3ff) |
---|
351 | #define E500_TLB_ATTR_TID(x) (((x)&0xfff)<<20) |
---|
352 | #define E500_TLB_ATTR_TID_GET(x) (((x)>>20)&0xfff) |
---|
353 | |
---|
354 | int |
---|
355 | rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr) |
---|
356 | { |
---|
357 | uint32_t mas1, mas2, mas3, mas4; |
---|
358 | uint32_t tid, msk; |
---|
359 | int lkup; |
---|
360 | rtems_interrupt_level lvl; |
---|
361 | |
---|
362 | if ( sz >= 1024 ) { |
---|
363 | /* Assume they literally specify a size */ |
---|
364 | msk = sz; |
---|
365 | sz = 0; |
---|
366 | while ( msk != (1024<<(2*sz)) ) { |
---|
367 | if ( ++sz > 15 ) { |
---|
368 | return -1; |
---|
369 | } |
---|
370 | } |
---|
371 | /* OK, acceptable */ |
---|
372 | } |
---|
373 | |
---|
374 | msk = sz > 0 ? (1024<<(2*sz)) - 1 : 0; |
---|
375 | |
---|
376 | if ( !initialized && sz > 0 ) { |
---|
377 | myprintf(stderr,"TLB driver not initialized; refuse to enable any entry\n"); |
---|
378 | return -3; |
---|
379 | } |
---|
380 | |
---|
381 | if ( (ea & msk) || (pa & msk) ) { |
---|
382 | myprintf(stderr,"Misaligned ea or pa\n"); |
---|
383 | return -1; |
---|
384 | } |
---|
385 | |
---|
386 | if ( idx < 0 || idx > 15 ) |
---|
387 | return -1; |
---|
388 | |
---|
389 | if ( sz > 15 ) { |
---|
390 | /* but e500v1 doesn't support all 16 sizes!! */ |
---|
391 | /* FIXME: we should inquire about this CPU's |
---|
392 | * capabilities... |
---|
393 | */ |
---|
394 | return -1; |
---|
395 | } |
---|
396 | |
---|
397 | tid = E500_TLB_ATTR_TID_GET(attr); |
---|
398 | |
---|
399 | mas1 = (attr & E500_TLB_ATTR_TS) ? FSL_EIS_MAS1_TS : 0; |
---|
400 | |
---|
401 | if ( sz >=0 ) { |
---|
402 | lkup = rtems_e500_matchtlb(ea, tid, mas1, sz); |
---|
403 | |
---|
404 | if ( lkup < -1 ) { |
---|
405 | /* some error */ |
---|
406 | return lkup; |
---|
407 | } |
---|
408 | |
---|
409 | if ( lkup >= 0 && lkup != idx ) { |
---|
410 | myprintf(stderr,"TLB[1] #%i overlaps with requested mapping\n", lkup); |
---|
411 | rtems_e500_prtlb( E500_SELTLB_1 | lkup, 0, stderr); |
---|
412 | return lkup+1; |
---|
413 | } |
---|
414 | } |
---|
415 | |
---|
416 | /* OK to proceed */ |
---|
417 | mas1 |= FSL_EIS_MAS1_IPROT | FSL_EIS_MAS1_TID(tid); |
---|
418 | |
---|
419 | if ( sz >= 0 ) |
---|
420 | mas1 |= FSL_EIS_MAS1_V | FSL_EIS_MAS1_TSIZE(sz); |
---|
421 | |
---|
422 | mas2 = FSL_EIS_MAS2_EPN( ea>>12 ) | E500_TLB_ATTR_WIMGE(attr); |
---|
423 | mas3 = FSL_EIS_MAS3_RPN( pa>>12 ) | E500_TLB_ATTR_PERM_GET(attr); |
---|
424 | /* mas4 is not really relevant; we don't use TLB replacement */ |
---|
425 | mas4 = FSL_EIS_MAS4_TLBSELD | FSL_EIS_MAS4_TIDSELD(0) | FSL_EIS_MAS4_TSIZED(9) | FSL_EIS_MAS4_ID | FSL_EIS_MAS4_GD; |
---|
426 | |
---|
427 | rtems_interrupt_disable(lvl); |
---|
428 | |
---|
429 | seltlb(idx | E500_SELTLB_1); |
---|
430 | |
---|
431 | _write_MAS1(mas1); |
---|
432 | _write_MAS2(mas2); |
---|
433 | _write_MAS3(mas3); |
---|
434 | _write_MAS4(mas4); |
---|
435 | |
---|
436 | asm volatile( |
---|
437 | " sync\n" |
---|
438 | " isync\n" |
---|
439 | " tlbwe\n" |
---|
440 | " sync\n" |
---|
441 | " isync\n" |
---|
442 | ); |
---|
443 | |
---|
444 | rtems_interrupt_enable(lvl); |
---|
445 | |
---|
446 | /* update cache */ |
---|
447 | rtems_e500_prtlb( E500_SELTLB_1 | idx, 1, 0); |
---|
448 | |
---|
449 | return 0; |
---|
450 | } |
---|
451 | |
---|
452 | /* |
---|
453 | * Check if a ts/tid/ea/sz mapping overlaps |
---|
454 | * with an existing entry. |
---|
455 | * |
---|
456 | * ASSUMPTION: all TLB0 (fixed 4k pages) are invalid and always unused. |
---|
457 | * |
---|
458 | * NOTE: 'sz' is the 'logarithmic' size selector; the page size |
---|
459 | * is 1024*2^(2*sz). |
---|
460 | * |
---|
461 | * RETURNS: |
---|
462 | * >= 0: index of TLB1 entry that already provides a mapping |
---|
463 | * which overlaps within the ea range. |
---|
464 | * -1: SUCCESS (no conflicting entry found) |
---|
465 | * <=-2: ERROR (invalid input) |
---|
466 | */ |
---|
467 | int rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz) |
---|
468 | { |
---|
469 | int i; |
---|
470 | uint32_t m,a; |
---|
471 | E500_tlb_va_cache_t *tlb; |
---|
472 | |
---|
473 | if ( sz < 0 || sz > 15 ) |
---|
474 | return -4; |
---|
475 | |
---|
476 | sz = (1024<<(2*sz)); |
---|
477 | |
---|
478 | if ( !initialized ) { |
---|
479 | /* cache not initialized */ |
---|
480 | return -3; |
---|
481 | } |
---|
482 | |
---|
483 | if ( ea & (sz-1) ) { |
---|
484 | /* misaligned ea */ |
---|
485 | return -2; |
---|
486 | } |
---|
487 | |
---|
488 | if ( ts ) |
---|
489 | ts = 1; |
---|
490 | |
---|
491 | for ( i=0, tlb=rtems_e500_tlb_va_cache; i<16; i++, tlb++ ) { |
---|
492 | if ( ! tlb->att.v ) |
---|
493 | continue; |
---|
494 | if ( tlb->att.ts != ts ) |
---|
495 | continue; |
---|
496 | if ( tlb->va.va_tid && tlb->va.va_tid != tid ) |
---|
497 | continue; |
---|
498 | /* TID and TS match a valid entry */ |
---|
499 | m = (1024<<(2*tlb->att.sz)) - 1; |
---|
500 | /* calculate starting address of this entry */ |
---|
501 | a = tlb->va.va_epn<<12; |
---|
502 | if ( ea <= a + m && ea + sz -1 >= a ) { |
---|
503 | /* overlap */ |
---|
504 | return i; |
---|
505 | } |
---|
506 | } |
---|
507 | return -1; |
---|
508 | } |
---|
509 | |
---|
510 | /* Find TLB index that maps 'ea/as' combination |
---|
511 | * |
---|
512 | * RETURNS: index 'key'; i.e., the index number plus |
---|
513 | * a bit (E500_SELTLB_1) which indicates whether |
---|
514 | * the mapping was found in TLB0 (4k fixed page |
---|
515 | * size) or in TLB1 (variable page size). |
---|
516 | * |
---|
517 | * On error (no mapping) -1 is returned. |
---|
518 | */ |
---|
519 | rtems_e500_tlb_idx |
---|
520 | rtems_e500_ftlb(uint32_t ea, int as) |
---|
521 | { |
---|
522 | uint32_t pid, mas0, mas1; |
---|
523 | int i, rval = -1; |
---|
524 | rtems_interrupt_level lvl; |
---|
525 | |
---|
526 | rtems_interrupt_disable(lvl); |
---|
527 | |
---|
528 | for ( i=0; i<3; i++ ) { |
---|
529 | switch (i) { |
---|
530 | case 0: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID0)); break; |
---|
531 | case 1: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID1)); break; |
---|
532 | case 2: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID2)); break; |
---|
533 | default: |
---|
534 | goto bail; |
---|
535 | } |
---|
536 | |
---|
537 | _write_MAS6( FSL_EIS_MAS6_SPID0(pid) | (as ? FSL_EIS_MAS6_SAS : 0 ) ); |
---|
538 | |
---|
539 | asm volatile("tlbsx 0, %0"::"r"(ea)); |
---|
540 | |
---|
541 | mas1 = _read_MAS1(); |
---|
542 | |
---|
543 | if ( (FSL_EIS_MAS1_V & mas1) ) { |
---|
544 | mas0 = _read_MAS0(); |
---|
545 | if ( FSL_EIS_MAS0_TLBSEL & mas0 ) { |
---|
546 | /* TLB1 */ |
---|
547 | rval = FSL_EIS_MAS0_ESEL_GET(mas0) | E500_SELTLB_1; |
---|
548 | } else { |
---|
549 | rval = (ea >> (63-51)) | (( FSL_EIS_MAS0_NV & mas0 ) ? 180 : 0 ) ; |
---|
550 | } |
---|
551 | break; |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | bail: |
---|
556 | rtems_interrupt_enable(lvl); |
---|
557 | return rval; |
---|
558 | } |
---|
559 | |
---|
560 | /* Mark TLB entry as invalid ('disabled'). Unlike |
---|
561 | * rtems_e500_wrtlb() with a negative size argument |
---|
562 | * this routine also can disable TLB0 entries. |
---|
563 | * |
---|
564 | * 'key': TLB entry (index) ORed with selector bit |
---|
565 | * (0 for TLB0, E500_SELTLB_1 for TLB1). |
---|
566 | * |
---|
567 | * RETURNS: zero on success, nonzero on error (TLB |
---|
568 | * unchanged). |
---|
569 | * |
---|
570 | * NOTE: If a TLB1 entry is disabled the associated |
---|
571 | * entry in rtems_e500_va_cache[] is also |
---|
572 | * marked as disabled. |
---|
573 | */ |
---|
574 | int |
---|
575 | rtems_e500_clrtlb(rtems_e500_tlb_idx key) |
---|
576 | { |
---|
577 | rtems_e500_tlb_idx k0; |
---|
578 | rtems_interrupt_level lvl; |
---|
579 | |
---|
580 | /* minimal guard against bad key */ |
---|
581 | if ( key < 0 ) |
---|
582 | return -1; |
---|
583 | |
---|
584 | if ( (key & E500_SELTLB_1) ) { |
---|
585 | if ( (key & ~E500_SELTLB_1) > 15 ) { |
---|
586 | myprintf(stderr,"Invalid TLB index; TLB1 index must be < 16\n"); |
---|
587 | return -1; |
---|
588 | } |
---|
589 | } else if ( key > 255 ) { |
---|
590 | myprintf(stderr,"Invalid TLB index; TLB0 index must be < 256\n"); |
---|
591 | return -1; |
---|
592 | } |
---|
593 | |
---|
594 | /* Must not invalidate page 0 which holds vectors, text etc... */ |
---|
595 | k0 = rtems_e500_ftlb(0, 0); |
---|
596 | if ( -1 == k0 ) { |
---|
597 | myprintf(stderr,"tlbivax; something's fishy - I don't find mapping for addr. 0\n"); |
---|
598 | return -1; |
---|
599 | } |
---|
600 | |
---|
601 | /* NOTE: we assume PID is ignored, and AS is 0 */ |
---|
602 | if ( k0 == key ) { |
---|
603 | myprintf(stderr,"Refuse to invalidate page holding addr 0 (always needed)\n"); |
---|
604 | return -1; |
---|
605 | } |
---|
606 | |
---|
607 | rtems_interrupt_disable(lvl); |
---|
608 | |
---|
609 | seltlb(key); |
---|
610 | |
---|
611 | asm volatile("tlbre"); |
---|
612 | |
---|
613 | /* read old entries */ |
---|
614 | _write_MAS1( _read_MAS1() & ~FSL_EIS_MAS1_V ); |
---|
615 | |
---|
616 | asm volatile( |
---|
617 | " sync\n" |
---|
618 | " isync\n" |
---|
619 | " tlbwe\n" |
---|
620 | " sync\n" |
---|
621 | " isync\n" |
---|
622 | ); |
---|
623 | |
---|
624 | /* update cache */ |
---|
625 | if ( E500_SELTLB_1 & key ) |
---|
626 | rtems_e500_tlb_va_cache[ (~E500_SELTLB_1 & key) ].att.v = 0; |
---|
627 | |
---|
628 | rtems_interrupt_enable(lvl); |
---|
629 | |
---|
630 | return 0; |
---|
631 | } |
---|