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 #include <linux/compiler.h>
0034 #include <linux/irqflags.h>
0035 #include <asm/octeon/cvmx.h>
0036 #include <asm/octeon/cvmx-l2c.h>
0037 #include <asm/octeon/cvmx-spinlock.h>
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 static cvmx_spinlock_t cvmx_l2c_spinlock;
0048
0049 int cvmx_l2c_get_core_way_partition(uint32_t core)
0050 {
0051 uint32_t field;
0052
0053
0054 if (core >= cvmx_octeon_num_cores())
0055 return -1;
0056
0057 if (OCTEON_IS_MODEL(OCTEON_CN63XX))
0058 return cvmx_read_csr(CVMX_L2C_WPAR_PPX(core)) & 0xffff;
0059
0060
0061
0062
0063
0064 field = (core & 0x3) * 8;
0065
0066
0067
0068
0069
0070
0071 switch (core & 0xC) {
0072 case 0x0:
0073 return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> field;
0074 case 0x4:
0075 return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> field;
0076 case 0x8:
0077 return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> field;
0078 case 0xC:
0079 return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> field;
0080 }
0081 return 0;
0082 }
0083
0084 int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask)
0085 {
0086 uint32_t field;
0087 uint32_t valid_mask;
0088
0089 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1;
0090
0091 mask &= valid_mask;
0092
0093
0094 if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX))
0095 return -1;
0096
0097
0098 if (core >= cvmx_octeon_num_cores())
0099 return -1;
0100
0101 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0102 cvmx_write_csr(CVMX_L2C_WPAR_PPX(core), mask);
0103 return 0;
0104 }
0105
0106
0107
0108
0109
0110 field = (core & 0x3) * 8;
0111
0112
0113
0114
0115
0116
0117 switch (core & 0xC) {
0118 case 0x0:
0119 cvmx_write_csr(CVMX_L2C_SPAR0,
0120 (cvmx_read_csr(CVMX_L2C_SPAR0) & ~(0xFF << field)) |
0121 mask << field);
0122 break;
0123 case 0x4:
0124 cvmx_write_csr(CVMX_L2C_SPAR1,
0125 (cvmx_read_csr(CVMX_L2C_SPAR1) & ~(0xFF << field)) |
0126 mask << field);
0127 break;
0128 case 0x8:
0129 cvmx_write_csr(CVMX_L2C_SPAR2,
0130 (cvmx_read_csr(CVMX_L2C_SPAR2) & ~(0xFF << field)) |
0131 mask << field);
0132 break;
0133 case 0xC:
0134 cvmx_write_csr(CVMX_L2C_SPAR3,
0135 (cvmx_read_csr(CVMX_L2C_SPAR3) & ~(0xFF << field)) |
0136 mask << field);
0137 break;
0138 }
0139 return 0;
0140 }
0141
0142 int cvmx_l2c_set_hw_way_partition(uint32_t mask)
0143 {
0144 uint32_t valid_mask;
0145
0146 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1;
0147 mask &= valid_mask;
0148
0149
0150 if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX))
0151 return -1;
0152
0153 if (OCTEON_IS_MODEL(OCTEON_CN63XX))
0154 cvmx_write_csr(CVMX_L2C_WPAR_IOBX(0), mask);
0155 else
0156 cvmx_write_csr(CVMX_L2C_SPAR4,
0157 (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask);
0158 return 0;
0159 }
0160
0161 int cvmx_l2c_get_hw_way_partition(void)
0162 {
0163 if (OCTEON_IS_MODEL(OCTEON_CN63XX))
0164 return cvmx_read_csr(CVMX_L2C_WPAR_IOBX(0)) & 0xffff;
0165 else
0166 return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF);
0167 }
0168
0169 void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event,
0170 uint32_t clear_on_read)
0171 {
0172 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
0173 union cvmx_l2c_pfctl pfctl;
0174
0175 pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL);
0176
0177 switch (counter) {
0178 case 0:
0179 pfctl.s.cnt0sel = event;
0180 pfctl.s.cnt0ena = 1;
0181 pfctl.s.cnt0rdclr = clear_on_read;
0182 break;
0183 case 1:
0184 pfctl.s.cnt1sel = event;
0185 pfctl.s.cnt1ena = 1;
0186 pfctl.s.cnt1rdclr = clear_on_read;
0187 break;
0188 case 2:
0189 pfctl.s.cnt2sel = event;
0190 pfctl.s.cnt2ena = 1;
0191 pfctl.s.cnt2rdclr = clear_on_read;
0192 break;
0193 case 3:
0194 default:
0195 pfctl.s.cnt3sel = event;
0196 pfctl.s.cnt3ena = 1;
0197 pfctl.s.cnt3rdclr = clear_on_read;
0198 break;
0199 }
0200
0201 cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64);
0202 } else {
0203 union cvmx_l2c_tadx_prf l2c_tadx_prf;
0204 int tad;
0205
0206 cvmx_dprintf("L2C performance counter events are different for this chip, mapping 'event' to cvmx_l2c_tad_event_t\n");
0207 if (clear_on_read)
0208 cvmx_dprintf("L2C counters don't support clear on read for this chip\n");
0209
0210 l2c_tadx_prf.u64 = cvmx_read_csr(CVMX_L2C_TADX_PRF(0));
0211
0212 switch (counter) {
0213 case 0:
0214 l2c_tadx_prf.s.cnt0sel = event;
0215 break;
0216 case 1:
0217 l2c_tadx_prf.s.cnt1sel = event;
0218 break;
0219 case 2:
0220 l2c_tadx_prf.s.cnt2sel = event;
0221 break;
0222 default:
0223 case 3:
0224 l2c_tadx_prf.s.cnt3sel = event;
0225 break;
0226 }
0227 for (tad = 0; tad < CVMX_L2C_TADS; tad++)
0228 cvmx_write_csr(CVMX_L2C_TADX_PRF(tad),
0229 l2c_tadx_prf.u64);
0230 }
0231 }
0232
0233 uint64_t cvmx_l2c_read_perf(uint32_t counter)
0234 {
0235 switch (counter) {
0236 case 0:
0237 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
0238 return cvmx_read_csr(CVMX_L2C_PFC0);
0239 else {
0240 uint64_t counter = 0;
0241 int tad;
0242
0243 for (tad = 0; tad < CVMX_L2C_TADS; tad++)
0244 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC0(tad));
0245 return counter;
0246 }
0247 case 1:
0248 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
0249 return cvmx_read_csr(CVMX_L2C_PFC1);
0250 else {
0251 uint64_t counter = 0;
0252 int tad;
0253
0254 for (tad = 0; tad < CVMX_L2C_TADS; tad++)
0255 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC1(tad));
0256 return counter;
0257 }
0258 case 2:
0259 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
0260 return cvmx_read_csr(CVMX_L2C_PFC2);
0261 else {
0262 uint64_t counter = 0;
0263 int tad;
0264
0265 for (tad = 0; tad < CVMX_L2C_TADS; tad++)
0266 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC2(tad));
0267 return counter;
0268 }
0269 case 3:
0270 default:
0271 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
0272 return cvmx_read_csr(CVMX_L2C_PFC3);
0273 else {
0274 uint64_t counter = 0;
0275 int tad;
0276
0277 for (tad = 0; tad < CVMX_L2C_TADS; tad++)
0278 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC3(tad));
0279 return counter;
0280 }
0281 }
0282 }
0283
0284
0285
0286
0287
0288
0289
0290
0291 static void fault_in(uint64_t addr, int len)
0292 {
0293 char *ptr;
0294
0295
0296
0297
0298
0299 len += addr & CVMX_CACHE_LINE_MASK;
0300 addr &= ~CVMX_CACHE_LINE_MASK;
0301 ptr = cvmx_phys_to_ptr(addr);
0302
0303
0304
0305
0306 CVMX_DCACHE_INVALIDATE;
0307 while (len > 0) {
0308 READ_ONCE(*ptr);
0309 len -= CVMX_CACHE_LINE_SIZE;
0310 ptr += CVMX_CACHE_LINE_SIZE;
0311 }
0312 }
0313
0314 int cvmx_l2c_lock_line(uint64_t addr)
0315 {
0316 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0317 int shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
0318 uint64_t assoc = cvmx_l2c_get_num_assoc();
0319 uint64_t tag = addr >> shift;
0320 uint64_t index = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, cvmx_l2c_address_to_index(addr) << CVMX_L2C_IDX_ADDR_SHIFT);
0321 uint64_t way;
0322 union cvmx_l2c_tadx_tag l2c_tadx_tag;
0323
0324 CVMX_CACHE_LCKL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, addr), 0);
0325
0326
0327 for (way = 0; way < assoc; way++) {
0328 CVMX_CACHE_LTGL2I(index | (way << shift), 0);
0329
0330 CVMX_SYNC;
0331 l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
0332 if (l2c_tadx_tag.s.valid && l2c_tadx_tag.s.tag == tag)
0333 break;
0334 }
0335
0336
0337 if (way >= assoc) {
0338
0339 return -1;
0340 }
0341
0342
0343 if (!l2c_tadx_tag.s.lock) {
0344
0345 return -1;
0346 }
0347 return way;
0348 } else {
0349 int retval = 0;
0350 union cvmx_l2c_dbg l2cdbg;
0351 union cvmx_l2c_lckbase lckbase;
0352 union cvmx_l2c_lckoff lckoff;
0353 union cvmx_l2t_err l2t_err;
0354
0355 cvmx_spinlock_lock(&cvmx_l2c_spinlock);
0356
0357 l2cdbg.u64 = 0;
0358 lckbase.u64 = 0;
0359 lckoff.u64 = 0;
0360
0361
0362 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
0363 l2t_err.s.lckerr = 1;
0364 l2t_err.s.lckerr2 = 1;
0365 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
0366
0367 addr &= ~CVMX_CACHE_LINE_MASK;
0368
0369
0370 l2cdbg.s.ppnum = cvmx_get_core_num();
0371 CVMX_SYNC;
0372 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
0373 cvmx_read_csr(CVMX_L2C_DBG);
0374
0375 lckoff.s.lck_offset = 0;
0376 cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64);
0377 cvmx_read_csr(CVMX_L2C_LCKOFF);
0378
0379 if (((union cvmx_l2c_cfg)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) {
0380 int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1;
0381 uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS;
0382
0383 lckbase.s.lck_base = addr_tmp >> 7;
0384
0385 } else {
0386 lckbase.s.lck_base = addr >> 7;
0387 }
0388
0389 lckbase.s.lck_ena = 1;
0390 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
0391
0392 cvmx_read_csr(CVMX_L2C_LCKBASE);
0393
0394 fault_in(addr, CVMX_CACHE_LINE_SIZE);
0395
0396 lckbase.s.lck_ena = 0;
0397 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
0398
0399 cvmx_read_csr(CVMX_L2C_LCKBASE);
0400
0401
0402 cvmx_write_csr(CVMX_L2C_DBG, 0);
0403 cvmx_read_csr(CVMX_L2C_DBG);
0404
0405 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
0406 if (l2t_err.s.lckerr || l2t_err.s.lckerr2)
0407 retval = 1;
0408
0409 cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
0410 return retval;
0411 }
0412 }
0413
0414 int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len)
0415 {
0416 int retval = 0;
0417
0418
0419 len += start & CVMX_CACHE_LINE_MASK;
0420 start &= ~CVMX_CACHE_LINE_MASK;
0421 len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
0422
0423 while (len) {
0424 retval += cvmx_l2c_lock_line(start);
0425 start += CVMX_CACHE_LINE_SIZE;
0426 len -= CVMX_CACHE_LINE_SIZE;
0427 }
0428 return retval;
0429 }
0430
0431 void cvmx_l2c_flush(void)
0432 {
0433 uint64_t assoc, set;
0434 uint64_t n_assoc, n_set;
0435
0436 n_set = cvmx_l2c_get_num_sets();
0437 n_assoc = cvmx_l2c_get_num_assoc();
0438
0439 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
0440 uint64_t address;
0441
0442 int assoc_shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
0443 int set_shift = CVMX_L2C_IDX_ADDR_SHIFT;
0444
0445 for (set = 0; set < n_set; set++) {
0446 for (assoc = 0; assoc < n_assoc; assoc++) {
0447 address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
0448 (assoc << assoc_shift) | (set << set_shift));
0449 CVMX_CACHE_WBIL2I(address, 0);
0450 }
0451 }
0452 } else {
0453 for (set = 0; set < n_set; set++)
0454 for (assoc = 0; assoc < n_assoc; assoc++)
0455 cvmx_l2c_flush_line(assoc, set);
0456 }
0457 }
0458
0459
0460 int cvmx_l2c_unlock_line(uint64_t address)
0461 {
0462
0463 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0464 int assoc;
0465 union cvmx_l2c_tag tag;
0466 uint32_t tag_addr;
0467 uint32_t index = cvmx_l2c_address_to_index(address);
0468
0469 tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
0470
0471
0472
0473
0474
0475
0476
0477 for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
0478 tag = cvmx_l2c_get_tag(assoc, index);
0479
0480 if (tag.s.V && (tag.s.addr == tag_addr)) {
0481 CVMX_CACHE_WBIL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0);
0482 return tag.s.L;
0483 }
0484 }
0485 } else {
0486 int assoc;
0487 union cvmx_l2c_tag tag;
0488 uint32_t tag_addr;
0489
0490 uint32_t index = cvmx_l2c_address_to_index(address);
0491
0492
0493 tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
0494 for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
0495 tag = cvmx_l2c_get_tag(assoc, index);
0496
0497 if (tag.s.V && (tag.s.addr == tag_addr)) {
0498 cvmx_l2c_flush_line(assoc, index);
0499 return tag.s.L;
0500 }
0501 }
0502 }
0503 return 0;
0504 }
0505
0506 int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len)
0507 {
0508 int num_unlocked = 0;
0509
0510 len += start & CVMX_CACHE_LINE_MASK;
0511 start &= ~CVMX_CACHE_LINE_MASK;
0512 len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
0513 while (len > 0) {
0514 num_unlocked += cvmx_l2c_unlock_line(start);
0515 start += CVMX_CACHE_LINE_SIZE;
0516 len -= CVMX_CACHE_LINE_SIZE;
0517 }
0518
0519 return num_unlocked;
0520 }
0521
0522
0523
0524
0525
0526 union __cvmx_l2c_tag {
0527 uint64_t u64;
0528 struct cvmx_l2c_tag_cn50xx {
0529 __BITFIELD_FIELD(uint64_t reserved:40,
0530 __BITFIELD_FIELD(uint64_t V:1,
0531 __BITFIELD_FIELD(uint64_t D:1,
0532 __BITFIELD_FIELD(uint64_t L:1,
0533 __BITFIELD_FIELD(uint64_t U:1,
0534 __BITFIELD_FIELD(uint64_t addr:20,
0535 ;))))))
0536 } cn50xx;
0537 struct cvmx_l2c_tag_cn30xx {
0538 __BITFIELD_FIELD(uint64_t reserved:41,
0539 __BITFIELD_FIELD(uint64_t V:1,
0540 __BITFIELD_FIELD(uint64_t D:1,
0541 __BITFIELD_FIELD(uint64_t L:1,
0542 __BITFIELD_FIELD(uint64_t U:1,
0543 __BITFIELD_FIELD(uint64_t addr:19,
0544 ;))))))
0545 } cn30xx;
0546 struct cvmx_l2c_tag_cn31xx {
0547 __BITFIELD_FIELD(uint64_t reserved:42,
0548 __BITFIELD_FIELD(uint64_t V:1,
0549 __BITFIELD_FIELD(uint64_t D:1,
0550 __BITFIELD_FIELD(uint64_t L:1,
0551 __BITFIELD_FIELD(uint64_t U:1,
0552 __BITFIELD_FIELD(uint64_t addr:18,
0553 ;))))))
0554 } cn31xx;
0555 struct cvmx_l2c_tag_cn38xx {
0556 __BITFIELD_FIELD(uint64_t reserved:43,
0557 __BITFIELD_FIELD(uint64_t V:1,
0558 __BITFIELD_FIELD(uint64_t D:1,
0559 __BITFIELD_FIELD(uint64_t L:1,
0560 __BITFIELD_FIELD(uint64_t U:1,
0561 __BITFIELD_FIELD(uint64_t addr:17,
0562 ;))))))
0563 } cn38xx;
0564 struct cvmx_l2c_tag_cn58xx {
0565 __BITFIELD_FIELD(uint64_t reserved:44,
0566 __BITFIELD_FIELD(uint64_t V:1,
0567 __BITFIELD_FIELD(uint64_t D:1,
0568 __BITFIELD_FIELD(uint64_t L:1,
0569 __BITFIELD_FIELD(uint64_t U:1,
0570 __BITFIELD_FIELD(uint64_t addr:16,
0571 ;))))))
0572 } cn58xx;
0573 struct cvmx_l2c_tag_cn58xx cn56xx;
0574 struct cvmx_l2c_tag_cn31xx cn52xx;
0575 };
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 static union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index)
0592 {
0593
0594 uint64_t debug_tag_addr = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, (index << 7) + 96);
0595 uint64_t core = cvmx_get_core_num();
0596 union __cvmx_l2c_tag tag_val;
0597 uint64_t dbg_addr = CVMX_L2C_DBG;
0598 unsigned long flags;
0599 union cvmx_l2c_dbg debug_val;
0600
0601 debug_val.u64 = 0;
0602
0603
0604
0605
0606
0607 debug_val.s.ppnum = core;
0608 debug_val.s.l2t = 1;
0609 debug_val.s.set = assoc;
0610
0611 local_irq_save(flags);
0612
0613
0614
0615
0616 CVMX_SYNC;
0617
0618 CVMX_DCACHE_INVALIDATE;
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629 asm volatile (
0630 ".set push\n\t"
0631 ".set mips64\n\t"
0632 ".set noreorder\n\t"
0633 "sd %[dbg_val], 0(%[dbg_addr])\n\t"
0634 "ld $0, 0(%[dbg_addr])\n\t"
0635 "ld %[tag_val], 0(%[tag_addr])\n\t"
0636 "sd $0, 0(%[dbg_addr])\n\t"
0637 "ld $0, 0(%[dbg_addr])\n\t"
0638 "cache 9, 0($0)\n\t"
0639 ".set pop"
0640 : [tag_val] "=r" (tag_val)
0641 : [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr)
0642 : "memory");
0643
0644 local_irq_restore(flags);
0645
0646 return tag_val;
0647 }
0648
0649
0650 union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index)
0651 {
0652 union cvmx_l2c_tag tag;
0653
0654 tag.u64 = 0;
0655 if ((int)association >= cvmx_l2c_get_num_assoc()) {
0656 cvmx_dprintf("ERROR: cvmx_l2c_get_tag association out of range\n");
0657 return tag;
0658 }
0659 if ((int)index >= cvmx_l2c_get_num_sets()) {
0660 cvmx_dprintf("ERROR: cvmx_l2c_get_tag index out of range (arg: %d, max: %d)\n",
0661 (int)index, cvmx_l2c_get_num_sets());
0662 return tag;
0663 }
0664 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0665 union cvmx_l2c_tadx_tag l2c_tadx_tag;
0666 uint64_t address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
0667 (association << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
0668 (index << CVMX_L2C_IDX_ADDR_SHIFT));
0669
0670
0671
0672
0673
0674
0675 CVMX_CACHE_LTGL2I(address, 0);
0676 CVMX_SYNC;
0677 l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
0678
0679 tag.s.V = l2c_tadx_tag.s.valid;
0680 tag.s.D = l2c_tadx_tag.s.dirty;
0681 tag.s.L = l2c_tadx_tag.s.lock;
0682 tag.s.U = l2c_tadx_tag.s.use;
0683 tag.s.addr = l2c_tadx_tag.s.tag;
0684 } else {
0685 union __cvmx_l2c_tag tmp_tag;
0686
0687 tmp_tag = __read_l2_tag(association, index);
0688
0689
0690
0691
0692
0693 if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
0694 tag.s.V = tmp_tag.cn58xx.V;
0695 tag.s.D = tmp_tag.cn58xx.D;
0696 tag.s.L = tmp_tag.cn58xx.L;
0697 tag.s.U = tmp_tag.cn58xx.U;
0698 tag.s.addr = tmp_tag.cn58xx.addr;
0699 } else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
0700 tag.s.V = tmp_tag.cn38xx.V;
0701 tag.s.D = tmp_tag.cn38xx.D;
0702 tag.s.L = tmp_tag.cn38xx.L;
0703 tag.s.U = tmp_tag.cn38xx.U;
0704 tag.s.addr = tmp_tag.cn38xx.addr;
0705 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
0706 tag.s.V = tmp_tag.cn31xx.V;
0707 tag.s.D = tmp_tag.cn31xx.D;
0708 tag.s.L = tmp_tag.cn31xx.L;
0709 tag.s.U = tmp_tag.cn31xx.U;
0710 tag.s.addr = tmp_tag.cn31xx.addr;
0711 } else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) {
0712 tag.s.V = tmp_tag.cn30xx.V;
0713 tag.s.D = tmp_tag.cn30xx.D;
0714 tag.s.L = tmp_tag.cn30xx.L;
0715 tag.s.U = tmp_tag.cn30xx.U;
0716 tag.s.addr = tmp_tag.cn30xx.addr;
0717 } else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
0718 tag.s.V = tmp_tag.cn50xx.V;
0719 tag.s.D = tmp_tag.cn50xx.D;
0720 tag.s.L = tmp_tag.cn50xx.L;
0721 tag.s.U = tmp_tag.cn50xx.U;
0722 tag.s.addr = tmp_tag.cn50xx.addr;
0723 } else {
0724 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
0725 }
0726 }
0727 return tag;
0728 }
0729
0730 uint32_t cvmx_l2c_address_to_index(uint64_t addr)
0731 {
0732 uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT;
0733 int indxalias = 0;
0734
0735 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
0736 union cvmx_l2c_ctl l2c_ctl;
0737
0738 l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL);
0739 indxalias = !l2c_ctl.s.disidxalias;
0740 } else {
0741 union cvmx_l2c_cfg l2c_cfg;
0742
0743 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
0744 indxalias = l2c_cfg.s.idxalias;
0745 }
0746
0747 if (indxalias) {
0748 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0749 uint32_t a_14_12 = (idx / (CVMX_L2C_MEMBANK_SELECT_SIZE/(1<<CVMX_L2C_IDX_ADDR_SHIFT))) & 0x7;
0750
0751 idx ^= idx / cvmx_l2c_get_num_sets();
0752 idx ^= a_14_12;
0753 } else {
0754 idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT);
0755 }
0756 }
0757 idx &= CVMX_L2C_IDX_MASK;
0758 return idx;
0759 }
0760
0761 int cvmx_l2c_get_cache_size_bytes(void)
0762 {
0763 return cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() *
0764 CVMX_CACHE_LINE_SIZE;
0765 }
0766
0767
0768
0769
0770 int cvmx_l2c_get_set_bits(void)
0771 {
0772 int l2_set_bits;
0773
0774 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
0775 l2_set_bits = 11;
0776 else if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
0777 l2_set_bits = 10;
0778 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
0779 l2_set_bits = 9;
0780 else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
0781 l2_set_bits = 8;
0782 else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
0783 l2_set_bits = 7;
0784 else {
0785 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
0786 l2_set_bits = 11;
0787 }
0788 return l2_set_bits;
0789 }
0790
0791
0792 int cvmx_l2c_get_num_sets(void)
0793 {
0794 return 1 << cvmx_l2c_get_set_bits();
0795 }
0796
0797
0798 int cvmx_l2c_get_num_assoc(void)
0799 {
0800 int l2_assoc;
0801
0802 if (OCTEON_IS_MODEL(OCTEON_CN56XX) ||
0803 OCTEON_IS_MODEL(OCTEON_CN52XX) ||
0804 OCTEON_IS_MODEL(OCTEON_CN58XX) ||
0805 OCTEON_IS_MODEL(OCTEON_CN50XX) ||
0806 OCTEON_IS_MODEL(OCTEON_CN38XX))
0807 l2_assoc = 8;
0808 else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
0809 l2_assoc = 16;
0810 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) ||
0811 OCTEON_IS_MODEL(OCTEON_CN30XX))
0812 l2_assoc = 4;
0813 else {
0814 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
0815 l2_assoc = 8;
0816 }
0817
0818
0819 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0820 union cvmx_mio_fus_dat3 mio_fus_dat3;
0821
0822 mio_fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836 if (mio_fus_dat3.s.l2c_crip == 3)
0837 l2_assoc = 4;
0838 else if (mio_fus_dat3.s.l2c_crip == 2)
0839 l2_assoc = 8;
0840 else if (mio_fus_dat3.s.l2c_crip == 1)
0841 l2_assoc = 12;
0842 } else {
0843 uint64_t l2d_fus3;
0844
0845 l2d_fus3 = cvmx_read_csr(CVMX_L2D_FUS3);
0846
0847
0848
0849
0850
0851 if ((l2d_fus3 >> 35) & 0x1)
0852 l2_assoc = l2_assoc >> 2;
0853 else if ((l2d_fus3 >> 34) & 0x1)
0854 l2_assoc = l2_assoc >> 1;
0855 }
0856 return l2_assoc;
0857 }
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867 void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index)
0868 {
0869
0870 if (index > (uint32_t)cvmx_l2c_get_num_sets()) {
0871 cvmx_dprintf("ERROR: cvmx_l2c_flush_line index out of range.\n");
0872 return;
0873 }
0874
0875
0876 if (assoc > (uint32_t)cvmx_l2c_get_num_assoc()) {
0877 cvmx_dprintf("ERROR: cvmx_l2c_flush_line association out of range.\n");
0878 return;
0879 }
0880
0881 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
0882 uint64_t address;
0883
0884
0885
0886
0887
0888 address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
0889 (assoc << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
0890 (index << CVMX_L2C_IDX_ADDR_SHIFT));
0891 CVMX_CACHE_WBIL2I(address, 0);
0892 } else {
0893 union cvmx_l2c_dbg l2cdbg;
0894
0895 l2cdbg.u64 = 0;
0896 if (!OCTEON_IS_MODEL(OCTEON_CN30XX))
0897 l2cdbg.s.ppnum = cvmx_get_core_num();
0898 l2cdbg.s.finv = 1;
0899
0900 l2cdbg.s.set = assoc;
0901 cvmx_spinlock_lock(&cvmx_l2c_spinlock);
0902
0903
0904
0905
0906 CVMX_SYNC;
0907 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
0908 cvmx_read_csr(CVMX_L2C_DBG);
0909
0910 CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
0911 index * CVMX_CACHE_LINE_SIZE),
0912 0);
0913
0914 CVMX_SYNC;
0915 cvmx_write_csr(CVMX_L2C_DBG, 0);
0916 cvmx_read_csr(CVMX_L2C_DBG);
0917 cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
0918 }
0919 }