source: rtems/c/src/lib/libcpu/powerpc/e500/mmu/mmu.c @ 010bf86

5
Last change on this file since 010bf86 was 010bf86, checked in by Chris Johns <chrisj@…>, on Jan 4, 2018 at 7:54:29 AM

bsps/powerpc: Use public include path

Update #3254.

  • Property mode set to 100644
File size: 17.8 KB
Line 
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
113static int initialized  = 0;
114
115E500_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 */
121static void
122myprintf(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
140void
141rtems_e500_dmptlbc(FILE *f)
142{
143int 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
166static void seltlb(rtems_e500_tlb_idx key)
167{
168int 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 */
199int
200rtems_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.= (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 */
289int rtems_e500_initlb()
290{
291int i;
292int 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
354int
355rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr)
356{
357uint32_t              mas1, mas2, mas3, mas4;
358uint32_t              tid, msk;
359int                   lkup;
360rtems_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 */
467int rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz)
468{
469int                  i;
470uint32_t             m,a;
471E500_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 */
519rtems_e500_tlb_idx
520rtems_e500_ftlb(uint32_t ea, int as)
521{
522uint32_t              pid, mas0, mas1;
523int                   i, rval = -1;
524rtems_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
555bail:
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 */
574int
575rtems_e500_clrtlb(rtems_e500_tlb_idx key)
576{
577rtems_e500_tlb_idx    k0;
578rtems_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}
Note: See TracBrowser for help on using the repository browser.