File indexing completed on 2025-05-11 08:23:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
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)
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
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
0120
0121
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
0132
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
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
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
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 ;
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
0245
0246
0247
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
0285
0286
0287
0288
0289
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
0299
0300
0301
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
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348 #define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f)
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
0366 msk = sz;
0367 sz = 0;
0368 while ( msk != (1024<<(2*sz)) ) {
0369 if ( ++sz > 15 ) {
0370 return -1;
0371 }
0372 }
0373
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
0393
0394
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
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
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
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
0447 rtems_e500_prtlb( E500_SELTLB_1 | idx, 1, 0);
0448
0449 return 0;
0450 }
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
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
0480 return -3;
0481 }
0482
0483 if ( ea & (sz-1) ) {
0484
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
0499 m = (1024<<(2*tlb->att.sz)) - 1;
0500
0501 a = tlb->va.va_epn<<12;
0502 if ( ea <= a + m && ea + sz -1 >= a ) {
0503
0504 return i;
0505 }
0506 }
0507 return -1;
0508 }
0509
0510
0511
0512
0513
0514
0515
0516
0517
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
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
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
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
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
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
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
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
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 }