1 /***********************license start*************** 2 * Author: Cavium Networks 3 * 4 * Contact: support@caviumnetworks.com 5 * This file is part of the OCTEON SDK 6 * 7 * Copyright (c) 2003-2008 Cavium Networks 8 * 9 * This file is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, Version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This file is distributed in the hope that it will be useful, but 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 16 * NONINFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this file; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * or visit http://www.gnu.org/licenses/. 23 * 24 * This file may also be available under a different license from Cavium. 25 * Contact Cavium Networks for more information 26 ***********************license end**************************************/ 27 28 /* 29 * Implementation of the Level 2 Cache (L2C) control, measurement, and 30 * debugging facilities. 31 */ 32 33 #include <asm/octeon/cvmx.h> 34 #include <asm/octeon/cvmx-l2c.h> 35 #include <asm/octeon/cvmx-spinlock.h> 36 37 /* 38 * This spinlock is used internally to ensure that only one core is 39 * performing certain L2 operations at a time. 40 * 41 * NOTE: This only protects calls from within a single application - 42 * if multiple applications or operating systems are running, then it 43 * is up to the user program to coordinate between them. 44 */ 45 static cvmx_spinlock_t cvmx_l2c_spinlock; 46 47 static inline int l2_size_half(void) 48 { 49 uint64_t val = cvmx_read_csr(CVMX_L2D_FUS3); 50 return !!(val & (1ull << 34)); 51 } 52 53 int cvmx_l2c_get_core_way_partition(uint32_t core) 54 { 55 uint32_t field; 56 57 /* Validate the core number */ 58 if (core >= cvmx_octeon_num_cores()) 59 return -1; 60 61 /* 62 * Use the lower two bits of the coreNumber to determine the 63 * bit offset of the UMSK[] field in the L2C_SPAR register. 64 */ 65 field = (core & 0x3) * 8; 66 67 /* 68 * Return the UMSK[] field from the appropriate L2C_SPAR 69 * register based on the coreNumber. 70 */ 71 72 switch (core & 0xC) { 73 case 0x0: 74 return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> 75 field; 76 case 0x4: 77 return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> 78 field; 79 case 0x8: 80 return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> 81 field; 82 case 0xC: 83 return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> 84 field; 85 } 86 return 0; 87 } 88 89 int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask) 90 { 91 uint32_t field; 92 uint32_t valid_mask; 93 94 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 95 96 mask &= valid_mask; 97 98 /* A UMSK setting which blocks all L2C Ways is an error. */ 99 if (mask == valid_mask) 100 return -1; 101 102 /* Validate the core number */ 103 if (core >= cvmx_octeon_num_cores()) 104 return -1; 105 106 /* Check to make sure current mask & new mask don't block all ways */ 107 if (((mask | cvmx_l2c_get_core_way_partition(core)) & valid_mask) == 108 valid_mask) 109 return -1; 110 111 /* Use the lower two bits of core to determine the bit offset of the 112 * UMSK[] field in the L2C_SPAR register. 113 */ 114 field = (core & 0x3) * 8; 115 116 /* Assign the new mask setting to the UMSK[] field in the appropriate 117 * L2C_SPAR register based on the core_num. 118 * 119 */ 120 switch (core & 0xC) { 121 case 0x0: 122 cvmx_write_csr(CVMX_L2C_SPAR0, 123 (cvmx_read_csr(CVMX_L2C_SPAR0) & 124 ~(0xFF << field)) | mask << field); 125 break; 126 case 0x4: 127 cvmx_write_csr(CVMX_L2C_SPAR1, 128 (cvmx_read_csr(CVMX_L2C_SPAR1) & 129 ~(0xFF << field)) | mask << field); 130 break; 131 case 0x8: 132 cvmx_write_csr(CVMX_L2C_SPAR2, 133 (cvmx_read_csr(CVMX_L2C_SPAR2) & 134 ~(0xFF << field)) | mask << field); 135 break; 136 case 0xC: 137 cvmx_write_csr(CVMX_L2C_SPAR3, 138 (cvmx_read_csr(CVMX_L2C_SPAR3) & 139 ~(0xFF << field)) | mask << field); 140 break; 141 } 142 return 0; 143 } 144 145 int cvmx_l2c_set_hw_way_partition(uint32_t mask) 146 { 147 uint32_t valid_mask; 148 149 valid_mask = 0xff; 150 151 if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN38XX)) { 152 if (l2_size_half()) 153 valid_mask = 0xf; 154 } else if (l2_size_half()) 155 valid_mask = 0x3; 156 157 mask &= valid_mask; 158 159 /* A UMSK setting which blocks all L2C Ways is an error. */ 160 if (mask == valid_mask) 161 return -1; 162 /* Check to make sure current mask & new mask don't block all ways */ 163 if (((mask | cvmx_l2c_get_hw_way_partition()) & valid_mask) == 164 valid_mask) 165 return -1; 166 167 cvmx_write_csr(CVMX_L2C_SPAR4, 168 (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask); 169 return 0; 170 } 171 172 int cvmx_l2c_get_hw_way_partition(void) 173 { 174 return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF); 175 } 176 177 void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event, 178 uint32_t clear_on_read) 179 { 180 union cvmx_l2c_pfctl pfctl; 181 182 pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL); 183 184 switch (counter) { 185 case 0: 186 pfctl.s.cnt0sel = event; 187 pfctl.s.cnt0ena = 1; 188 if (!cvmx_octeon_is_pass1()) 189 pfctl.s.cnt0rdclr = clear_on_read; 190 break; 191 case 1: 192 pfctl.s.cnt1sel = event; 193 pfctl.s.cnt1ena = 1; 194 if (!cvmx_octeon_is_pass1()) 195 pfctl.s.cnt1rdclr = clear_on_read; 196 break; 197 case 2: 198 pfctl.s.cnt2sel = event; 199 pfctl.s.cnt2ena = 1; 200 if (!cvmx_octeon_is_pass1()) 201 pfctl.s.cnt2rdclr = clear_on_read; 202 break; 203 case 3: 204 default: 205 pfctl.s.cnt3sel = event; 206 pfctl.s.cnt3ena = 1; 207 if (!cvmx_octeon_is_pass1()) 208 pfctl.s.cnt3rdclr = clear_on_read; 209 break; 210 } 211 212 cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64); 213 } 214 215 uint64_t cvmx_l2c_read_perf(uint32_t counter) 216 { 217 switch (counter) { 218 case 0: 219 return cvmx_read_csr(CVMX_L2C_PFC0); 220 case 1: 221 return cvmx_read_csr(CVMX_L2C_PFC1); 222 case 2: 223 return cvmx_read_csr(CVMX_L2C_PFC2); 224 case 3: 225 default: 226 return cvmx_read_csr(CVMX_L2C_PFC3); 227 } 228 } 229 230 /** 231 * @INTERNAL 232 * Helper function use to fault in cache lines for L2 cache locking 233 * 234 * @addr: Address of base of memory region to read into L2 cache 235 * @len: Length (in bytes) of region to fault in 236 */ 237 static void fault_in(uint64_t addr, int len) 238 { 239 volatile char *ptr; 240 volatile char dummy; 241 /* 242 * Adjust addr and length so we get all cache lines even for 243 * small ranges spanning two cache lines 244 */ 245 len += addr & CVMX_CACHE_LINE_MASK; 246 addr &= ~CVMX_CACHE_LINE_MASK; 247 ptr = (volatile char *)cvmx_phys_to_ptr(addr); 248 /* 249 * Invalidate L1 cache to make sure all loads result in data 250 * being in L2. 251 */ 252 CVMX_DCACHE_INVALIDATE; 253 while (len > 0) { 254 dummy += *ptr; 255 len -= CVMX_CACHE_LINE_SIZE; 256 ptr += CVMX_CACHE_LINE_SIZE; 257 } 258 } 259 260 int cvmx_l2c_lock_line(uint64_t addr) 261 { 262 int retval = 0; 263 union cvmx_l2c_dbg l2cdbg; 264 union cvmx_l2c_lckbase lckbase; 265 union cvmx_l2c_lckoff lckoff; 266 union cvmx_l2t_err l2t_err; 267 l2cdbg.u64 = 0; 268 lckbase.u64 = 0; 269 lckoff.u64 = 0; 270 271 cvmx_spinlock_lock(&cvmx_l2c_spinlock); 272 273 /* Clear l2t error bits if set */ 274 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 275 l2t_err.s.lckerr = 1; 276 l2t_err.s.lckerr2 = 1; 277 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 278 279 addr &= ~CVMX_CACHE_LINE_MASK; 280 281 /* Set this core as debug core */ 282 l2cdbg.s.ppnum = cvmx_get_core_num(); 283 CVMX_SYNC; 284 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 285 cvmx_read_csr(CVMX_L2C_DBG); 286 287 lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */ 288 cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64); 289 cvmx_read_csr(CVMX_L2C_LCKOFF); 290 291 if (((union cvmx_l2c_cfg) (cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) { 292 int alias_shift = 293 CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1; 294 uint64_t addr_tmp = 295 addr ^ (addr & ((1 << alias_shift) - 1)) >> 296 CVMX_L2_SET_BITS; 297 lckbase.s.lck_base = addr_tmp >> 7; 298 } else { 299 lckbase.s.lck_base = addr >> 7; 300 } 301 302 lckbase.s.lck_ena = 1; 303 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 304 cvmx_read_csr(CVMX_L2C_LCKBASE); /* Make sure it gets there */ 305 306 fault_in(addr, CVMX_CACHE_LINE_SIZE); 307 308 lckbase.s.lck_ena = 0; 309 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 310 cvmx_read_csr(CVMX_L2C_LCKBASE); /* Make sure it gets there */ 311 312 /* Stop being debug core */ 313 cvmx_write_csr(CVMX_L2C_DBG, 0); 314 cvmx_read_csr(CVMX_L2C_DBG); 315 316 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 317 if (l2t_err.s.lckerr || l2t_err.s.lckerr2) 318 retval = 1; /* We were unable to lock the line */ 319 320 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 321 322 return retval; 323 } 324 325 int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len) 326 { 327 int retval = 0; 328 329 /* Round start/end to cache line boundaries */ 330 len += start & CVMX_CACHE_LINE_MASK; 331 start &= ~CVMX_CACHE_LINE_MASK; 332 len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; 333 334 while (len) { 335 retval += cvmx_l2c_lock_line(start); 336 start += CVMX_CACHE_LINE_SIZE; 337 len -= CVMX_CACHE_LINE_SIZE; 338 } 339 340 return retval; 341 } 342 343 void cvmx_l2c_flush(void) 344 { 345 uint64_t assoc, set; 346 uint64_t n_assoc, n_set; 347 union cvmx_l2c_dbg l2cdbg; 348 349 cvmx_spinlock_lock(&cvmx_l2c_spinlock); 350 351 l2cdbg.u64 = 0; 352 if (!OCTEON_IS_MODEL(OCTEON_CN30XX)) 353 l2cdbg.s.ppnum = cvmx_get_core_num(); 354 l2cdbg.s.finv = 1; 355 n_set = CVMX_L2_SETS; 356 n_assoc = l2_size_half() ? (CVMX_L2_ASSOC / 2) : CVMX_L2_ASSOC; 357 for (set = 0; set < n_set; set++) { 358 for (assoc = 0; assoc < n_assoc; assoc++) { 359 l2cdbg.s.set = assoc; 360 /* Enter debug mode, and make sure all other 361 ** writes complete before we enter debug 362 ** mode */ 363 CVMX_SYNCW; 364 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 365 cvmx_read_csr(CVMX_L2C_DBG); 366 367 CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG 368 (CVMX_MIPS_SPACE_XKPHYS, 369 set * CVMX_CACHE_LINE_SIZE), 0); 370 CVMX_SYNCW; /* Push STF out to L2 */ 371 /* Exit debug mode */ 372 CVMX_SYNC; 373 cvmx_write_csr(CVMX_L2C_DBG, 0); 374 cvmx_read_csr(CVMX_L2C_DBG); 375 } 376 } 377 378 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 379 } 380 381 int cvmx_l2c_unlock_line(uint64_t address) 382 { 383 int assoc; 384 union cvmx_l2c_tag tag; 385 union cvmx_l2c_dbg l2cdbg; 386 uint32_t tag_addr; 387 388 uint32_t index = cvmx_l2c_address_to_index(address); 389 390 cvmx_spinlock_lock(&cvmx_l2c_spinlock); 391 /* Compute portion of address that is stored in tag */ 392 tag_addr = 393 ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & 394 ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 395 for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) { 396 tag = cvmx_get_l2c_tag(assoc, index); 397 398 if (tag.s.V && (tag.s.addr == tag_addr)) { 399 l2cdbg.u64 = 0; 400 l2cdbg.s.ppnum = cvmx_get_core_num(); 401 l2cdbg.s.set = assoc; 402 l2cdbg.s.finv = 1; 403 404 CVMX_SYNC; 405 /* Enter debug mode */ 406 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 407 cvmx_read_csr(CVMX_L2C_DBG); 408 409 CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG 410 (CVMX_MIPS_SPACE_XKPHYS, 411 address), 0); 412 CVMX_SYNC; 413 /* Exit debug mode */ 414 cvmx_write_csr(CVMX_L2C_DBG, 0); 415 cvmx_read_csr(CVMX_L2C_DBG); 416 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 417 return tag.s.L; 418 } 419 } 420 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 421 return 0; 422 } 423 424 int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len) 425 { 426 int num_unlocked = 0; 427 /* Round start/end to cache line boundaries */ 428 len += start & CVMX_CACHE_LINE_MASK; 429 start &= ~CVMX_CACHE_LINE_MASK; 430 len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; 431 while (len > 0) { 432 num_unlocked += cvmx_l2c_unlock_line(start); 433 start += CVMX_CACHE_LINE_SIZE; 434 len -= CVMX_CACHE_LINE_SIZE; 435 } 436 437 return num_unlocked; 438 } 439 440 /* 441 * Internal l2c tag types. These are converted to a generic structure 442 * that can be used on all chips. 443 */ 444 union __cvmx_l2c_tag { 445 uint64_t u64; 446 struct cvmx_l2c_tag_cn50xx { 447 uint64_t reserved:40; 448 uint64_t V:1; /* Line valid */ 449 uint64_t D:1; /* Line dirty */ 450 uint64_t L:1; /* Line locked */ 451 uint64_t U:1; /* Use, LRU eviction */ 452 uint64_t addr:20; /* Phys mem addr (33..14) */ 453 } cn50xx; 454 struct cvmx_l2c_tag_cn30xx { 455 uint64_t reserved:41; 456 uint64_t V:1; /* Line valid */ 457 uint64_t D:1; /* Line dirty */ 458 uint64_t L:1; /* Line locked */ 459 uint64_t U:1; /* Use, LRU eviction */ 460 uint64_t addr:19; /* Phys mem addr (33..15) */ 461 } cn30xx; 462 struct cvmx_l2c_tag_cn31xx { 463 uint64_t reserved:42; 464 uint64_t V:1; /* Line valid */ 465 uint64_t D:1; /* Line dirty */ 466 uint64_t L:1; /* Line locked */ 467 uint64_t U:1; /* Use, LRU eviction */ 468 uint64_t addr:18; /* Phys mem addr (33..16) */ 469 } cn31xx; 470 struct cvmx_l2c_tag_cn38xx { 471 uint64_t reserved:43; 472 uint64_t V:1; /* Line valid */ 473 uint64_t D:1; /* Line dirty */ 474 uint64_t L:1; /* Line locked */ 475 uint64_t U:1; /* Use, LRU eviction */ 476 uint64_t addr:17; /* Phys mem addr (33..17) */ 477 } cn38xx; 478 struct cvmx_l2c_tag_cn58xx { 479 uint64_t reserved:44; 480 uint64_t V:1; /* Line valid */ 481 uint64_t D:1; /* Line dirty */ 482 uint64_t L:1; /* Line locked */ 483 uint64_t U:1; /* Use, LRU eviction */ 484 uint64_t addr:16; /* Phys mem addr (33..18) */ 485 } cn58xx; 486 struct cvmx_l2c_tag_cn58xx cn56xx; /* 2048 sets */ 487 struct cvmx_l2c_tag_cn31xx cn52xx; /* 512 sets */ 488 }; 489 490 /** 491 * @INTERNAL 492 * Function to read a L2C tag. This code make the current core 493 * the 'debug core' for the L2. This code must only be executed by 494 * 1 core at a time. 495 * 496 * @assoc: Association (way) of the tag to dump 497 * @index: Index of the cacheline 498 * 499 * Returns The Octeon model specific tag structure. This is 500 * translated by a wrapper function to a generic form that is 501 * easier for applications to use. 502 */ 503 static union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index) 504 { 505 506 uint64_t debug_tag_addr = (((1ULL << 63) | (index << 7)) + 96); 507 uint64_t core = cvmx_get_core_num(); 508 union __cvmx_l2c_tag tag_val; 509 uint64_t dbg_addr = CVMX_L2C_DBG; 510 unsigned long flags; 511 512 union cvmx_l2c_dbg debug_val; 513 debug_val.u64 = 0; 514 /* 515 * For low core count parts, the core number is always small enough 516 * to stay in the correct field and not set any reserved bits. 517 */ 518 debug_val.s.ppnum = core; 519 debug_val.s.l2t = 1; 520 debug_val.s.set = assoc; 521 /* 522 * Make sure core is quiet (no prefetches, etc.) before 523 * entering debug mode. 524 */ 525 CVMX_SYNC; 526 /* Flush L1 to make sure debug load misses L1 */ 527 CVMX_DCACHE_INVALIDATE; 528 529 local_irq_save(flags); 530 531 /* 532 * The following must be done in assembly as when in debug 533 * mode all data loads from L2 return special debug data, not 534 * normal memory contents. Also, interrupts must be 535 * disabled, since if an interrupt occurs while in debug mode 536 * the ISR will get debug data from all its memory reads 537 * instead of the contents of memory 538 */ 539 540 asm volatile (".set push \n" 541 " .set mips64 \n" 542 " .set noreorder \n" 543 /* Enter debug mode, wait for store */ 544 " sd %[dbg_val], 0(%[dbg_addr]) \n" 545 " ld $0, 0(%[dbg_addr]) \n" 546 /* Read L2C tag data */ 547 " ld %[tag_val], 0(%[tag_addr]) \n" 548 /* Exit debug mode, wait for store */ 549 " sd $0, 0(%[dbg_addr]) \n" 550 " ld $0, 0(%[dbg_addr]) \n" 551 /* Invalidate dcache to discard debug data */ 552 " cache 9, 0($0) \n" 553 " .set pop" : 554 [tag_val] "=r"(tag_val.u64) : [dbg_addr] "r"(dbg_addr), 555 [dbg_val] "r"(debug_val.u64), 556 [tag_addr] "r"(debug_tag_addr) : "memory"); 557 558 local_irq_restore(flags); 559 return tag_val; 560 561 } 562 563 union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index) 564 { 565 union __cvmx_l2c_tag tmp_tag; 566 union cvmx_l2c_tag tag; 567 tag.u64 = 0; 568 569 if ((int)association >= cvmx_l2c_get_num_assoc()) { 570 cvmx_dprintf 571 ("ERROR: cvmx_get_l2c_tag association out of range\n"); 572 return tag; 573 } 574 if ((int)index >= cvmx_l2c_get_num_sets()) { 575 cvmx_dprintf("ERROR: cvmx_get_l2c_tag " 576 "index out of range (arg: %d, max: %d\n", 577 index, cvmx_l2c_get_num_sets()); 578 return tag; 579 } 580 /* __read_l2_tag is intended for internal use only */ 581 tmp_tag = __read_l2_tag(association, index); 582 583 /* 584 * Convert all tag structure types to generic version, as it 585 * can represent all models. 586 */ 587 if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { 588 tag.s.V = tmp_tag.cn58xx.V; 589 tag.s.D = tmp_tag.cn58xx.D; 590 tag.s.L = tmp_tag.cn58xx.L; 591 tag.s.U = tmp_tag.cn58xx.U; 592 tag.s.addr = tmp_tag.cn58xx.addr; 593 } else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { 594 tag.s.V = tmp_tag.cn38xx.V; 595 tag.s.D = tmp_tag.cn38xx.D; 596 tag.s.L = tmp_tag.cn38xx.L; 597 tag.s.U = tmp_tag.cn38xx.U; 598 tag.s.addr = tmp_tag.cn38xx.addr; 599 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) 600 || OCTEON_IS_MODEL(OCTEON_CN52XX)) { 601 tag.s.V = tmp_tag.cn31xx.V; 602 tag.s.D = tmp_tag.cn31xx.D; 603 tag.s.L = tmp_tag.cn31xx.L; 604 tag.s.U = tmp_tag.cn31xx.U; 605 tag.s.addr = tmp_tag.cn31xx.addr; 606 } else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) { 607 tag.s.V = tmp_tag.cn30xx.V; 608 tag.s.D = tmp_tag.cn30xx.D; 609 tag.s.L = tmp_tag.cn30xx.L; 610 tag.s.U = tmp_tag.cn30xx.U; 611 tag.s.addr = tmp_tag.cn30xx.addr; 612 } else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { 613 tag.s.V = tmp_tag.cn50xx.V; 614 tag.s.D = tmp_tag.cn50xx.D; 615 tag.s.L = tmp_tag.cn50xx.L; 616 tag.s.U = tmp_tag.cn50xx.U; 617 tag.s.addr = tmp_tag.cn50xx.addr; 618 } else { 619 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 620 } 621 622 return tag; 623 } 624 625 uint32_t cvmx_l2c_address_to_index(uint64_t addr) 626 { 627 uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT; 628 union cvmx_l2c_cfg l2c_cfg; 629 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); 630 631 if (l2c_cfg.s.idxalias) { 632 idx ^= 633 ((addr & CVMX_L2C_ALIAS_MASK) >> 634 CVMX_L2C_TAG_ADDR_ALIAS_SHIFT); 635 } 636 idx &= CVMX_L2C_IDX_MASK; 637 return idx; 638 } 639 640 int cvmx_l2c_get_cache_size_bytes(void) 641 { 642 return cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() * 643 CVMX_CACHE_LINE_SIZE; 644 } 645 646 /** 647 * Return log base 2 of the number of sets in the L2 cache 648 * Returns 649 */ 650 int cvmx_l2c_get_set_bits(void) 651 { 652 int l2_set_bits; 653 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 654 l2_set_bits = 11; /* 2048 sets */ 655 else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 656 l2_set_bits = 10; /* 1024 sets */ 657 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) 658 || OCTEON_IS_MODEL(OCTEON_CN52XX)) 659 l2_set_bits = 9; /* 512 sets */ 660 else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 661 l2_set_bits = 8; /* 256 sets */ 662 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 663 l2_set_bits = 7; /* 128 sets */ 664 else { 665 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 666 l2_set_bits = 11; /* 2048 sets */ 667 } 668 return l2_set_bits; 669 670 } 671 672 /* Return the number of sets in the L2 Cache */ 673 int cvmx_l2c_get_num_sets(void) 674 { 675 return 1 << cvmx_l2c_get_set_bits(); 676 } 677 678 /* Return the number of associations in the L2 Cache */ 679 int cvmx_l2c_get_num_assoc(void) 680 { 681 int l2_assoc; 682 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 683 OCTEON_IS_MODEL(OCTEON_CN52XX) || 684 OCTEON_IS_MODEL(OCTEON_CN58XX) || 685 OCTEON_IS_MODEL(OCTEON_CN50XX) || OCTEON_IS_MODEL(OCTEON_CN38XX)) 686 l2_assoc = 8; 687 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || 688 OCTEON_IS_MODEL(OCTEON_CN30XX)) 689 l2_assoc = 4; 690 else { 691 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 692 l2_assoc = 8; 693 } 694 695 /* Check to see if part of the cache is disabled */ 696 if (cvmx_fuse_read(265)) 697 l2_assoc = l2_assoc >> 2; 698 else if (cvmx_fuse_read(264)) 699 l2_assoc = l2_assoc >> 1; 700 701 return l2_assoc; 702 } 703 704 /** 705 * Flush a line from the L2 cache 706 * This should only be called from one core at a time, as this routine 707 * sets the core to the 'debug' core in order to flush the line. 708 * 709 * @assoc: Association (or way) to flush 710 * @index: Index to flush 711 */ 712 void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index) 713 { 714 union cvmx_l2c_dbg l2cdbg; 715 716 l2cdbg.u64 = 0; 717 l2cdbg.s.ppnum = cvmx_get_core_num(); 718 l2cdbg.s.finv = 1; 719 720 l2cdbg.s.set = assoc; 721 /* 722 * Enter debug mode, and make sure all other writes complete 723 * before we enter debug mode. 724 */ 725 asm volatile ("sync" : : : "memory"); 726 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 727 cvmx_read_csr(CVMX_L2C_DBG); 728 729 CVMX_PREPARE_FOR_STORE(((1ULL << 63) + (index) * 128), 0); 730 /* Exit debug mode */ 731 asm volatile ("sync" : : : "memory"); 732 cvmx_write_csr(CVMX_L2C_DBG, 0); 733 cvmx_read_csr(CVMX_L2C_DBG); 734 } 735