18c2ecf20Sopenharmony_ci/***********************license start*************** 28c2ecf20Sopenharmony_ci * Author: Cavium Networks 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Contact: support@caviumnetworks.com 58c2ecf20Sopenharmony_ci * This file is part of the OCTEON SDK 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2017 Cavium, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 158c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 168c2ecf20Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more 178c2ecf20Sopenharmony_ci * details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 208c2ecf20Sopenharmony_ci * along with this file; if not, write to the Free Software 218c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 228c2ecf20Sopenharmony_ci * or visit http://www.gnu.org/licenses/. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This file may also be available under a different license from Cavium. 258c2ecf20Sopenharmony_ci * Contact Cavium Networks for more information 268c2ecf20Sopenharmony_ci ***********************license end**************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Implementation of the Level 2 Cache (L2C) control, 308c2ecf20Sopenharmony_ci * measurement, and debugging facilities. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/compiler.h> 348c2ecf20Sopenharmony_ci#include <linux/irqflags.h> 358c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx.h> 368c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-l2c.h> 378c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-spinlock.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * This spinlock is used internally to ensure that only one core is 418c2ecf20Sopenharmony_ci * performing certain L2 operations at a time. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * NOTE: This only protects calls from within a single application - 448c2ecf20Sopenharmony_ci * if multiple applications or operating systems are running, then it 458c2ecf20Sopenharmony_ci * is up to the user program to coordinate between them. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic cvmx_spinlock_t cvmx_l2c_spinlock; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint cvmx_l2c_get_core_way_partition(uint32_t core) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci uint32_t field; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Validate the core number */ 548c2ecf20Sopenharmony_ci if (core >= cvmx_octeon_num_cores()) 558c2ecf20Sopenharmony_ci return -1; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 588c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_WPAR_PPX(core)) & 0xffff; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * Use the lower two bits of the coreNumber to determine the 628c2ecf20Sopenharmony_ci * bit offset of the UMSK[] field in the L2C_SPAR register. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci field = (core & 0x3) * 8; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * Return the UMSK[] field from the appropriate L2C_SPAR 688c2ecf20Sopenharmony_ci * register based on the coreNumber. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci switch (core & 0xC) { 728c2ecf20Sopenharmony_ci case 0x0: 738c2ecf20Sopenharmony_ci return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> field; 748c2ecf20Sopenharmony_ci case 0x4: 758c2ecf20Sopenharmony_ci return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> field; 768c2ecf20Sopenharmony_ci case 0x8: 778c2ecf20Sopenharmony_ci return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> field; 788c2ecf20Sopenharmony_ci case 0xC: 798c2ecf20Sopenharmony_ci return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> field; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci uint32_t field; 878c2ecf20Sopenharmony_ci uint32_t valid_mask; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci mask &= valid_mask; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* A UMSK setting which blocks all L2C Ways is an error on some chips */ 948c2ecf20Sopenharmony_ci if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX)) 958c2ecf20Sopenharmony_ci return -1; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Validate the core number */ 988c2ecf20Sopenharmony_ci if (core >= cvmx_octeon_num_cores()) 998c2ecf20Sopenharmony_ci return -1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 1028c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_WPAR_PPX(core), mask); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Use the lower two bits of core to determine the bit offset of the 1088c2ecf20Sopenharmony_ci * UMSK[] field in the L2C_SPAR register. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci field = (core & 0x3) * 8; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 1138c2ecf20Sopenharmony_ci * Assign the new mask setting to the UMSK[] field in the appropriate 1148c2ecf20Sopenharmony_ci * L2C_SPAR register based on the core_num. 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci switch (core & 0xC) { 1188c2ecf20Sopenharmony_ci case 0x0: 1198c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_SPAR0, 1208c2ecf20Sopenharmony_ci (cvmx_read_csr(CVMX_L2C_SPAR0) & ~(0xFF << field)) | 1218c2ecf20Sopenharmony_ci mask << field); 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case 0x4: 1248c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_SPAR1, 1258c2ecf20Sopenharmony_ci (cvmx_read_csr(CVMX_L2C_SPAR1) & ~(0xFF << field)) | 1268c2ecf20Sopenharmony_ci mask << field); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case 0x8: 1298c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_SPAR2, 1308c2ecf20Sopenharmony_ci (cvmx_read_csr(CVMX_L2C_SPAR2) & ~(0xFF << field)) | 1318c2ecf20Sopenharmony_ci mask << field); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case 0xC: 1348c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_SPAR3, 1358c2ecf20Sopenharmony_ci (cvmx_read_csr(CVMX_L2C_SPAR3) & ~(0xFF << field)) | 1368c2ecf20Sopenharmony_ci mask << field); 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ciint cvmx_l2c_set_hw_way_partition(uint32_t mask) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci uint32_t valid_mask; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 1478c2ecf20Sopenharmony_ci mask &= valid_mask; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* A UMSK setting which blocks all L2C Ways is an error on some chips */ 1508c2ecf20Sopenharmony_ci if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX)) 1518c2ecf20Sopenharmony_ci return -1; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 1548c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_WPAR_IOBX(0), mask); 1558c2ecf20Sopenharmony_ci else 1568c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_SPAR4, 1578c2ecf20Sopenharmony_ci (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask); 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciint cvmx_l2c_get_hw_way_partition(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 1648c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_WPAR_IOBX(0)) & 0xffff; 1658c2ecf20Sopenharmony_ci else 1668c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event, 1708c2ecf20Sopenharmony_ci uint32_t clear_on_read) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) { 1738c2ecf20Sopenharmony_ci union cvmx_l2c_pfctl pfctl; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci switch (counter) { 1788c2ecf20Sopenharmony_ci case 0: 1798c2ecf20Sopenharmony_ci pfctl.s.cnt0sel = event; 1808c2ecf20Sopenharmony_ci pfctl.s.cnt0ena = 1; 1818c2ecf20Sopenharmony_ci pfctl.s.cnt0rdclr = clear_on_read; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case 1: 1848c2ecf20Sopenharmony_ci pfctl.s.cnt1sel = event; 1858c2ecf20Sopenharmony_ci pfctl.s.cnt1ena = 1; 1868c2ecf20Sopenharmony_ci pfctl.s.cnt1rdclr = clear_on_read; 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci case 2: 1898c2ecf20Sopenharmony_ci pfctl.s.cnt2sel = event; 1908c2ecf20Sopenharmony_ci pfctl.s.cnt2ena = 1; 1918c2ecf20Sopenharmony_ci pfctl.s.cnt2rdclr = clear_on_read; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case 3: 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci pfctl.s.cnt3sel = event; 1968c2ecf20Sopenharmony_ci pfctl.s.cnt3ena = 1; 1978c2ecf20Sopenharmony_ci pfctl.s.cnt3rdclr = clear_on_read; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64); 2028c2ecf20Sopenharmony_ci } else { 2038c2ecf20Sopenharmony_ci union cvmx_l2c_tadx_prf l2c_tadx_prf; 2048c2ecf20Sopenharmony_ci int tad; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci cvmx_dprintf("L2C performance counter events are different for this chip, mapping 'event' to cvmx_l2c_tad_event_t\n"); 2078c2ecf20Sopenharmony_ci if (clear_on_read) 2088c2ecf20Sopenharmony_ci cvmx_dprintf("L2C counters don't support clear on read for this chip\n"); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci l2c_tadx_prf.u64 = cvmx_read_csr(CVMX_L2C_TADX_PRF(0)); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci switch (counter) { 2138c2ecf20Sopenharmony_ci case 0: 2148c2ecf20Sopenharmony_ci l2c_tadx_prf.s.cnt0sel = event; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case 1: 2178c2ecf20Sopenharmony_ci l2c_tadx_prf.s.cnt1sel = event; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case 2: 2208c2ecf20Sopenharmony_ci l2c_tadx_prf.s.cnt2sel = event; 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci default: 2238c2ecf20Sopenharmony_ci case 3: 2248c2ecf20Sopenharmony_ci l2c_tadx_prf.s.cnt3sel = event; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci for (tad = 0; tad < CVMX_L2C_TADS; tad++) 2288c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_TADX_PRF(tad), 2298c2ecf20Sopenharmony_ci l2c_tadx_prf.u64); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciuint64_t cvmx_l2c_read_perf(uint32_t counter) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci switch (counter) { 2368c2ecf20Sopenharmony_ci case 0: 2378c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 2388c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_PFC0); 2398c2ecf20Sopenharmony_ci else { 2408c2ecf20Sopenharmony_ci uint64_t counter = 0; 2418c2ecf20Sopenharmony_ci int tad; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for (tad = 0; tad < CVMX_L2C_TADS; tad++) 2448c2ecf20Sopenharmony_ci counter += cvmx_read_csr(CVMX_L2C_TADX_PFC0(tad)); 2458c2ecf20Sopenharmony_ci return counter; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci case 1: 2488c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 2498c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_PFC1); 2508c2ecf20Sopenharmony_ci else { 2518c2ecf20Sopenharmony_ci uint64_t counter = 0; 2528c2ecf20Sopenharmony_ci int tad; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci for (tad = 0; tad < CVMX_L2C_TADS; tad++) 2558c2ecf20Sopenharmony_ci counter += cvmx_read_csr(CVMX_L2C_TADX_PFC1(tad)); 2568c2ecf20Sopenharmony_ci return counter; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci case 2: 2598c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 2608c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_PFC2); 2618c2ecf20Sopenharmony_ci else { 2628c2ecf20Sopenharmony_ci uint64_t counter = 0; 2638c2ecf20Sopenharmony_ci int tad; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci for (tad = 0; tad < CVMX_L2C_TADS; tad++) 2668c2ecf20Sopenharmony_ci counter += cvmx_read_csr(CVMX_L2C_TADX_PFC2(tad)); 2678c2ecf20Sopenharmony_ci return counter; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci case 3: 2708c2ecf20Sopenharmony_ci default: 2718c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 2728c2ecf20Sopenharmony_ci return cvmx_read_csr(CVMX_L2C_PFC3); 2738c2ecf20Sopenharmony_ci else { 2748c2ecf20Sopenharmony_ci uint64_t counter = 0; 2758c2ecf20Sopenharmony_ci int tad; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci for (tad = 0; tad < CVMX_L2C_TADS; tad++) 2788c2ecf20Sopenharmony_ci counter += cvmx_read_csr(CVMX_L2C_TADX_PFC3(tad)); 2798c2ecf20Sopenharmony_ci return counter; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/** 2858c2ecf20Sopenharmony_ci * @INTERNAL 2868c2ecf20Sopenharmony_ci * Helper function use to fault in cache lines for L2 cache locking 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci * @addr: Address of base of memory region to read into L2 cache 2898c2ecf20Sopenharmony_ci * @len: Length (in bytes) of region to fault in 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic void fault_in(uint64_t addr, int len) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci char *ptr; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * Adjust addr and length so we get all cache lines even for 2978c2ecf20Sopenharmony_ci * small ranges spanning two cache lines. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci len += addr & CVMX_CACHE_LINE_MASK; 3008c2ecf20Sopenharmony_ci addr &= ~CVMX_CACHE_LINE_MASK; 3018c2ecf20Sopenharmony_ci ptr = cvmx_phys_to_ptr(addr); 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * Invalidate L1 cache to make sure all loads result in data 3048c2ecf20Sopenharmony_ci * being in L2. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci CVMX_DCACHE_INVALIDATE; 3078c2ecf20Sopenharmony_ci while (len > 0) { 3088c2ecf20Sopenharmony_ci READ_ONCE(*ptr); 3098c2ecf20Sopenharmony_ci len -= CVMX_CACHE_LINE_SIZE; 3108c2ecf20Sopenharmony_ci ptr += CVMX_CACHE_LINE_SIZE; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciint cvmx_l2c_lock_line(uint64_t addr) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 3178c2ecf20Sopenharmony_ci int shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT; 3188c2ecf20Sopenharmony_ci uint64_t assoc = cvmx_l2c_get_num_assoc(); 3198c2ecf20Sopenharmony_ci uint64_t tag = addr >> shift; 3208c2ecf20Sopenharmony_ci uint64_t index = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, cvmx_l2c_address_to_index(addr) << CVMX_L2C_IDX_ADDR_SHIFT); 3218c2ecf20Sopenharmony_ci uint64_t way; 3228c2ecf20Sopenharmony_ci union cvmx_l2c_tadx_tag l2c_tadx_tag; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci CVMX_CACHE_LCKL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, addr), 0); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Make sure we were able to lock the line */ 3278c2ecf20Sopenharmony_ci for (way = 0; way < assoc; way++) { 3288c2ecf20Sopenharmony_ci CVMX_CACHE_LTGL2I(index | (way << shift), 0); 3298c2ecf20Sopenharmony_ci /* make sure CVMX_L2C_TADX_TAG is updated */ 3308c2ecf20Sopenharmony_ci CVMX_SYNC; 3318c2ecf20Sopenharmony_ci l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0)); 3328c2ecf20Sopenharmony_ci if (l2c_tadx_tag.s.valid && l2c_tadx_tag.s.tag == tag) 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Check if a valid line is found */ 3378c2ecf20Sopenharmony_ci if (way >= assoc) { 3388c2ecf20Sopenharmony_ci /* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: line not found for locking at 0x%llx address\n", (unsigned long long)addr); */ 3398c2ecf20Sopenharmony_ci return -1; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Check if lock bit is not set */ 3438c2ecf20Sopenharmony_ci if (!l2c_tadx_tag.s.lock) { 3448c2ecf20Sopenharmony_ci /* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: Not able to lock at 0x%llx address\n", (unsigned long long)addr); */ 3458c2ecf20Sopenharmony_ci return -1; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci return way; 3488c2ecf20Sopenharmony_ci } else { 3498c2ecf20Sopenharmony_ci int retval = 0; 3508c2ecf20Sopenharmony_ci union cvmx_l2c_dbg l2cdbg; 3518c2ecf20Sopenharmony_ci union cvmx_l2c_lckbase lckbase; 3528c2ecf20Sopenharmony_ci union cvmx_l2c_lckoff lckoff; 3538c2ecf20Sopenharmony_ci union cvmx_l2t_err l2t_err; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci cvmx_spinlock_lock(&cvmx_l2c_spinlock); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci l2cdbg.u64 = 0; 3588c2ecf20Sopenharmony_ci lckbase.u64 = 0; 3598c2ecf20Sopenharmony_ci lckoff.u64 = 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Clear l2t error bits if set */ 3628c2ecf20Sopenharmony_ci l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 3638c2ecf20Sopenharmony_ci l2t_err.s.lckerr = 1; 3648c2ecf20Sopenharmony_ci l2t_err.s.lckerr2 = 1; 3658c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci addr &= ~CVMX_CACHE_LINE_MASK; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Set this core as debug core */ 3708c2ecf20Sopenharmony_ci l2cdbg.s.ppnum = cvmx_get_core_num(); 3718c2ecf20Sopenharmony_ci CVMX_SYNC; 3728c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 3738c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_DBG); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */ 3768c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64); 3778c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_LCKOFF); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (((union cvmx_l2c_cfg)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) { 3808c2ecf20Sopenharmony_ci int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1; 3818c2ecf20Sopenharmony_ci uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci lckbase.s.lck_base = addr_tmp >> 7; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci lckbase.s.lck_base = addr >> 7; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci lckbase.s.lck_ena = 1; 3908c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 3918c2ecf20Sopenharmony_ci /* Make sure it gets there */ 3928c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_LCKBASE); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci fault_in(addr, CVMX_CACHE_LINE_SIZE); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci lckbase.s.lck_ena = 0; 3978c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 3988c2ecf20Sopenharmony_ci /* Make sure it gets there */ 3998c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_LCKBASE); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Stop being debug core */ 4028c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_DBG, 0); 4038c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_DBG); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 4068c2ecf20Sopenharmony_ci if (l2t_err.s.lckerr || l2t_err.s.lckerr2) 4078c2ecf20Sopenharmony_ci retval = 1; /* We were unable to lock the line */ 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 4108c2ecf20Sopenharmony_ci return retval; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciint cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int retval = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Round start/end to cache line boundaries */ 4198c2ecf20Sopenharmony_ci len += start & CVMX_CACHE_LINE_MASK; 4208c2ecf20Sopenharmony_ci start &= ~CVMX_CACHE_LINE_MASK; 4218c2ecf20Sopenharmony_ci len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci while (len) { 4248c2ecf20Sopenharmony_ci retval += cvmx_l2c_lock_line(start); 4258c2ecf20Sopenharmony_ci start += CVMX_CACHE_LINE_SIZE; 4268c2ecf20Sopenharmony_ci len -= CVMX_CACHE_LINE_SIZE; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci return retval; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_civoid cvmx_l2c_flush(void) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci uint64_t assoc, set; 4348c2ecf20Sopenharmony_ci uint64_t n_assoc, n_set; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci n_set = cvmx_l2c_get_num_sets(); 4378c2ecf20Sopenharmony_ci n_assoc = cvmx_l2c_get_num_assoc(); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { 4408c2ecf20Sopenharmony_ci uint64_t address; 4418c2ecf20Sopenharmony_ci /* These may look like constants, but they aren't... */ 4428c2ecf20Sopenharmony_ci int assoc_shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT; 4438c2ecf20Sopenharmony_ci int set_shift = CVMX_L2C_IDX_ADDR_SHIFT; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci for (set = 0; set < n_set; set++) { 4468c2ecf20Sopenharmony_ci for (assoc = 0; assoc < n_assoc; assoc++) { 4478c2ecf20Sopenharmony_ci address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 4488c2ecf20Sopenharmony_ci (assoc << assoc_shift) | (set << set_shift)); 4498c2ecf20Sopenharmony_ci CVMX_CACHE_WBIL2I(address, 0); 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } else { 4538c2ecf20Sopenharmony_ci for (set = 0; set < n_set; set++) 4548c2ecf20Sopenharmony_ci for (assoc = 0; assoc < n_assoc; assoc++) 4558c2ecf20Sopenharmony_ci cvmx_l2c_flush_line(assoc, set); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciint cvmx_l2c_unlock_line(uint64_t address) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 4648c2ecf20Sopenharmony_ci int assoc; 4658c2ecf20Sopenharmony_ci union cvmx_l2c_tag tag; 4668c2ecf20Sopenharmony_ci uint32_t tag_addr; 4678c2ecf20Sopenharmony_ci uint32_t index = cvmx_l2c_address_to_index(address); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * For 63XX, we can flush a line by using the physical 4738c2ecf20Sopenharmony_ci * address directly, so finding the cache line used by 4748c2ecf20Sopenharmony_ci * the address is only required to provide the proper 4758c2ecf20Sopenharmony_ci * return value for the function. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) { 4788c2ecf20Sopenharmony_ci tag = cvmx_l2c_get_tag(assoc, index); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (tag.s.V && (tag.s.addr == tag_addr)) { 4818c2ecf20Sopenharmony_ci CVMX_CACHE_WBIL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0); 4828c2ecf20Sopenharmony_ci return tag.s.L; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci int assoc; 4878c2ecf20Sopenharmony_ci union cvmx_l2c_tag tag; 4888c2ecf20Sopenharmony_ci uint32_t tag_addr; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci uint32_t index = cvmx_l2c_address_to_index(address); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Compute portion of address that is stored in tag */ 4938c2ecf20Sopenharmony_ci tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 4948c2ecf20Sopenharmony_ci for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) { 4958c2ecf20Sopenharmony_ci tag = cvmx_l2c_get_tag(assoc, index); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (tag.s.V && (tag.s.addr == tag_addr)) { 4988c2ecf20Sopenharmony_ci cvmx_l2c_flush_line(assoc, index); 4998c2ecf20Sopenharmony_ci return tag.s.L; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciint cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci int num_unlocked = 0; 5098c2ecf20Sopenharmony_ci /* Round start/end to cache line boundaries */ 5108c2ecf20Sopenharmony_ci len += start & CVMX_CACHE_LINE_MASK; 5118c2ecf20Sopenharmony_ci start &= ~CVMX_CACHE_LINE_MASK; 5128c2ecf20Sopenharmony_ci len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; 5138c2ecf20Sopenharmony_ci while (len > 0) { 5148c2ecf20Sopenharmony_ci num_unlocked += cvmx_l2c_unlock_line(start); 5158c2ecf20Sopenharmony_ci start += CVMX_CACHE_LINE_SIZE; 5168c2ecf20Sopenharmony_ci len -= CVMX_CACHE_LINE_SIZE; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return num_unlocked; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/* 5238c2ecf20Sopenharmony_ci * Internal l2c tag types. These are converted to a generic structure 5248c2ecf20Sopenharmony_ci * that can be used on all chips. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ciunion __cvmx_l2c_tag { 5278c2ecf20Sopenharmony_ci uint64_t u64; 5288c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn50xx { 5298c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t reserved:40, 5308c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t V:1, /* Line valid */ 5318c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */ 5328c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t L:1, /* Line locked */ 5338c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */ 5348c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t addr:20, /* Phys addr (33..14) */ 5358c2ecf20Sopenharmony_ci ;)))))) 5368c2ecf20Sopenharmony_ci } cn50xx; 5378c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn30xx { 5388c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t reserved:41, 5398c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t V:1, /* Line valid */ 5408c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */ 5418c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t L:1, /* Line locked */ 5428c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */ 5438c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t addr:19, /* Phys addr (33..15) */ 5448c2ecf20Sopenharmony_ci ;)))))) 5458c2ecf20Sopenharmony_ci } cn30xx; 5468c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn31xx { 5478c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t reserved:42, 5488c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t V:1, /* Line valid */ 5498c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */ 5508c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t L:1, /* Line locked */ 5518c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */ 5528c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t addr:18, /* Phys addr (33..16) */ 5538c2ecf20Sopenharmony_ci ;)))))) 5548c2ecf20Sopenharmony_ci } cn31xx; 5558c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn38xx { 5568c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t reserved:43, 5578c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t V:1, /* Line valid */ 5588c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */ 5598c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t L:1, /* Line locked */ 5608c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */ 5618c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t addr:17, /* Phys addr (33..17) */ 5628c2ecf20Sopenharmony_ci ;)))))) 5638c2ecf20Sopenharmony_ci } cn38xx; 5648c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn58xx { 5658c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t reserved:44, 5668c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t V:1, /* Line valid */ 5678c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */ 5688c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t L:1, /* Line locked */ 5698c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */ 5708c2ecf20Sopenharmony_ci __BITFIELD_FIELD(uint64_t addr:16, /* Phys addr (33..18) */ 5718c2ecf20Sopenharmony_ci ;)))))) 5728c2ecf20Sopenharmony_ci } cn58xx; 5738c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn58xx cn56xx; /* 2048 sets */ 5748c2ecf20Sopenharmony_ci struct cvmx_l2c_tag_cn31xx cn52xx; /* 512 sets */ 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/** 5798c2ecf20Sopenharmony_ci * @INTERNAL 5808c2ecf20Sopenharmony_ci * Function to read a L2C tag. This code make the current core 5818c2ecf20Sopenharmony_ci * the 'debug core' for the L2. This code must only be executed by 5828c2ecf20Sopenharmony_ci * 1 core at a time. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci * @assoc: Association (way) of the tag to dump 5858c2ecf20Sopenharmony_ci * @index: Index of the cacheline 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * Returns The Octeon model specific tag structure. This is 5888c2ecf20Sopenharmony_ci * translated by a wrapper function to a generic form that is 5898c2ecf20Sopenharmony_ci * easier for applications to use. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_cistatic union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci uint64_t debug_tag_addr = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, (index << 7) + 96); 5958c2ecf20Sopenharmony_ci uint64_t core = cvmx_get_core_num(); 5968c2ecf20Sopenharmony_ci union __cvmx_l2c_tag tag_val; 5978c2ecf20Sopenharmony_ci uint64_t dbg_addr = CVMX_L2C_DBG; 5988c2ecf20Sopenharmony_ci unsigned long flags; 5998c2ecf20Sopenharmony_ci union cvmx_l2c_dbg debug_val; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci debug_val.u64 = 0; 6028c2ecf20Sopenharmony_ci /* 6038c2ecf20Sopenharmony_ci * For low core count parts, the core number is always small 6048c2ecf20Sopenharmony_ci * enough to stay in the correct field and not set any 6058c2ecf20Sopenharmony_ci * reserved bits. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci debug_val.s.ppnum = core; 6088c2ecf20Sopenharmony_ci debug_val.s.l2t = 1; 6098c2ecf20Sopenharmony_ci debug_val.s.set = assoc; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci local_irq_save(flags); 6128c2ecf20Sopenharmony_ci /* 6138c2ecf20Sopenharmony_ci * Make sure core is quiet (no prefetches, etc.) before 6148c2ecf20Sopenharmony_ci * entering debug mode. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci CVMX_SYNC; 6178c2ecf20Sopenharmony_ci /* Flush L1 to make sure debug load misses L1 */ 6188c2ecf20Sopenharmony_ci CVMX_DCACHE_INVALIDATE; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* 6218c2ecf20Sopenharmony_ci * The following must be done in assembly as when in debug 6228c2ecf20Sopenharmony_ci * mode all data loads from L2 return special debug data, not 6238c2ecf20Sopenharmony_ci * normal memory contents. Also, interrupts must be disabled, 6248c2ecf20Sopenharmony_ci * since if an interrupt occurs while in debug mode the ISR 6258c2ecf20Sopenharmony_ci * will get debug data from all its memory * reads instead of 6268c2ecf20Sopenharmony_ci * the contents of memory. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci asm volatile ( 6308c2ecf20Sopenharmony_ci ".set push\n\t" 6318c2ecf20Sopenharmony_ci ".set mips64\n\t" 6328c2ecf20Sopenharmony_ci ".set noreorder\n\t" 6338c2ecf20Sopenharmony_ci "sd %[dbg_val], 0(%[dbg_addr])\n\t" /* Enter debug mode, wait for store */ 6348c2ecf20Sopenharmony_ci "ld $0, 0(%[dbg_addr])\n\t" 6358c2ecf20Sopenharmony_ci "ld %[tag_val], 0(%[tag_addr])\n\t" /* Read L2C tag data */ 6368c2ecf20Sopenharmony_ci "sd $0, 0(%[dbg_addr])\n\t" /* Exit debug mode, wait for store */ 6378c2ecf20Sopenharmony_ci "ld $0, 0(%[dbg_addr])\n\t" 6388c2ecf20Sopenharmony_ci "cache 9, 0($0)\n\t" /* Invalidate dcache to discard debug data */ 6398c2ecf20Sopenharmony_ci ".set pop" 6408c2ecf20Sopenharmony_ci : [tag_val] "=r" (tag_val) 6418c2ecf20Sopenharmony_ci : [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr) 6428c2ecf20Sopenharmony_ci : "memory"); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci local_irq_restore(flags); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return tag_val; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ciunion cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci union cvmx_l2c_tag tag; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci tag.u64 = 0; 6558c2ecf20Sopenharmony_ci if ((int)association >= cvmx_l2c_get_num_assoc()) { 6568c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_l2c_get_tag association out of range\n"); 6578c2ecf20Sopenharmony_ci return tag; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci if ((int)index >= cvmx_l2c_get_num_sets()) { 6608c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_l2c_get_tag index out of range (arg: %d, max: %d)\n", 6618c2ecf20Sopenharmony_ci (int)index, cvmx_l2c_get_num_sets()); 6628c2ecf20Sopenharmony_ci return tag; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 6658c2ecf20Sopenharmony_ci union cvmx_l2c_tadx_tag l2c_tadx_tag; 6668c2ecf20Sopenharmony_ci uint64_t address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 6678c2ecf20Sopenharmony_ci (association << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) | 6688c2ecf20Sopenharmony_ci (index << CVMX_L2C_IDX_ADDR_SHIFT)); 6698c2ecf20Sopenharmony_ci /* 6708c2ecf20Sopenharmony_ci * Use L2 cache Index load tag cache instruction, as 6718c2ecf20Sopenharmony_ci * hardware loads the virtual tag for the L2 cache 6728c2ecf20Sopenharmony_ci * block with the contents of L2C_TAD0_TAG 6738c2ecf20Sopenharmony_ci * register. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_ci CVMX_CACHE_LTGL2I(address, 0); 6768c2ecf20Sopenharmony_ci CVMX_SYNC; /* make sure CVMX_L2C_TADX_TAG is updated */ 6778c2ecf20Sopenharmony_ci l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0)); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci tag.s.V = l2c_tadx_tag.s.valid; 6808c2ecf20Sopenharmony_ci tag.s.D = l2c_tadx_tag.s.dirty; 6818c2ecf20Sopenharmony_ci tag.s.L = l2c_tadx_tag.s.lock; 6828c2ecf20Sopenharmony_ci tag.s.U = l2c_tadx_tag.s.use; 6838c2ecf20Sopenharmony_ci tag.s.addr = l2c_tadx_tag.s.tag; 6848c2ecf20Sopenharmony_ci } else { 6858c2ecf20Sopenharmony_ci union __cvmx_l2c_tag tmp_tag; 6868c2ecf20Sopenharmony_ci /* __read_l2_tag is intended for internal use only */ 6878c2ecf20Sopenharmony_ci tmp_tag = __read_l2_tag(association, index); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * Convert all tag structure types to generic version, 6918c2ecf20Sopenharmony_ci * as it can represent all models. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { 6948c2ecf20Sopenharmony_ci tag.s.V = tmp_tag.cn58xx.V; 6958c2ecf20Sopenharmony_ci tag.s.D = tmp_tag.cn58xx.D; 6968c2ecf20Sopenharmony_ci tag.s.L = tmp_tag.cn58xx.L; 6978c2ecf20Sopenharmony_ci tag.s.U = tmp_tag.cn58xx.U; 6988c2ecf20Sopenharmony_ci tag.s.addr = tmp_tag.cn58xx.addr; 6998c2ecf20Sopenharmony_ci } else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { 7008c2ecf20Sopenharmony_ci tag.s.V = tmp_tag.cn38xx.V; 7018c2ecf20Sopenharmony_ci tag.s.D = tmp_tag.cn38xx.D; 7028c2ecf20Sopenharmony_ci tag.s.L = tmp_tag.cn38xx.L; 7038c2ecf20Sopenharmony_ci tag.s.U = tmp_tag.cn38xx.U; 7048c2ecf20Sopenharmony_ci tag.s.addr = tmp_tag.cn38xx.addr; 7058c2ecf20Sopenharmony_ci } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { 7068c2ecf20Sopenharmony_ci tag.s.V = tmp_tag.cn31xx.V; 7078c2ecf20Sopenharmony_ci tag.s.D = tmp_tag.cn31xx.D; 7088c2ecf20Sopenharmony_ci tag.s.L = tmp_tag.cn31xx.L; 7098c2ecf20Sopenharmony_ci tag.s.U = tmp_tag.cn31xx.U; 7108c2ecf20Sopenharmony_ci tag.s.addr = tmp_tag.cn31xx.addr; 7118c2ecf20Sopenharmony_ci } else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) { 7128c2ecf20Sopenharmony_ci tag.s.V = tmp_tag.cn30xx.V; 7138c2ecf20Sopenharmony_ci tag.s.D = tmp_tag.cn30xx.D; 7148c2ecf20Sopenharmony_ci tag.s.L = tmp_tag.cn30xx.L; 7158c2ecf20Sopenharmony_ci tag.s.U = tmp_tag.cn30xx.U; 7168c2ecf20Sopenharmony_ci tag.s.addr = tmp_tag.cn30xx.addr; 7178c2ecf20Sopenharmony_ci } else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { 7188c2ecf20Sopenharmony_ci tag.s.V = tmp_tag.cn50xx.V; 7198c2ecf20Sopenharmony_ci tag.s.D = tmp_tag.cn50xx.D; 7208c2ecf20Sopenharmony_ci tag.s.L = tmp_tag.cn50xx.L; 7218c2ecf20Sopenharmony_ci tag.s.U = tmp_tag.cn50xx.U; 7228c2ecf20Sopenharmony_ci tag.s.addr = tmp_tag.cn50xx.addr; 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci return tag; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciuint32_t cvmx_l2c_address_to_index(uint64_t addr) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT; 7338c2ecf20Sopenharmony_ci int indxalias = 0; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { 7368c2ecf20Sopenharmony_ci union cvmx_l2c_ctl l2c_ctl; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL); 7398c2ecf20Sopenharmony_ci indxalias = !l2c_ctl.s.disidxalias; 7408c2ecf20Sopenharmony_ci } else { 7418c2ecf20Sopenharmony_ci union cvmx_l2c_cfg l2c_cfg; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); 7448c2ecf20Sopenharmony_ci indxalias = l2c_cfg.s.idxalias; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (indxalias) { 7488c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 7498c2ecf20Sopenharmony_ci uint32_t a_14_12 = (idx / (CVMX_L2C_MEMBANK_SELECT_SIZE/(1<<CVMX_L2C_IDX_ADDR_SHIFT))) & 0x7; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci idx ^= idx / cvmx_l2c_get_num_sets(); 7528c2ecf20Sopenharmony_ci idx ^= a_14_12; 7538c2ecf20Sopenharmony_ci } else { 7548c2ecf20Sopenharmony_ci idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci idx &= CVMX_L2C_IDX_MASK; 7588c2ecf20Sopenharmony_ci return idx; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciint cvmx_l2c_get_cache_size_bytes(void) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci return cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() * 7648c2ecf20Sopenharmony_ci CVMX_CACHE_LINE_SIZE; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci/** 7688c2ecf20Sopenharmony_ci * Return log base 2 of the number of sets in the L2 cache 7698c2ecf20Sopenharmony_ci * Returns 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ciint cvmx_l2c_get_set_bits(void) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci int l2_set_bits; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) 7768c2ecf20Sopenharmony_ci l2_set_bits = 11; /* 2048 sets */ 7778c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) 7788c2ecf20Sopenharmony_ci l2_set_bits = 10; /* 1024 sets */ 7798c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 7808c2ecf20Sopenharmony_ci l2_set_bits = 9; /* 512 sets */ 7818c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 7828c2ecf20Sopenharmony_ci l2_set_bits = 8; /* 256 sets */ 7838c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 7848c2ecf20Sopenharmony_ci l2_set_bits = 7; /* 128 sets */ 7858c2ecf20Sopenharmony_ci else { 7868c2ecf20Sopenharmony_ci cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 7878c2ecf20Sopenharmony_ci l2_set_bits = 11; /* 2048 sets */ 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci return l2_set_bits; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/* Return the number of sets in the L2 Cache */ 7938c2ecf20Sopenharmony_ciint cvmx_l2c_get_num_sets(void) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci return 1 << cvmx_l2c_get_set_bits(); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/* Return the number of associations in the L2 Cache */ 7998c2ecf20Sopenharmony_ciint cvmx_l2c_get_num_assoc(void) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci int l2_assoc; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 8048c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN52XX) || 8058c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN58XX) || 8068c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN50XX) || 8078c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN38XX)) 8088c2ecf20Sopenharmony_ci l2_assoc = 8; 8098c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 8108c2ecf20Sopenharmony_ci l2_assoc = 16; 8118c2ecf20Sopenharmony_ci else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || 8128c2ecf20Sopenharmony_ci OCTEON_IS_MODEL(OCTEON_CN30XX)) 8138c2ecf20Sopenharmony_ci l2_assoc = 4; 8148c2ecf20Sopenharmony_ci else { 8158c2ecf20Sopenharmony_ci cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); 8168c2ecf20Sopenharmony_ci l2_assoc = 8; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Check to see if part of the cache is disabled */ 8208c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 8218c2ecf20Sopenharmony_ci union cvmx_mio_fus_dat3 mio_fus_dat3; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci mio_fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci * cvmx_mio_fus_dat3.s.l2c_crip fuses map as follows 8268c2ecf20Sopenharmony_ci * <2> will be not used for 63xx 8278c2ecf20Sopenharmony_ci * <1> disables 1/2 ways 8288c2ecf20Sopenharmony_ci * <0> disables 1/4 ways 8298c2ecf20Sopenharmony_ci * They are cumulative, so for 63xx: 8308c2ecf20Sopenharmony_ci * <1> <0> 8318c2ecf20Sopenharmony_ci * 0 0 16-way 2MB cache 8328c2ecf20Sopenharmony_ci * 0 1 12-way 1.5MB cache 8338c2ecf20Sopenharmony_ci * 1 0 8-way 1MB cache 8348c2ecf20Sopenharmony_ci * 1 1 4-way 512KB cache 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (mio_fus_dat3.s.l2c_crip == 3) 8388c2ecf20Sopenharmony_ci l2_assoc = 4; 8398c2ecf20Sopenharmony_ci else if (mio_fus_dat3.s.l2c_crip == 2) 8408c2ecf20Sopenharmony_ci l2_assoc = 8; 8418c2ecf20Sopenharmony_ci else if (mio_fus_dat3.s.l2c_crip == 1) 8428c2ecf20Sopenharmony_ci l2_assoc = 12; 8438c2ecf20Sopenharmony_ci } else { 8448c2ecf20Sopenharmony_ci uint64_t l2d_fus3; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci l2d_fus3 = cvmx_read_csr(CVMX_L2D_FUS3); 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * Using shifts here, as bit position names are 8498c2ecf20Sopenharmony_ci * different for each model but they all mean the 8508c2ecf20Sopenharmony_ci * same. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ci if ((l2d_fus3 >> 35) & 0x1) 8538c2ecf20Sopenharmony_ci l2_assoc = l2_assoc >> 2; 8548c2ecf20Sopenharmony_ci else if ((l2d_fus3 >> 34) & 0x1) 8558c2ecf20Sopenharmony_ci l2_assoc = l2_assoc >> 1; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci return l2_assoc; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/** 8618c2ecf20Sopenharmony_ci * Flush a line from the L2 cache 8628c2ecf20Sopenharmony_ci * This should only be called from one core at a time, as this routine 8638c2ecf20Sopenharmony_ci * sets the core to the 'debug' core in order to flush the line. 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * @assoc: Association (or way) to flush 8668c2ecf20Sopenharmony_ci * @index: Index to flush 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_civoid cvmx_l2c_flush_line(uint32_t assoc, uint32_t index) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci /* Check the range of the index. */ 8718c2ecf20Sopenharmony_ci if (index > (uint32_t)cvmx_l2c_get_num_sets()) { 8728c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_l2c_flush_line index out of range.\n"); 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Check the range of association. */ 8778c2ecf20Sopenharmony_ci if (assoc > (uint32_t)cvmx_l2c_get_num_assoc()) { 8788c2ecf20Sopenharmony_ci cvmx_dprintf("ERROR: cvmx_l2c_flush_line association out of range.\n"); 8798c2ecf20Sopenharmony_ci return; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (OCTEON_IS_MODEL(OCTEON_CN63XX)) { 8838c2ecf20Sopenharmony_ci uint64_t address; 8848c2ecf20Sopenharmony_ci /* Create the address based on index and association. 8858c2ecf20Sopenharmony_ci * Bits<20:17> select the way of the cache block involved in 8868c2ecf20Sopenharmony_ci * the operation 8878c2ecf20Sopenharmony_ci * Bits<16:7> of the effect address select the index 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 8908c2ecf20Sopenharmony_ci (assoc << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) | 8918c2ecf20Sopenharmony_ci (index << CVMX_L2C_IDX_ADDR_SHIFT)); 8928c2ecf20Sopenharmony_ci CVMX_CACHE_WBIL2I(address, 0); 8938c2ecf20Sopenharmony_ci } else { 8948c2ecf20Sopenharmony_ci union cvmx_l2c_dbg l2cdbg; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci l2cdbg.u64 = 0; 8978c2ecf20Sopenharmony_ci if (!OCTEON_IS_MODEL(OCTEON_CN30XX)) 8988c2ecf20Sopenharmony_ci l2cdbg.s.ppnum = cvmx_get_core_num(); 8998c2ecf20Sopenharmony_ci l2cdbg.s.finv = 1; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci l2cdbg.s.set = assoc; 9028c2ecf20Sopenharmony_ci cvmx_spinlock_lock(&cvmx_l2c_spinlock); 9038c2ecf20Sopenharmony_ci /* 9048c2ecf20Sopenharmony_ci * Enter debug mode, and make sure all other writes 9058c2ecf20Sopenharmony_ci * complete before we enter debug mode 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci CVMX_SYNC; 9088c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 9098c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_DBG); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 9128c2ecf20Sopenharmony_ci index * CVMX_CACHE_LINE_SIZE), 9138c2ecf20Sopenharmony_ci 0); 9148c2ecf20Sopenharmony_ci /* Exit debug mode */ 9158c2ecf20Sopenharmony_ci CVMX_SYNC; 9168c2ecf20Sopenharmony_ci cvmx_write_csr(CVMX_L2C_DBG, 0); 9178c2ecf20Sopenharmony_ci cvmx_read_csr(CVMX_L2C_DBG); 9188c2ecf20Sopenharmony_ci cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci} 921