Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /*
0002  * Routines to manipulate e500 TLBs; TLB0 (fixed 4k page size)
0003  * is not very useful so we mostly focus on TLB1 (variable page size).
0004  *
0005  * TLB0's 256 entries are 2-way set associative which means that
0006  *        only 2 entries for page index numbers with matching 7 LSBs
0007  *        are available.
0008  *
0009  *        E.g., look at EA = 0xAAAyy000. 0xAAAyy is the page index.
0010  *
0011  *        The least-significant 7 bits in 'yy' determine the 'way'
0012  *        in the TLB 0 array. At most two EAs with matching 'yy' bits
0013  *        (the 7 LSBs, that is) can be mapped with TLB0 since there
0014  *        are only two entries per 'way'.
0015  *
0016  *        Since this is a real-time OS we want to stay away from
0017  *        software TLB replacement.
0018  */
0019 
0020 /*
0021  * Authorship
0022  * ----------
0023  * This software was created by
0024  *     Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
0025  *      Stanford Linear Accelerator Center, Stanford University.
0026  *
0027  * Acknowledgement of sponsorship
0028  * ------------------------------
0029  * This software was produced by
0030  *     the Stanford Linear Accelerator Center, Stanford University,
0031  *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
0032  *
0033  * Government disclaimer of liability
0034  * ----------------------------------
0035  * Neither the United States nor the United States Department of Energy,
0036  * nor any of their employees, makes any warranty, express or implied, or
0037  * assumes any legal liability or responsibility for the accuracy,
0038  * completeness, or usefulness of any data, apparatus, product, or process
0039  * disclosed, or represents that its use would not infringe privately owned
0040  * rights.
0041  *
0042  * Stanford disclaimer of liability
0043  * --------------------------------
0044  * Stanford University makes no representations or warranties, express or
0045  * implied, nor assumes any liability for the use of this software.
0046  *
0047  * Stanford disclaimer of copyright
0048  * --------------------------------
0049  * Stanford University, owner of the copyright, hereby disclaims its
0050  * copyright and all other rights in this software.  Hence, anyone may
0051  * freely use it for any purpose without restriction.
0052  *
0053  * Maintenance of notices
0054  * ----------------------
0055  * In the interest of clarity regarding the origin and status of this
0056  * SLAC software, this and all the preceding Stanford University notices
0057  * are to remain affixed to any copy or derivative of this software made
0058  * or distributed by the recipient and are to be affixed to any copy of
0059  * software made or distributed by the recipient that contains a copy or
0060  * derivative of this software.
0061  *
0062  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0063  */
0064 
0065 /* 8450 MSR definitions; note that there are *substantial* differences
0066  * compared to classic powerpc; in particular, IS/DS are *different*
0067  * from IR/DR; the e500 MMU can not be switched off!
0068  *
0069  * Also: To disable/enable all external interrupts, CE and EE must both be
0070  *       controlled.
0071  */
0072 #include <rtems.h>
0073 #include <rtems/bspIo.h>
0074 #include <rtems/score/sysstate.h>
0075 #include <inttypes.h>
0076 #include <stdio.h>
0077 
0078 #include <libcpu/e500_mmu.h>
0079 #include <libcpu/powerpc-utility.h>
0080 
0081 #define TLBIVAX_TLBSEL  (1<<(63-60))
0082 #define TLBIVAX_INV_ALL  (1<<(63-61))
0083 
0084 #define E500_TLB_ATTR_WIMGE(x)      ((x)&0x7f)        /* includes user bits */
0085 #define E500_TLB_ATTR_WIMGE_GET(x)  ((x)&0x7f)
0086 #define E500_TLB_ATTR_TS            (1<<7)
0087 #define E500_TLB_ATTR_PERM(x)     (((x)&0x3ff)<<8)
0088 #define E500_TLB_ATTR_PERM_GET(x)   (((x)>>8)&0x3ff)
0089 #define E500_TLB_ATTR_TID(x)        (((x)&0xfff)<<20)
0090 #define E500_TLB_ATTR_TID_GET(x)    (((x)>>20)&0xfff)
0091 
0092 
0093 #ifdef DEBUG
0094 #define STATIC
0095 #else
0096 #define STATIC static
0097 #endif
0098 
0099 /* Factory to generate inline macros for accessing the MAS registers */
0100 #define __RDWRMAS(mas,rmas)  \
0101   static inline uint32_t _read_MAS##mas(void)                                   \
0102   { uint32_t x; __asm__ volatile("mfspr %0, %1": "=r"(x):"i"(rmas)); return x; } \
0103   static inline void _write_MAS##mas(uint32_t x)                             \
0104   {             __asm__ volatile("mtspr %1, %0":: "r"(x),"i"(rmas)); }
0105 
0106 __RDWRMAS(0,FSL_EIS_MAS0)
0107 __RDWRMAS(1,FSL_EIS_MAS1)
0108 __RDWRMAS(2,FSL_EIS_MAS2)
0109 __RDWRMAS(3,FSL_EIS_MAS3)
0110 __RDWRMAS(4,FSL_EIS_MAS4)
0111 __RDWRMAS(6,FSL_EIS_MAS6)
0112 
0113 #undef __RDWRMAS
0114 
0115 static int initialized  = 0;
0116 
0117 E500_tlb_va_cache_t rtems_e500_tlb_va_cache[16];
0118 
0119 /* Since it is likely that these routines are used during
0120  * early initialization when stdio is not available yet
0121  * we provide a helper that resorts to 'printk()'
0122  */
0123 static void
0124 myprintf(FILE *f, char *fmt, ...)
0125 {
0126   va_list ap;
0127   va_start(ap, fmt);
0128 
0129   if (!f || !_System_state_Is_up(_System_state_Get())) {
0130       /*
0131        * Might be called at an early stage when
0132        * stdio is not yet initialized.
0133        */
0134       vprintk(fmt,ap);
0135   } else {
0136       vfprintf(f,fmt,ap);
0137   }
0138   va_end(ap);
0139 }
0140 
0141 
0142 void
0143 rtems_e500_dmptlbc(FILE *f)
0144 {
0145 int i;
0146   if ( !initialized ) {
0147     myprintf(stderr,"TLB cache not initialized\n");
0148     return;
0149   }
0150   for ( i=0; i<16; i++ ) {
0151     if ( !rtems_e500_tlb_va_cache[i].att.v )
0152       continue;
0153     myprintf(f,"#%2i: TID 0x%03x, TS %i, ea 0x%08x .. 0x%08x\n",
0154       i,
0155       rtems_e500_tlb_va_cache[i].va.va_tid,
0156       rtems_e500_tlb_va_cache[i].att.ts,
0157       rtems_e500_tlb_va_cache[i].va.va_epn<<12,
0158       (rtems_e500_tlb_va_cache[i].va.va_epn<<12) + (1024<<(2*rtems_e500_tlb_va_cache[i].att.sz))-1);
0159     myprintf(f,"PA 0x%08"PRIx32", PERM 0x%03x, WIMGE 0x%02x\n",
0160       rtems_e500_tlb_va_cache[i].rpn<<12,
0161       rtems_e500_tlb_va_cache[i].att.perm,
0162       rtems_e500_tlb_va_cache[i].att.wimge);
0163   }
0164 }
0165 
0166 #define E500_SELTLB_1  0x1000
0167 
0168 static void seltlb(rtems_e500_tlb_idx key)
0169 {
0170 int idx = key & ~E500_SELTLB_1;
0171 
0172   if ( key & E500_SELTLB_1 ) {
0173     _write_MAS0( FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(idx) );
0174   } else {
0175     _write_MAS0( (idx & 128) ? FSL_EIS_MAS0_ESEL(1) : FSL_EIS_MAS0_ESEL(0) );
0176     _write_MAS2( FSL_EIS_MAS2_EPN( idx & 127 ) );
0177   }
0178 }
0179 
0180 /*
0181  * Read a TLB entry from the hardware; if it is a TLB1 entry
0182  * then the current settings are stored in the
0183  * rtems_e500_tlb_va_cache[] structure.
0184  *
0185  * The routine can perform this operation quietly or
0186  * print information to a file.
0187  *
0188  *   'sel': which TLB array to use; TLB0 (4k) if zero,
0189  *          TLB1 (variable) if nonzero.
0190  *   'idx': which TLB entry to access.
0191  * 'quiet': perform operation silently (no info printed)
0192  *          if nonzero.
0193  *     'f': open FILE where to print information. May be
0194  *          NULL in which case 'stdout' is used.
0195  *
0196  * RETURNS:
0197  *       0: success; TLB entry is VALID
0198  *      +1: success but TLB entry is INVALID
0199  *     < 0: error (-1: invalid argument)
0200  */
0201 int
0202 rtems_e500_prtlb(rtems_e500_tlb_idx key, int quiet, FILE *f)
0203 {
0204   uint32_t               mas1, mas2, mas3;
0205   rtems_interrupt_level  lvl;
0206   E500_tlb_va_cache_t   *tlb;
0207   E500_tlb_va_cache_t    buf;
0208   int                    sel, idx;
0209 
0210   sel = (key &  E500_SELTLB_1) ? 1 : 0;
0211   idx = key & ~E500_SELTLB_1;
0212 
0213   if ( idx < 0 || idx > 255 || ( idx > 15 && sel ) )
0214     return -1;
0215 
0216   rtems_interrupt_disable(lvl);
0217 
0218   seltlb( key );
0219 
0220   ppc_tlbre();
0221 
0222   /* not manipulating MAS0, skip reading it */
0223   mas1 = _read_MAS1();
0224   mas2 = _read_MAS2();
0225   mas3 = _read_MAS3();
0226 
0227   rtems_interrupt_enable(lvl);
0228 
0229   tlb = sel ? rtems_e500_tlb_va_cache + idx : &buf;
0230 
0231   if ( (tlb->att.v  = (FSL_EIS_MAS1_V & mas1) ? 1 : 0) ) {
0232     tlb->va.va_epn = FSL_EIS_MAS2_EPN_GET(mas2);
0233     tlb->rpn       = FSL_EIS_MAS3_RPN_GET(mas3);
0234     tlb->va.va_tid = FSL_EIS_MAS1_TID_GET(mas1);
0235     tlb->att.ts    = (FSL_EIS_MAS1_TS & mas1) ? 1 : 0;
0236     tlb->att.sz    = sel ? FSL_EIS_MAS1_TSIZE_GET(mas1) : 1 /* 4k size */;
0237     tlb->att.wimge = FSL_EIS_MAS2_ATTR_GET(mas2);
0238     tlb->att.perm  = FSL_EIS_MAS3_PERM_GET(mas3);
0239   }
0240 
0241   if ( tlb->att.v ) {
0242     if ( !quiet ) {
0243 /*
0244       "TLB[1] Entry # 0 spans EA range     0x00000000 .. 0x00000000
0245       "Mapping:    VA     [TS 0/TID 0x00/EPN 0x00000] -> RPN 0x00000"
0246       "Size:       TSIZE  0x0 ( 4^ts KiB = 000000 KiB = 0x00000000 B)
0247       "Attributes: PERM 0x000 (ux/sx/uw/sw/ur/sr) WIMGE 0x00 IPROT 0"
0248 */
0249       myprintf(f,
0250         "TLB[%i] Entry # %d spans EA range     0x%08x .. 0x%08x\r\n",
0251         sel,
0252         idx,
0253         (tlb->va.va_epn << 12),
0254         (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1
0255       );
0256 
0257       myprintf(f,
0258         "Mapping:    VA     [TS %d/TID 0x%02x/EPN 0x%05x] -> RPN 0x%05"PRIx32"\r\n",
0259         tlb->att.ts, tlb->va.va_tid, tlb->va.va_epn, tlb->rpn
0260       );
0261       myprintf(f,
0262         "Size:       TSIZE  0x%x ( 4^ts KiB = %6d KiB = 0x%08x B)\r\n",
0263         tlb->att.sz, (1<<(2*tlb->att.sz)), (1024<<(2*tlb->att.sz))
0264       );
0265       myprintf(f,
0266         "Attributes: PERM 0x%03x (ux/sx/uw/sw/ur/sr) WIMGE 0x%02x IPROT %i\r\n",
0267         tlb->att.perm, tlb->att.wimge, (sel && (mas1 & FSL_EIS_MAS1_IPROT) ? 1 : 0)
0268       );
0269       myprintf(f,
0270         "EA range 0x%08x .. 0x%08x\r\n",
0271         (tlb->va.va_epn << 12),
0272         (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1
0273       );
0274     }
0275   } else {
0276     if ( !quiet ) {
0277       myprintf(f, "TLB[%i] Entry #%i <OFF> (size 0x%x = 0x%xb)\n", sel, idx, tlb->att.sz, (1024<<(2*tlb->att.sz)));
0278     }
0279     return 1;
0280   }
0281   return 0;
0282 }
0283 
0284 /* Initialize cache; verify that TLB0 is unused;
0285  *
0286  * RETURNS: zero on success, nonzero on error (TLB0
0287  *          seems to be in use); in this case the
0288  *          driver will refuse to change TLB1 entries
0289  *          (other than disabling them).
0290  */
0291 int rtems_e500_initlb()
0292 {
0293 int i;
0294 int rval = 0;
0295   for (i=0; i<16; i++)
0296     rtems_e500_prtlb(E500_SELTLB_1 | i, 1, 0);
0297   for (i=0; i<256; i++) {
0298     /* refuse to enable operations that change TLB entries
0299          * if anything in TLB[0] is valid (because we currently
0300      * don't check against overlap with TLB[0] when we
0301      * write a new entry).
0302      */
0303     if ( rtems_e500_prtlb(E500_SELTLB_0 | i, 1, 0) <=0 ) {
0304       myprintf(stderr,"WARNING: 4k TLB #%i seems to be valid; UNSUPPORTED configuration\n", i);
0305       rval = -1;
0306     }
0307   }
0308   if ( !rval )
0309     initialized = 1;
0310   return rval;
0311 }
0312 
0313 /*
0314  * Write TLB1 entry (can also be used to disable an entry).
0315  *
0316  * The routine checks against the cached data in
0317  * rtems_e500_tlb_va[] to prevent the user from generating
0318  * overlapping entries.
0319  *
0320  *   'idx': TLB 1 entry # to manipulate
0321  *    'ea': Effective address (must be page aligned)
0322  *    'pa': Physical  address (must be page aligned)
0323  *    'sz': Page size selector; page size is
0324  *          1024 * 2^(2*sz) bytes.
0325  *          'sz' may also be one of the following:
0326  *          - page size in bytes ( >= 1024 ); the selector
0327  *            value is then computed by this routine.
0328  *            However, 'sz' must be a valid page size
0329  *            or -1 will be returned.
0330  *          - a value < 0 to invalidate/disable the
0331  *            TLB entry.
0332  *  'attr': Page attributes; ORed combination of WIMGE,
0333  *          PERMissions, TID and TS. Use ATTR_xxx macros
0334  *
0335  * RETURNS: 0 on success, nonzero on error:
0336  *
0337  *         >0: requested mapping would overlap with
0338  *             existing mapping in other entry. Return
0339  *             value gives conflicting entry + 1; i.e.,
0340  *             if a value of 4 is returned then the request
0341  *             conflicts with existing mapping in entry 3.
0342  *         -1: invalid argument
0343  *         -3: driver not initialized (or initialization
0344  *             failed because TLB0 is in use).
0345  *         <0: other error
0346  *
0347  */
0348 #define E500_TLB_ATTR_WIMGE(x)      ((x)&0x7f)        /* includes user bits */
0349 #define E500_TLB_ATTR_WIMGE_GET(x)  ((x)&0x7f)
0350 #define E500_TLB_ATTR_TS            (1<<7)
0351 #define E500_TLB_ATTR_PERM(x)        (((x)&0x3ff)<<8)
0352 #define E500_TLB_ATTR_PERM_GET(x)   (((x)>>8)&0x3ff)
0353 #define E500_TLB_ATTR_TID(x)        (((x)&0xfff)<<20)
0354 #define E500_TLB_ATTR_TID_GET(x)    (((x)>>20)&0xfff)
0355 
0356 int
0357 rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr)
0358 {
0359 uint32_t              mas1, mas2, mas3, mas4;
0360 uint32_t              tid, msk;
0361 int                   lkup;
0362 rtems_interrupt_level lvl;
0363 
0364   if ( sz >= 1024 ) {
0365     /* Assume they literally specify a size */
0366     msk = sz;
0367     sz  = 0;
0368     while ( msk != (1024<<(2*sz)) ) {
0369       if ( ++sz > 15 ) {
0370         return -1;
0371       }
0372     }
0373     /* OK, acceptable */
0374   }
0375 
0376   msk = sz > 0 ? (1024<<(2*sz)) - 1 : 0;
0377 
0378   if ( !initialized && sz > 0 ) {
0379     myprintf(stderr,"TLB driver not initialized; refuse to enable any entry\n");
0380     return -3;
0381   }
0382 
0383   if ( (ea & msk) || (pa & msk) ) {
0384     myprintf(stderr,"Misaligned ea or pa\n");
0385     return -1;
0386   }
0387 
0388   if ( idx < 0 || idx > 15 )
0389     return -1;
0390 
0391   if ( sz > 15 ) {
0392     /* but e500v1 doesn't support all 16 sizes!! */
0393     /* FIXME: we should inquire about this CPU's
0394      *        capabilities...
0395      */
0396     return -1;
0397   }
0398 
0399   tid = E500_TLB_ATTR_TID_GET(attr);
0400 
0401   mas1 = (attr & E500_TLB_ATTR_TS) ? FSL_EIS_MAS1_TS : 0;
0402 
0403   if ( sz >=0 ) {
0404     lkup = rtems_e500_matchtlb(ea, tid, mas1, sz);
0405 
0406     if ( lkup < -1 ) {
0407       /* some error */
0408       return lkup;
0409     }
0410 
0411     if ( lkup >= 0 && lkup != idx ) {
0412       myprintf(stderr,"TLB[1] #%i overlaps with requested mapping\n", lkup);
0413       rtems_e500_prtlb( E500_SELTLB_1 | lkup, 0, stderr);
0414       return lkup+1;
0415     }
0416   }
0417 
0418   /* OK to proceed */
0419   mas1 |= FSL_EIS_MAS1_IPROT | FSL_EIS_MAS1_TID(tid);
0420 
0421   if ( sz >= 0 )
0422     mas1 |= FSL_EIS_MAS1_V | FSL_EIS_MAS1_TSIZE(sz);
0423 
0424   mas2 = FSL_EIS_MAS2_EPN( ea>>12 ) | E500_TLB_ATTR_WIMGE(attr);
0425   mas3 = FSL_EIS_MAS3_RPN( pa>>12 ) | E500_TLB_ATTR_PERM_GET(attr);
0426   /* mas4 is not really relevant; we don't use TLB replacement */
0427   mas4 = FSL_EIS_MAS4_TLBSELD | FSL_EIS_MAS4_TIDSELD(0) | FSL_EIS_MAS4_TSIZED(9) | FSL_EIS_MAS4_ID | FSL_EIS_MAS4_GD;
0428 
0429   rtems_interrupt_disable(lvl);
0430 
0431   seltlb(idx | E500_SELTLB_1);
0432 
0433   _write_MAS1(mas1);
0434   _write_MAS2(mas2);
0435   _write_MAS3(mas3);
0436   _write_MAS4(mas4);
0437 
0438   ppc_synchronize_data();
0439   ppc_synchronize_instructions();
0440   ppc_tlbwe();
0441   ppc_synchronize_data();
0442   ppc_synchronize_instructions();
0443 
0444   rtems_interrupt_enable(lvl);
0445 
0446   /* update cache */
0447   rtems_e500_prtlb( E500_SELTLB_1 | idx, 1, 0);
0448 
0449   return 0;
0450 }
0451 
0452 /*
0453  * Check if a ts/tid/ea/sz mapping overlaps
0454  * with an existing entry.
0455  *
0456  * ASSUMPTION: all TLB0 (fixed 4k pages) are invalid and always unused.
0457  *
0458  * NOTE: 'sz' is the 'logarithmic' size selector; the page size
0459  *       is 1024*2^(2*sz).
0460  *
0461  * RETURNS:
0462  *     >= 0: index of TLB1 entry that already provides a mapping
0463  *           which overlaps within the ea range.
0464  *       -1: SUCCESS (no conflicting entry found)
0465  *     <=-2: ERROR (invalid input)
0466  */
0467 int rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz)
0468 {
0469 int                  i;
0470 uint32_t             m,a;
0471 E500_tlb_va_cache_t *tlb;
0472 
0473   if ( sz < 0 || sz > 15 )
0474     return -4;
0475 
0476   sz = (1024<<(2*sz));
0477 
0478   if ( !initialized ) {
0479     /* cache not initialized */
0480     return -3;
0481   }
0482 
0483   if ( ea & (sz-1) ) {
0484     /* misaligned ea */
0485     return -2;
0486   }
0487 
0488   if ( ts )
0489     ts = 1;
0490 
0491   for ( i=0, tlb=rtems_e500_tlb_va_cache; i<16; i++, tlb++ ) {
0492     if ( ! tlb->att.v )
0493       continue;
0494     if ( tlb->att.ts != ts )
0495       continue;
0496     if ( tlb->va.va_tid && tlb->va.va_tid != tid )
0497       continue;
0498     /* TID and TS match a valid entry */
0499     m  = (1024<<(2*tlb->att.sz)) - 1;
0500     /* calculate starting address of this entry */
0501     a  = tlb->va.va_epn<<12;
0502     if ( ea <= a + m && ea + sz -1 >= a ) {
0503       /* overlap */
0504       return i;
0505     }
0506   }
0507   return -1;
0508 }
0509 
0510 /* Find TLB index that maps 'ea/as' combination
0511  *
0512  * RETURNS: index 'key'; i.e., the index number plus
0513  *          a bit (E500_SELTLB_1) which indicates whether
0514  *          the mapping was found in TLB0 (4k fixed page
0515  *          size) or in TLB1 (variable page size).
0516  *
0517  *          On error (no mapping) -1 is returned.
0518  */
0519 rtems_e500_tlb_idx
0520 rtems_e500_ftlb(uint32_t ea, int as)
0521 {
0522 uint32_t              pid, mas0, mas1;
0523 int                   i, rval = -1;
0524 rtems_interrupt_level lvl;
0525 
0526   rtems_interrupt_disable(lvl);
0527 
0528   for ( i=0; i<3; i++ ) {
0529     switch (i) {
0530       case 0:  asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID0)); break;
0531       case 1:  asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID1)); break;
0532       case 2:  asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID2)); break;
0533       default:
0534         goto bail;
0535     }
0536 
0537     _write_MAS6( FSL_EIS_MAS6_SPID0(pid) | (as ? FSL_EIS_MAS6_SAS : 0 ) );
0538 
0539     ppc_tlbsx((void *)(uintptr_t) ea);
0540 
0541     mas1 = _read_MAS1();
0542 
0543     if ( (FSL_EIS_MAS1_V & mas1) ) {
0544       mas0 = _read_MAS0();
0545       if ( FSL_EIS_MAS0_TLBSEL & mas0 ) {
0546         /* TLB1 */
0547         rval = FSL_EIS_MAS0_ESEL_GET(mas0) | E500_SELTLB_1;
0548       } else {
0549         rval = (ea >> (63-51)) | (( FSL_EIS_MAS0_NV & mas0 ) ? 180 : 0 ) ;
0550       }
0551       break;
0552     }
0553   }
0554 
0555 bail:
0556   rtems_interrupt_enable(lvl);
0557   return rval;
0558 }
0559 
0560 /* Mark TLB entry as invalid ('disabled'). Unlike
0561  * rtems_e500_wrtlb() with a negative size argument
0562  * this routine also can disable TLB0 entries.
0563  *
0564  * 'key': TLB entry (index) ORed with selector bit
0565  *        (0 for TLB0, E500_SELTLB_1 for TLB1).
0566  *
0567  * RETURNS: zero on success, nonzero on error (TLB
0568  *          unchanged).
0569  *
0570  * NOTE:  If a TLB1 entry is disabled the associated
0571  *        entry in rtems_e500_va_cache[] is also
0572  *        marked as disabled.
0573  */
0574 int
0575 rtems_e500_clrtlb(rtems_e500_tlb_idx key)
0576 {
0577 rtems_e500_tlb_idx    k0;
0578 rtems_interrupt_level lvl;
0579 
0580   /* minimal guard against bad key */
0581   if ( key < 0 )
0582     return -1;
0583 
0584   if ( (key & E500_SELTLB_1) ) {
0585     if ( (key & ~E500_SELTLB_1) > 15 ) {
0586       myprintf(stderr,"Invalid TLB index; TLB1 index must be < 16\n");
0587       return -1;
0588     }
0589   } else if ( key > 255 ) {
0590       myprintf(stderr,"Invalid TLB index; TLB0 index must be < 256\n");
0591       return -1;
0592   }
0593 
0594   /* Must not invalidate page 0 which holds vectors, text etc...  */
0595   k0 = rtems_e500_ftlb(0, 0);
0596   if ( -1 == k0 ) {
0597     myprintf(stderr,"tlbivax; something's fishy - I don't find mapping for addr. 0\n");
0598     return -1;
0599   }
0600 
0601   /* NOTE: we assume PID is ignored, and AS is 0 */
0602   if ( k0 == key ) {
0603     myprintf(stderr,"Refuse to invalidate page holding addr 0 (always needed)\n");
0604     return -1;
0605   }
0606 
0607   rtems_interrupt_disable(lvl);
0608 
0609   seltlb(key);
0610 
0611   ppc_tlbre();
0612 
0613   /* read old entries */
0614   _write_MAS1( _read_MAS1() & ~FSL_EIS_MAS1_V );
0615 
0616   ppc_synchronize_data();
0617   ppc_synchronize_instructions();
0618   ppc_tlbwe();
0619   ppc_synchronize_data();
0620   ppc_synchronize_instructions();
0621 
0622   /* update cache */
0623   if ( E500_SELTLB_1 & key )
0624     rtems_e500_tlb_va_cache[ (~E500_SELTLB_1 & key) ].att.v = 0;
0625 
0626   rtems_interrupt_enable(lvl);
0627 
0628   return 0;
0629 }