cvmx-l2c.c (210286) | cvmx-l2c.c (215990) |
---|---|
1/***********************license start*************** | 1/***********************license start*************** |
2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3 * reserved. | 2 * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 3 * reserved. |
4 * 5 * | 4 * 5 * |
6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: | 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: |
9 * | 9 * |
10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. | 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. |
12 * | 12 * |
13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * * Neither the name of Cavium Networks nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 * 23 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33 * 34 * 35 * For any questions regarding licensing please contact marketing@caviumnetworks.com 36 * | 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Networks nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. |
37 ***********************license end**************************************/ 38 39 40 41 42 43 | 38 ***********************license end**************************************/ 39 40 41 42 43 44 |
45 |
|
44/** 45 * @file 46 * 47 * Implementation of the Level 2 Cache (L2C) control, 48 * measurement, and debugging facilities. 49 * | 46/** 47 * @file 48 * 49 * Implementation of the Level 2 Cache (L2C) control, 50 * measurement, and debugging facilities. 51 * |
50 * <hr>$Revision: 41586 $<hr> | 52 * <hr>$Revision: 52004 $<hr> |
51 * 52 */ | 53 * 54 */ |
55#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 56#include <asm/octeon/cvmx.h> 57#include <asm/octeon/cvmx-l2c.h> 58#include <asm/octeon/cvmx-spinlock.h> 59#else 60#if !defined(__FreeBSD__) || !defined(_KERNEL) |
|
53#include "cvmx-config.h" | 61#include "cvmx-config.h" |
62#endif |
|
54#include "cvmx.h" 55#include "cvmx-l2c.h" 56#include "cvmx-spinlock.h" 57#include "cvmx-interrupt.h" | 63#include "cvmx.h" 64#include "cvmx-l2c.h" 65#include "cvmx-spinlock.h" 66#include "cvmx-interrupt.h" |
67#endif |
|
58 | 68 |
59 | |
60#ifndef CVMX_BUILD_FOR_LINUX_HOST 61/* This spinlock is used internally to ensure that only one core is performing 62** certain L2 operations at a time. 63** 64** NOTE: This only protects calls from within a single application - if multiple applications 65** or operating systems are running, then it is up to the user program to coordinate between them. 66*/ 67CVMX_SHARED cvmx_spinlock_t cvmx_l2c_spinlock; 68#endif 69 | 69#ifndef CVMX_BUILD_FOR_LINUX_HOST 70/* This spinlock is used internally to ensure that only one core is performing 71** certain L2 operations at a time. 72** 73** NOTE: This only protects calls from within a single application - if multiple applications 74** or operating systems are running, then it is up to the user program to coordinate between them. 75*/ 76CVMX_SHARED cvmx_spinlock_t cvmx_l2c_spinlock; 77#endif 78 |
70static inline int l2_size_half(void) 71{ 72 uint64_t val = cvmx_read_csr(CVMX_L2D_FUS3); 73 return !!(val & (1ull << 34)); 74} | 79CVMX_SHARED cvmx_spinlock_t cvmx_l2c_vrt_spinlock; 80 |
75int cvmx_l2c_get_core_way_partition(uint32_t core) 76{ 77 uint32_t field; 78 79 /* Validate the core number */ 80 if (core >= cvmx_octeon_num_cores()) 81 return -1; 82 | 81int cvmx_l2c_get_core_way_partition(uint32_t core) 82{ 83 uint32_t field; 84 85 /* Validate the core number */ 86 if (core >= cvmx_octeon_num_cores()) 87 return -1; 88 |
89 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 90 return (cvmx_read_csr(CVMX_L2C_WPAR_PPX(core)) & 0xffff); 91 |
|
83 /* Use the lower two bits of the coreNumber to determine the bit offset 84 * of the UMSK[] field in the L2C_SPAR register. 85 */ 86 field = (core & 0x3) * 8; 87 88 /* Return the UMSK[] field from the appropriate L2C_SPAR register based 89 * on the coreNumber. 90 */ --- 16 unchanged lines hidden (view full) --- 107{ 108 uint32_t field; 109 uint32_t valid_mask; 110 111 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 112 113 mask &= valid_mask; 114 | 92 /* Use the lower two bits of the coreNumber to determine the bit offset 93 * of the UMSK[] field in the L2C_SPAR register. 94 */ 95 field = (core & 0x3) * 8; 96 97 /* Return the UMSK[] field from the appropriate L2C_SPAR register based 98 * on the coreNumber. 99 */ --- 16 unchanged lines hidden (view full) --- 116{ 117 uint32_t field; 118 uint32_t valid_mask; 119 120 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 121 122 mask &= valid_mask; 123 |
115 /* A UMSK setting which blocks all L2C Ways is an error. */ 116 if (mask == valid_mask) | 124 /* A UMSK setting which blocks all L2C Ways is an error on some chips */ 125 if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX)) |
117 return -1; 118 119 /* Validate the core number */ 120 if (core >= cvmx_octeon_num_cores()) 121 return -1; 122 | 126 return -1; 127 128 /* Validate the core number */ 129 if (core >= cvmx_octeon_num_cores()) 130 return -1; 131 |
123 /* Check to make sure current mask & new mask don't block all ways */ 124 if (((mask | cvmx_l2c_get_core_way_partition(core)) & valid_mask) == valid_mask) 125 return -1; | 132 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 133 { 134 cvmx_write_csr(CVMX_L2C_WPAR_PPX(core), mask); 135 return 0; 136 } |
126 | 137 |
127 | |
128 /* Use the lower two bits of core to determine the bit offset of the 129 * UMSK[] field in the L2C_SPAR register. 130 */ 131 field = (core & 0x3) * 8; 132 133 /* Assign the new mask setting to the UMSK[] field in the appropriate 134 * L2C_SPAR register based on the core_num. 135 * --- 27 unchanged lines hidden (view full) --- 163 164int cvmx_l2c_set_hw_way_partition(uint32_t mask) 165{ 166 uint32_t valid_mask; 167 168 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 169 mask &= valid_mask; 170 | 138 /* Use the lower two bits of core to determine the bit offset of the 139 * UMSK[] field in the L2C_SPAR register. 140 */ 141 field = (core & 0x3) * 8; 142 143 /* Assign the new mask setting to the UMSK[] field in the appropriate 144 * L2C_SPAR register based on the core_num. 145 * --- 27 unchanged lines hidden (view full) --- 173 174int cvmx_l2c_set_hw_way_partition(uint32_t mask) 175{ 176 uint32_t valid_mask; 177 178 valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; 179 mask &= valid_mask; 180 |
171 /* A UMSK setting which blocks all L2C Ways is an error. */ 172 if (mask == valid_mask) | 181 /* A UMSK setting which blocks all L2C Ways is an error on some chips */ 182 if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX)) |
173 return -1; | 183 return -1; |
174 /* Check to make sure current mask & new mask don't block all ways */ 175 if (((mask | cvmx_l2c_get_hw_way_partition()) & valid_mask) == valid_mask) 176 return -1; | |
177 | 184 |
178 cvmx_write_csr(CVMX_L2C_SPAR4, (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask); | 185 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 186 cvmx_write_csr(CVMX_L2C_WPAR_IOBX(0), mask); 187 else 188 cvmx_write_csr(CVMX_L2C_SPAR4, (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask); |
179 return 0; 180} 181 182int cvmx_l2c_get_hw_way_partition(void) 183{ | 189 return 0; 190} 191 192int cvmx_l2c_get_hw_way_partition(void) 193{ |
184 return(cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF)); | 194 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 195 return(cvmx_read_csr(CVMX_L2C_WPAR_IOBX(0)) & 0xffff); 196 else 197 return(cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF)); |
185} 186 | 198} 199 |
187 | |
188void cvmx_l2c_config_perf(uint32_t counter, cvmx_l2c_event_t event, 189 uint32_t clear_on_read) | 200void cvmx_l2c_config_perf(uint32_t counter, cvmx_l2c_event_t event, 201 uint32_t clear_on_read) |
190{ cvmx_l2c_pfctl_t pfctl; | 202{ |
191 | 203 |
192 pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL); 193 194 switch (counter) | 204 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) |
195 { | 205 { |
196 case 0: 197 pfctl.s.cnt0sel = event; 198 pfctl.s.cnt0ena = 1; 199 if (!cvmx_octeon_is_pass1()) | 206 cvmx_l2c_pfctl_t pfctl; 207 208 pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL); 209 210 switch (counter) 211 { 212 case 0: 213 pfctl.s.cnt0sel = event; 214 pfctl.s.cnt0ena = 1; |
200 pfctl.s.cnt0rdclr = clear_on_read; | 215 pfctl.s.cnt0rdclr = clear_on_read; |
201 break; 202 case 1: 203 pfctl.s.cnt1sel = event; 204 pfctl.s.cnt1ena = 1; 205 if (!cvmx_octeon_is_pass1()) | 216 break; 217 case 1: 218 pfctl.s.cnt1sel = event; 219 pfctl.s.cnt1ena = 1; |
206 pfctl.s.cnt1rdclr = clear_on_read; | 220 pfctl.s.cnt1rdclr = clear_on_read; |
207 break; 208 case 2: 209 pfctl.s.cnt2sel = event; 210 pfctl.s.cnt2ena = 1; 211 if (!cvmx_octeon_is_pass1()) | 221 break; 222 case 2: 223 pfctl.s.cnt2sel = event; 224 pfctl.s.cnt2ena = 1; |
212 pfctl.s.cnt2rdclr = clear_on_read; | 225 pfctl.s.cnt2rdclr = clear_on_read; |
213 break; 214 case 3: 215 default: 216 pfctl.s.cnt3sel = event; 217 pfctl.s.cnt3ena = 1; 218 if (!cvmx_octeon_is_pass1()) | 226 break; 227 case 3: 228 default: 229 pfctl.s.cnt3sel = event; 230 pfctl.s.cnt3ena = 1; |
219 pfctl.s.cnt3rdclr = clear_on_read; | 231 pfctl.s.cnt3rdclr = clear_on_read; |
220 break; | 232 break; 233 } 234 235 cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64); |
221 } | 236 } |
237 else 238 { 239 cvmx_l2c_tadx_prf_t l2c_tadx_prf; 240 int tad; |
|
222 | 241 |
223 cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64); | 242 cvmx_warn("L2C performance counter events are different for this chip, mapping 'event' to cvmx_l2c_tad_event_t\n"); 243 244 cvmx_warn_if(clear_on_read, "L2C counters don't support clear on read for this chip\n"); 245 246 l2c_tadx_prf.u64 = cvmx_read_csr(CVMX_L2C_TADX_PRF(0)); 247 248 switch (counter) 249 { 250 case 0: 251 l2c_tadx_prf.s.cnt0sel = event; 252 break; 253 case 1: 254 l2c_tadx_prf.s.cnt1sel = event; 255 break; 256 case 2: 257 l2c_tadx_prf.s.cnt2sel = event; 258 break; 259 default: 260 case 3: 261 l2c_tadx_prf.s.cnt3sel = event; 262 break; 263 } 264 for (tad=0; tad<CVMX_L2C_TADS; tad++) 265 cvmx_write_csr(CVMX_L2C_TADX_PRF(tad), l2c_tadx_prf.u64); 266 } |
224} 225 226uint64_t cvmx_l2c_read_perf(uint32_t counter) 227{ 228 switch (counter) 229 { 230 case 0: | 267} 268 269uint64_t cvmx_l2c_read_perf(uint32_t counter) 270{ 271 switch (counter) 272 { 273 case 0: |
231 return(cvmx_read_csr(CVMX_L2C_PFC0)); | 274 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 275 return(cvmx_read_csr(CVMX_L2C_PFC0)); 276 else 277 { 278 uint64_t counter = 0; 279 int tad; 280 for (tad=0; tad<CVMX_L2C_TADS; tad++) 281 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC0(tad)); 282 return counter; 283 } |
232 case 1: | 284 case 1: |
233 return(cvmx_read_csr(CVMX_L2C_PFC1)); | 285 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 286 return(cvmx_read_csr(CVMX_L2C_PFC1)); 287 else 288 { 289 uint64_t counter = 0; 290 int tad; 291 for (tad=0; tad<CVMX_L2C_TADS; tad++) 292 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC1(tad)); 293 return counter; 294 } |
234 case 2: | 295 case 2: |
235 return(cvmx_read_csr(CVMX_L2C_PFC2)); | 296 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 297 return(cvmx_read_csr(CVMX_L2C_PFC2)); 298 else 299 { 300 uint64_t counter = 0; 301 int tad; 302 for (tad=0; tad<CVMX_L2C_TADS; tad++) 303 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC2(tad)); 304 return counter; 305 } |
236 case 3: 237 default: | 306 case 3: 307 default: |
238 return(cvmx_read_csr(CVMX_L2C_PFC3)); | 308 if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) 309 return(cvmx_read_csr(CVMX_L2C_PFC3)); 310 else 311 { 312 uint64_t counter = 0; 313 int tad; 314 for (tad=0; tad<CVMX_L2C_TADS; tad++) 315 counter += cvmx_read_csr(CVMX_L2C_TADX_PFC3(tad)); 316 return counter; 317 } |
239 } 240} 241 242#ifndef CVMX_BUILD_FOR_LINUX_HOST 243/** 244 * @INTERNAL 245 * Helper function use to fault in cache lines for L2 cache locking 246 * --- 15 unchanged lines hidden (view full) --- 262 dummy += *ptr; 263 len -= CVMX_CACHE_LINE_SIZE; 264 ptr += CVMX_CACHE_LINE_SIZE; 265 } 266} 267 268int cvmx_l2c_lock_line(uint64_t addr) 269{ | 318 } 319} 320 321#ifndef CVMX_BUILD_FOR_LINUX_HOST 322/** 323 * @INTERNAL 324 * Helper function use to fault in cache lines for L2 cache locking 325 * --- 15 unchanged lines hidden (view full) --- 341 dummy += *ptr; 342 len -= CVMX_CACHE_LINE_SIZE; 343 ptr += CVMX_CACHE_LINE_SIZE; 344 } 345} 346 347int cvmx_l2c_lock_line(uint64_t addr) 348{ |
270 int retval = 0; 271 cvmx_l2c_dbg_t l2cdbg; 272 cvmx_l2c_lckbase_t lckbase; 273 cvmx_l2c_lckoff_t lckoff; 274 cvmx_l2t_err_t l2t_err; 275 l2cdbg.u64 = 0; 276 lckbase.u64 = 0; 277 lckoff.u64 = 0; | 349 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 350 { 351 int shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT; 352 uint64_t assoc = cvmx_l2c_get_num_assoc(); 353 uint64_t tag = addr >> shift; 354 uint64_t index = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, cvmx_l2c_address_to_index(addr) << CVMX_L2C_IDX_ADDR_SHIFT); 355 uint64_t way; 356 cvmx_l2c_tadx_tag_t l2c_tadx_tag; |
278 | 357 |
279 cvmx_spinlock_lock(&cvmx_l2c_spinlock); | 358 CVMX_CACHE_LCKL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, addr), 0); |
280 | 359 |
281 /* Clear l2t error bits if set */ 282 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 283 l2t_err.s.lckerr = 1; 284 l2t_err.s.lckerr2 = 1; 285 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); | 360 /* Make sure we were able to lock the line */ 361 for (way = 0; way < assoc; way++) 362 { 363 CVMX_CACHE_LTGL2I(index | (way << shift), 0); 364 CVMX_SYNC; // make sure CVMX_L2C_TADX_TAG is updated 365 l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0)); 366 if (l2c_tadx_tag.s.valid && l2c_tadx_tag.s.tag == tag) 367 break; 368 } |
286 | 369 |
287 addr &= ~CVMX_CACHE_LINE_MASK; | 370 /* Check if a valid line is found */ 371 if (way >= assoc) 372 { 373 //cvmx_dprintf("ERROR: cvmx_l2c_lock_line: line not found for locking at 0x%llx address\n", (unsigned long long)addr); 374 return -1; 375 } |
288 | 376 |
289 /* Set this core as debug core */ 290 l2cdbg.s.ppnum = cvmx_get_core_num(); 291 CVMX_SYNC; 292 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 293 cvmx_read_csr(CVMX_L2C_DBG); | 377 /* Check if lock bit is not set */ 378 if (!l2c_tadx_tag.s.lock) 379 { 380 //cvmx_dprintf("ERROR: cvmx_l2c_lock_line: Not able to lock at 0x%llx address\n", (unsigned long long)addr); 381 return -1; 382 } |
294 | 383 |
295 lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */ 296 cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64); 297 cvmx_read_csr(CVMX_L2C_LCKOFF); 298 299 if (((cvmx_l2c_cfg_t)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) 300 { 301 int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1; 302 uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS; 303 lckbase.s.lck_base = addr_tmp >> 7; | 384 return way; |
304 } 305 else 306 { | 385 } 386 else 387 { |
307 lckbase.s.lck_base = addr >> 7; 308 } | 388 int retval = 0; 389 cvmx_l2c_dbg_t l2cdbg; 390 cvmx_l2c_lckbase_t lckbase; 391 cvmx_l2c_lckoff_t lckoff; 392 cvmx_l2t_err_t l2t_err; |
309 | 393 |
310 lckbase.s.lck_ena = 1; 311 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 312 cvmx_read_csr(CVMX_L2C_LCKBASE); // Make sure it gets there | 394 cvmx_spinlock_lock(&cvmx_l2c_spinlock); |
313 | 395 |
314 fault_in(addr, CVMX_CACHE_LINE_SIZE); | 396 l2cdbg.u64 = 0; 397 lckbase.u64 = 0; 398 lckoff.u64 = 0; |
315 | 399 |
316 lckbase.s.lck_ena = 0; 317 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 318 cvmx_read_csr(CVMX_L2C_LCKBASE); // Make sure it gets there | 400 /* Clear l2t error bits if set */ 401 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 402 l2t_err.s.lckerr = 1; 403 l2t_err.s.lckerr2 = 1; 404 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); |
319 | 405 |
320 /* Stop being debug core */ 321 cvmx_write_csr(CVMX_L2C_DBG, 0); 322 cvmx_read_csr(CVMX_L2C_DBG); | 406 addr &= ~CVMX_CACHE_LINE_MASK; |
323 | 407 |
324 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 325 if (l2t_err.s.lckerr || l2t_err.s.lckerr2) 326 retval = 1; /* We were unable to lock the line */ | 408 /* Set this core as debug core */ 409 l2cdbg.s.ppnum = cvmx_get_core_num(); 410 CVMX_SYNC; 411 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 412 cvmx_read_csr(CVMX_L2C_DBG); |
327 | 413 |
328 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | 414 lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */ 415 cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64); 416 cvmx_read_csr(CVMX_L2C_LCKOFF); |
329 | 417 |
330 return(retval); | 418 if (((cvmx_l2c_cfg_t)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) 419 { 420 int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1; 421 uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS; 422 lckbase.s.lck_base = addr_tmp >> 7; 423 } 424 else 425 { 426 lckbase.s.lck_base = addr >> 7; 427 } 428 429 lckbase.s.lck_ena = 1; 430 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 431 cvmx_read_csr(CVMX_L2C_LCKBASE); // Make sure it gets there 432 433 fault_in(addr, CVMX_CACHE_LINE_SIZE); 434 435 lckbase.s.lck_ena = 0; 436 cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); 437 cvmx_read_csr(CVMX_L2C_LCKBASE); // Make sure it gets there 438 439 /* Stop being debug core */ 440 cvmx_write_csr(CVMX_L2C_DBG, 0); 441 cvmx_read_csr(CVMX_L2C_DBG); 442 443 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 444 if (l2t_err.s.lckerr || l2t_err.s.lckerr2) 445 retval = 1; /* We were unable to lock the line */ 446 447 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 448 return(retval); 449 } |
331} 332 333 334int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len) 335{ 336 int retval = 0; 337 338 /* Round start/end to cache line boundaries */ --- 11 unchanged lines hidden (view full) --- 350 return(retval); 351} 352 353 354void cvmx_l2c_flush(void) 355{ 356 uint64_t assoc, set; 357 uint64_t n_assoc, n_set; | 450} 451 452 453int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len) 454{ 455 int retval = 0; 456 457 /* Round start/end to cache line boundaries */ --- 11 unchanged lines hidden (view full) --- 469 return(retval); 470} 471 472 473void cvmx_l2c_flush(void) 474{ 475 uint64_t assoc, set; 476 uint64_t n_assoc, n_set; |
358 cvmx_l2c_dbg_t l2cdbg; | |
359 | 477 |
360 cvmx_spinlock_lock(&cvmx_l2c_spinlock); | 478 n_set = cvmx_l2c_get_num_sets(); 479 n_assoc = cvmx_l2c_get_num_assoc(); |
361 | 480 |
362 l2cdbg.u64 = 0; 363 if (!OCTEON_IS_MODEL(OCTEON_CN30XX)) 364 l2cdbg.s.ppnum = cvmx_get_core_num(); 365 l2cdbg.s.finv = 1; 366 n_set = CVMX_L2_SETS; 367 n_assoc = l2_size_half() ? (CVMX_L2_ASSOC/2) : CVMX_L2_ASSOC ; 368 for(set=0; set < n_set; set++) | 481 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) |
369 { | 482 { |
370 for(assoc = 0; assoc < n_assoc; assoc++) | 483 uint64_t address; 484 /* These may look like constants, but they aren't... */ 485 int assoc_shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT; 486 int set_shift = CVMX_L2C_IDX_ADDR_SHIFT; 487 for (set=0; set < n_set; set++) |
371 { | 488 { |
372 l2cdbg.s.set = assoc; 373 /* Enter debug mode, and make sure all other writes complete before we 374 ** enter debug mode */ 375 CVMX_SYNCW; 376 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 377 cvmx_read_csr(CVMX_L2C_DBG); 378 379 CVMX_PREPARE_FOR_STORE (CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, set*CVMX_CACHE_LINE_SIZE), 0); 380 CVMX_SYNCW; /* Push STF out to L2 */ 381 /* Exit debug mode */ 382 CVMX_SYNC; 383 cvmx_write_csr(CVMX_L2C_DBG, 0); 384 cvmx_read_csr(CVMX_L2C_DBG); | 489 for(assoc=0; assoc < n_assoc; assoc++) 490 { 491 address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 492 (assoc << assoc_shift) | 493 (set << set_shift)); 494 CVMX_CACHE_WBIL2I(address, 0); 495 } |
385 } 386 } | 496 } 497 } |
387 388 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | 498 else 499 { 500 for (set=0; set < n_set; set++) 501 for(assoc=0; assoc < n_assoc; assoc++) 502 cvmx_l2c_flush_line(assoc, set); 503 } |
389} 390 391 392int cvmx_l2c_unlock_line(uint64_t address) 393{ | 504} 505 506 507int cvmx_l2c_unlock_line(uint64_t address) 508{ |
394 int assoc; 395 cvmx_l2c_tag_t tag; 396 cvmx_l2c_dbg_t l2cdbg; 397 uint32_t tag_addr; | |
398 | 509 |
399 uint32_t index = cvmx_l2c_address_to_index(address); 400 401 cvmx_spinlock_lock(&cvmx_l2c_spinlock); 402 /* Compute portion of address that is stored in tag */ 403 tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 404 for(assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) | 510 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) |
405 { | 511 { |
406 tag = cvmx_get_l2c_tag(assoc, index); | 512 int assoc; cvmx_l2c_tag_t tag; 513 uint32_t tag_addr; 514 uint32_t index = cvmx_l2c_address_to_index(address); |
407 | 515 |
408 if (tag.s.V && (tag.s.addr == tag_addr)) | 516 tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 517 518 /* For 63XX, we can flush a line by using the physical address directly, 519 ** so finding the cache line used by the address is only required to provide 520 ** the proper return value for the function. 521 */ 522 for(assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) |
409 { | 523 { |
410 l2cdbg.u64 = 0; 411 l2cdbg.s.ppnum = cvmx_get_core_num(); 412 l2cdbg.s.set = assoc; 413 l2cdbg.s.finv = 1; | 524 tag = cvmx_l2c_get_tag(assoc, index); |
414 | 525 |
415 CVMX_SYNC; 416 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); /* Enter debug mode */ 417 cvmx_read_csr(CVMX_L2C_DBG); | 526 if (tag.s.V && (tag.s.addr == tag_addr)) 527 { 528 CVMX_CACHE_WBIL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0); 529 return tag.s.L; 530 } 531 } 532 } 533 else 534 { 535 int assoc; 536 cvmx_l2c_tag_t tag; 537 uint32_t tag_addr; |
418 | 538 |
419 CVMX_PREPARE_FOR_STORE (CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0); 420 CVMX_SYNC; 421 /* Exit debug mode */ 422 cvmx_write_csr(CVMX_L2C_DBG, 0); 423 cvmx_read_csr(CVMX_L2C_DBG); 424 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 425 return tag.s.L; | 539 uint32_t index = cvmx_l2c_address_to_index(address); 540 541 /* Compute portion of address that is stored in tag */ 542 tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); 543 for(assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) 544 { 545 tag = cvmx_l2c_get_tag(assoc, index); 546 547 if (tag.s.V && (tag.s.addr == tag_addr)) 548 { 549 cvmx_l2c_flush_line(assoc, index); 550 return tag.s.L; 551 } |
426 } 427 } | 552 } 553 } |
428 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | |
429 return 0; 430} 431 432int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len) 433{ 434 int num_unlocked = 0; 435 /* Round start/end to cache line boundaries */ 436 len += start & CVMX_CACHE_LINE_MASK; --- 77 unchanged lines hidden (view full) --- 514 * @param index Index of the cacheline 515 * 516 * @return The Octeon model specific tag structure. This is translated by a wrapper 517 * function to a generic form that is easier for applications to use. 518 */ 519static __cvmx_l2c_tag_t __read_l2_tag(uint64_t assoc, uint64_t index) 520{ 521 | 554 return 0; 555} 556 557int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len) 558{ 559 int num_unlocked = 0; 560 /* Round start/end to cache line boundaries */ 561 len += start & CVMX_CACHE_LINE_MASK; --- 77 unchanged lines hidden (view full) --- 639 * @param index Index of the cacheline 640 * 641 * @return The Octeon model specific tag structure. This is translated by a wrapper 642 * function to a generic form that is easier for applications to use. 643 */ 644static __cvmx_l2c_tag_t __read_l2_tag(uint64_t assoc, uint64_t index) 645{ 646 |
522 uint64_t debug_tag_addr = (((1ULL << 63) | (index << 7)) + 96); | 647 uint64_t debug_tag_addr = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, (index << 7) + 96); |
523 uint64_t core = cvmx_get_core_num(); 524 __cvmx_l2c_tag_t tag_val; 525 uint64_t dbg_addr = CVMX_L2C_DBG; | 648 uint64_t core = cvmx_get_core_num(); 649 __cvmx_l2c_tag_t tag_val; 650 uint64_t dbg_addr = CVMX_L2C_DBG; |
526 uint32_t flags; | 651 unsigned long flags; |
527 528 cvmx_l2c_dbg_t debug_val; 529 debug_val.u64 = 0; 530 /* For low core count parts, the core number is always small enough 531 ** to stay in the correct field and not set any reserved bits */ 532 debug_val.s.ppnum = core; 533 debug_val.s.l2t = 1; 534 debug_val.s.set = assoc; 535 536 CVMX_SYNC; /* Make sure core is quiet (no prefetches, etc.) before entering debug mode */ 537 CVMX_DCACHE_INVALIDATE; /* Flush L1 to make sure debug load misses L1 */ 538 | 652 653 cvmx_l2c_dbg_t debug_val; 654 debug_val.u64 = 0; 655 /* For low core count parts, the core number is always small enough 656 ** to stay in the correct field and not set any reserved bits */ 657 debug_val.s.ppnum = core; 658 debug_val.s.l2t = 1; 659 debug_val.s.set = assoc; 660 661 CVMX_SYNC; /* Make sure core is quiet (no prefetches, etc.) before entering debug mode */ 662 CVMX_DCACHE_INVALIDATE; /* Flush L1 to make sure debug load misses L1 */ 663 |
539 flags = cvmx_interrupt_disable_save(); | 664 cvmx_local_irq_save(flags); |
540 541 /* The following must be done in assembly as when in debug mode all data loads from 542 ** L2 return special debug data, not normal memory contents. Also, interrupts must be disabled, 543 ** since if an interrupt occurs while in debug mode the ISR will get debug data from all its memory 544 ** reads instead of the contents of memory */ 545 546 asm volatile ( 547 " .set push \n" 548 " .set mips64 \n" 549 " .set noreorder \n" 550 " sd %[dbg_val], 0(%[dbg_addr]) \n" /* Enter debug mode, wait for store */ 551 " ld $0, 0(%[dbg_addr]) \n" 552 " ld %[tag_val], 0(%[tag_addr]) \n" /* Read L2C tag data */ 553 " sd $0, 0(%[dbg_addr]) \n" /* Exit debug mode, wait for store */ 554 " ld $0, 0(%[dbg_addr]) \n" 555 " cache 9, 0($0) \n" /* Invalidate dcache to discard debug data */ 556 " .set pop \n" 557 :[tag_val] "=r" (tag_val): [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr) : "memory"); 558 | 665 666 /* The following must be done in assembly as when in debug mode all data loads from 667 ** L2 return special debug data, not normal memory contents. Also, interrupts must be disabled, 668 ** since if an interrupt occurs while in debug mode the ISR will get debug data from all its memory 669 ** reads instead of the contents of memory */ 670 671 asm volatile ( 672 " .set push \n" 673 " .set mips64 \n" 674 " .set noreorder \n" 675 " sd %[dbg_val], 0(%[dbg_addr]) \n" /* Enter debug mode, wait for store */ 676 " ld $0, 0(%[dbg_addr]) \n" 677 " ld %[tag_val], 0(%[tag_addr]) \n" /* Read L2C tag data */ 678 " sd $0, 0(%[dbg_addr]) \n" /* Exit debug mode, wait for store */ 679 " ld $0, 0(%[dbg_addr]) \n" 680 " cache 9, 0($0) \n" /* Invalidate dcache to discard debug data */ 681 " .set pop \n" 682 :[tag_val] "=r" (tag_val): [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr) : "memory"); 683 |
559 cvmx_interrupt_restore(flags); | 684 cvmx_local_irq_restore(flags); |
560 561 return(tag_val); 562 563} 564 565 566cvmx_l2c_tag_t cvmx_l2c_get_tag(uint32_t association, uint32_t index) 567{ | 685 686 return(tag_val); 687 688} 689 690 691cvmx_l2c_tag_t cvmx_l2c_get_tag(uint32_t association, uint32_t index) 692{ |
568 __cvmx_l2c_tag_t tmp_tag; | |
569 cvmx_l2c_tag_t tag; 570 tag.u64 = 0; 571 572 if ((int)association >= cvmx_l2c_get_num_assoc()) 573 { | 693 cvmx_l2c_tag_t tag; 694 tag.u64 = 0; 695 696 if ((int)association >= cvmx_l2c_get_num_assoc()) 697 { |
574 cvmx_dprintf("ERROR: cvmx_get_l2c_tag association out of range\n"); | 698 cvmx_dprintf("ERROR: cvmx_l2c_get_tag association out of range\n"); |
575 return(tag); 576 } 577 if ((int)index >= cvmx_l2c_get_num_sets()) 578 { | 699 return(tag); 700 } 701 if ((int)index >= cvmx_l2c_get_num_sets()) 702 { |
579 cvmx_dprintf("ERROR: cvmx_get_l2c_tag index out of range (arg: %d, max: %d)\n", (int)index, cvmx_l2c_get_num_sets()); | 703 cvmx_dprintf("ERROR: cvmx_l2c_get_tag index out of range (arg: %d, max: %d)\n", (int)index, cvmx_l2c_get_num_sets()); |
580 return(tag); 581 } | 704 return(tag); 705 } |
582 /* __read_l2_tag is intended for internal use only */ 583 tmp_tag = __read_l2_tag(association, index); 584 585 /* Convert all tag structure types to generic version, as it can represent all models */ 586 if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) | 706 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) |
587 { | 707 { |
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; | 708 cvmx_l2c_tadx_tag_t l2c_tadx_tag; 709 uint64_t address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 710 (association << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) | 711 (index << CVMX_L2C_IDX_ADDR_SHIFT)); 712 /* Use L2 cache Index load tag cache instruction, as hardware loads 713 the virtual tag for the L2 cache block with the contents of 714 L2C_TAD0_TAG register. */ 715 CVMX_CACHE_LTGL2I(address, 0); 716 CVMX_SYNC; // make sure CVMX_L2C_TADX_TAG is updated 717 l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0)); 718 719 tag.s.V = l2c_tadx_tag.s.valid; 720 tag.s.D = l2c_tadx_tag.s.dirty; 721 tag.s.L = l2c_tadx_tag.s.lock; 722 tag.s.U = l2c_tadx_tag.s.use; 723 tag.s.addr = l2c_tadx_tag.s.tag; |
593 } | 724 } |
594 else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 595 { 596 tag.s.V = tmp_tag.cn38xx.V; 597 tag.s.D = tmp_tag.cn38xx.D; 598 tag.s.L = tmp_tag.cn38xx.L; 599 tag.s.U = tmp_tag.cn38xx.U; 600 tag.s.addr = tmp_tag.cn38xx.addr; 601 } 602 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 603 { 604 tag.s.V = tmp_tag.cn31xx.V; 605 tag.s.D = tmp_tag.cn31xx.D; 606 tag.s.L = tmp_tag.cn31xx.L; 607 tag.s.U = tmp_tag.cn31xx.U; 608 tag.s.addr = tmp_tag.cn31xx.addr; 609 } 610 else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 611 { 612 tag.s.V = tmp_tag.cn30xx.V; 613 tag.s.D = tmp_tag.cn30xx.D; 614 tag.s.L = tmp_tag.cn30xx.L; 615 tag.s.U = tmp_tag.cn30xx.U; 616 tag.s.addr = tmp_tag.cn30xx.addr; 617 } 618 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 619 { 620 tag.s.V = tmp_tag.cn50xx.V; 621 tag.s.D = tmp_tag.cn50xx.D; 622 tag.s.L = tmp_tag.cn50xx.L; 623 tag.s.U = tmp_tag.cn50xx.U; 624 tag.s.addr = tmp_tag.cn50xx.addr; 625 } | |
626 else 627 { | 725 else 726 { |
628 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__); | 727 __cvmx_l2c_tag_t tmp_tag; 728 /* __read_l2_tag is intended for internal use only */ 729 tmp_tag = __read_l2_tag(association, index); 730 731 /* Convert all tag structure types to generic version, as it can represent all models */ 732 if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) 733 { 734 tag.s.V = tmp_tag.cn58xx.V; 735 tag.s.D = tmp_tag.cn58xx.D; 736 tag.s.L = tmp_tag.cn58xx.L; 737 tag.s.U = tmp_tag.cn58xx.U; 738 tag.s.addr = tmp_tag.cn58xx.addr; 739 } 740 else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 741 { 742 tag.s.V = tmp_tag.cn38xx.V; 743 tag.s.D = tmp_tag.cn38xx.D; 744 tag.s.L = tmp_tag.cn38xx.L; 745 tag.s.U = tmp_tag.cn38xx.U; 746 tag.s.addr = tmp_tag.cn38xx.addr; 747 } 748 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 749 { 750 tag.s.V = tmp_tag.cn31xx.V; 751 tag.s.D = tmp_tag.cn31xx.D; 752 tag.s.L = tmp_tag.cn31xx.L; 753 tag.s.U = tmp_tag.cn31xx.U; 754 tag.s.addr = tmp_tag.cn31xx.addr; 755 } 756 else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 757 { 758 tag.s.V = tmp_tag.cn30xx.V; 759 tag.s.D = tmp_tag.cn30xx.D; 760 tag.s.L = tmp_tag.cn30xx.L; 761 tag.s.U = tmp_tag.cn30xx.U; 762 tag.s.addr = tmp_tag.cn30xx.addr; 763 } 764 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 765 { 766 tag.s.V = tmp_tag.cn50xx.V; 767 tag.s.D = tmp_tag.cn50xx.D; 768 tag.s.L = tmp_tag.cn50xx.L; 769 tag.s.U = tmp_tag.cn50xx.U; 770 tag.s.addr = tmp_tag.cn50xx.addr; 771 } 772 else 773 { 774 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__); 775 } |
629 } 630 631 return tag; 632} 633 634#endif 635 636uint32_t cvmx_l2c_address_to_index (uint64_t addr) 637{ 638 uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT; | 776 } 777 778 return tag; 779} 780 781#endif 782 783uint32_t cvmx_l2c_address_to_index (uint64_t addr) 784{ 785 uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT; |
639 cvmx_l2c_cfg_t l2c_cfg; 640 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); | 786 int indxalias = 0; |
641 | 787 |
642 if (l2c_cfg.s.idxalias) | 788 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) |
643 { | 789 { |
644 idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT); | 790 cvmx_l2c_ctl_t l2c_ctl; 791 l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL); 792 indxalias = !l2c_ctl.s.disidxalias; |
645 } | 793 } |
794 else 795 { 796 cvmx_l2c_cfg_t l2c_cfg; 797 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); 798 indxalias = l2c_cfg.s.idxalias; 799 } 800 801 if (indxalias) 802 { 803 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 804 { 805 uint32_t a_14_12 = (idx / (CVMX_L2C_MEMBANK_SELECT_SIZE/(1<<CVMX_L2C_IDX_ADDR_SHIFT))) & 0x7; 806 idx ^= idx / cvmx_l2c_get_num_sets(); 807 idx ^= a_14_12; 808 } 809 else 810 { 811 idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT); 812 } 813 } |
|
646 idx &= CVMX_L2C_IDX_MASK; 647 return(idx); 648} 649 650int cvmx_l2c_get_cache_size_bytes(void) 651{ 652 return (cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() * CVMX_CACHE_LINE_SIZE); 653} 654 655/** 656 * Return log base 2 of the number of sets in the L2 cache 657 * @return 658 */ 659int cvmx_l2c_get_set_bits(void) 660{ 661 int l2_set_bits; 662 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 663 OCTEON_IS_MODEL(OCTEON_CN58XX)) 664 l2_set_bits = 11; /* 2048 sets */ | 814 idx &= CVMX_L2C_IDX_MASK; 815 return(idx); 816} 817 818int cvmx_l2c_get_cache_size_bytes(void) 819{ 820 return (cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() * CVMX_CACHE_LINE_SIZE); 821} 822 823/** 824 * Return log base 2 of the number of sets in the L2 cache 825 * @return 826 */ 827int cvmx_l2c_get_set_bits(void) 828{ 829 int l2_set_bits; 830 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 831 OCTEON_IS_MODEL(OCTEON_CN58XX)) 832 l2_set_bits = 11; /* 2048 sets */ |
665 else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) | 833 else if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) |
666 l2_set_bits = 10; /* 1024 sets */ 667 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 668 l2_set_bits = 9; /* 512 sets */ 669 else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 670 l2_set_bits = 8; /* 256 sets */ 671 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 672 l2_set_bits = 7; /* 128 sets */ 673 else --- 16 unchanged lines hidden (view full) --- 690{ 691 int l2_assoc; 692 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 693 OCTEON_IS_MODEL(OCTEON_CN52XX) || 694 OCTEON_IS_MODEL(OCTEON_CN58XX) || 695 OCTEON_IS_MODEL(OCTEON_CN50XX) || 696 OCTEON_IS_MODEL(OCTEON_CN38XX)) 697 l2_assoc = 8; | 834 l2_set_bits = 10; /* 1024 sets */ 835 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) 836 l2_set_bits = 9; /* 512 sets */ 837 else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) 838 l2_set_bits = 8; /* 256 sets */ 839 else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) 840 l2_set_bits = 7; /* 128 sets */ 841 else --- 16 unchanged lines hidden (view full) --- 858{ 859 int l2_assoc; 860 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || 861 OCTEON_IS_MODEL(OCTEON_CN52XX) || 862 OCTEON_IS_MODEL(OCTEON_CN58XX) || 863 OCTEON_IS_MODEL(OCTEON_CN50XX) || 864 OCTEON_IS_MODEL(OCTEON_CN38XX)) 865 l2_assoc = 8; |
698 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || | 866 else if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 867 l2_assoc = 16; 868 else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || |
699 OCTEON_IS_MODEL(OCTEON_CN30XX)) 700 l2_assoc = 4; 701 else 702 { 703 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__); 704 l2_assoc = 8; 705 } 706 707 /* Check to see if part of the cache is disabled */ | 869 OCTEON_IS_MODEL(OCTEON_CN30XX)) 870 l2_assoc = 4; 871 else 872 { 873 cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__); 874 l2_assoc = 8; 875 } 876 877 /* Check to see if part of the cache is disabled */ |
708 if (cvmx_fuse_read(265)) 709 l2_assoc = l2_assoc >> 2; 710 else if (cvmx_fuse_read(264)) 711 l2_assoc = l2_assoc >> 1; | 878 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 879 { 880 cvmx_mio_fus_dat3_t mio_fus_dat3; |
712 | 881 |
882 mio_fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); 883 /* cvmx_mio_fus_dat3.s.l2c_crip fuses map as follows 884 <2> will be not used for 63xx 885 <1> disables 1/2 ways 886 <0> disables 1/4 ways 887 They are cumulative, so for 63xx: 888 <1> <0> 889 0 0 16-way 2MB cache 890 0 1 12-way 1.5MB cache 891 1 0 8-way 1MB cache 892 1 1 4-way 512KB cache */ 893 894 if (mio_fus_dat3.s.l2c_crip == 3) 895 l2_assoc = 4; 896 else if (mio_fus_dat3.s.l2c_crip == 2) 897 l2_assoc = 8; 898 else if (mio_fus_dat3.s.l2c_crip == 1) 899 l2_assoc = 12; 900 } 901 else 902 { 903 cvmx_l2d_fus3_t val; 904 val.u64 = cvmx_read_csr(CVMX_L2D_FUS3); 905 /* Using shifts here, as bit position names are different for 906 each model but they all mean the same. */ 907 if ((val.u64 >> 35) & 0x1) 908 l2_assoc = l2_assoc >> 2; 909 else if ((val.u64 >> 34) & 0x1) 910 l2_assoc = l2_assoc >> 1; 911 } 912 |
|
713 return(l2_assoc); 714} 715 716 717#ifndef CVMX_BUILD_FOR_LINUX_HOST 718/** 719 * Flush a line from the L2 cache 720 * This should only be called from one core at a time, as this routine 721 * sets the core to the 'debug' core in order to flush the line. 722 * 723 * @param assoc Association (or way) to flush 724 * @param index Index to flush 725 */ 726void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index) 727{ | 913 return(l2_assoc); 914} 915 916 917#ifndef CVMX_BUILD_FOR_LINUX_HOST 918/** 919 * Flush a line from the L2 cache 920 * This should only be called from one core at a time, as this routine 921 * sets the core to the 'debug' core in order to flush the line. 922 * 923 * @param assoc Association (or way) to flush 924 * @param index Index to flush 925 */ 926void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index) 927{ |
728 cvmx_l2c_dbg_t l2cdbg; | 928 /* Check the range of the index. */ 929 if (index > (uint32_t)cvmx_l2c_get_num_sets()) 930 { 931 cvmx_dprintf("ERROR: cvmx_l2c_flush_line index out of range.\n"); 932 return; 933 } |
729 | 934 |
730 l2cdbg.u64 = 0; 731 l2cdbg.s.ppnum = cvmx_get_core_num(); 732 l2cdbg.s.finv = 1; | 935 /* Check the range of association. */ 936 if (assoc > (uint32_t)cvmx_l2c_get_num_assoc()) 937 { 938 cvmx_dprintf("ERROR: cvmx_l2c_flush_line association out of range.\n"); 939 return; 940 } |
733 | 941 |
734 l2cdbg.s.set = assoc; 735 /* Enter debug mode, and make sure all other writes complete before we 736 ** enter debug mode */ 737 asm volatile ("sync \n"::: "memory"); 738 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 739 cvmx_read_csr(CVMX_L2C_DBG); | 942 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 943 { 944 uint64_t address; 945 /* Create the address based on index and association. 946 Bits<20:17> select the way of the cache block involved in 947 the operation 948 Bits<16:7> of the effect address select the index */ 949 address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 950 (assoc << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) | 951 (index << CVMX_L2C_IDX_ADDR_SHIFT)); 952 CVMX_CACHE_WBIL2I(address, 0); 953 } 954 else 955 { 956 cvmx_l2c_dbg_t l2cdbg; |
740 | 957 |
741 CVMX_PREPARE_FOR_STORE (((1ULL << 63) + (index)*128), 0); 742 /* Exit debug mode */ 743 asm volatile ("sync \n"::: "memory"); 744 cvmx_write_csr(CVMX_L2C_DBG, 0); 745 cvmx_read_csr(CVMX_L2C_DBG); | 958 l2cdbg.u64 = 0; 959 if (!OCTEON_IS_MODEL(OCTEON_CN30XX)) 960 l2cdbg.s.ppnum = cvmx_get_core_num(); 961 l2cdbg.s.finv = 1; 962 963 l2cdbg.s.set = assoc; 964 cvmx_spinlock_lock(&cvmx_l2c_spinlock); 965 /* Enter debug mode, and make sure all other writes complete before we 966 ** enter debug mode */ 967 CVMX_SYNC; 968 cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); 969 cvmx_read_csr(CVMX_L2C_DBG); 970 971 CVMX_PREPARE_FOR_STORE (CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, index*CVMX_CACHE_LINE_SIZE), 0); 972 /* Exit debug mode */ 973 CVMX_SYNC; 974 cvmx_write_csr(CVMX_L2C_DBG, 0); 975 cvmx_read_csr(CVMX_L2C_DBG); 976 cvmx_spinlock_unlock(&cvmx_l2c_spinlock); 977 } |
746} 747#endif | 978} 979#endif |
980 981#ifndef CVMX_BUILD_FOR_LINUX_HOST 982 983/* L2C Virtualization APIs. These APIs are based on Octeon II documentation. */ 984 985/** 986 * @INTERNAL 987 * Helper function to decode VALUE to number of allowed virtualization IDS. 988 * Returns L2C_VRT_CTL[NUMID]. 989 * 990 * @param nvid Number of virtual Ids. 991 * @return On success decode to NUMID, or to -1 on failure. 992 */ 993static inline int __cvmx_l2c_vrt_decode_numid(int nvid) 994{ 995 int bits = -1; 996 int zero_bits = -1; 997 998 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 999 { 1000 if (nvid < 1 || nvid > CVMX_L2C_VRT_MAX_VIRTID_ALLOWED) 1001 { 1002 cvmx_dprintf("WARNING: Invalid number of virtual ids(%d) requested, should be <= 64\n", nvid); 1003 return bits; 1004 } 1005 1006 while (nvid) 1007 { 1008 if ((nvid & 1) == 0) 1009 zero_bits++; 1010 1011 bits++; 1012 nvid >>= 1; 1013 } 1014 1015 if (bits == 1 || (zero_bits && ((bits - zero_bits) == 1))) 1016 return zero_bits; 1017 } 1018 return -1; 1019} 1020 1021/** 1022 * Set maxium number of Virtual IDs allowed in a machine. 1023 * 1024 * @param nvid Number of virtial ids allowed in a machine. 1025 * @return Return 0 on success or -1 on failure. 1026 */ 1027int cvmx_l2c_vrt_set_max_virtids(int nvid) 1028{ 1029 if (OCTEON_IS_MODEL(OCTEON_CN63XX)) 1030 { 1031 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1032 1033 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1034 1035 if (l2c_vrt_ctl.s.enable) 1036 { 1037 cvmx_dprintf("WARNING: Changing number of Virtual Machine IDs is not allowed after Virtualization is enabled\n"); 1038 return -1; 1039 } 1040 1041 if (nvid < 1 || nvid > CVMX_L2C_VRT_MAX_VIRTID_ALLOWED) 1042 { 1043 cvmx_dprintf("WARNING: cvmx_l2c_vrt_set_max_virtids: Invalid number of Virtual Machine IDs(%d) requested, max allowed %d\n", nvid, CVMX_L2C_VRT_MAX_VIRTID_ALLOWED); 1044 return -1; 1045 } 1046 1047 /* Calculate the numid based on nvid */ 1048 l2c_vrt_ctl.s.numid = __cvmx_l2c_vrt_decode_numid(nvid); 1049 cvmx_write_csr(CVMX_L2C_VRT_CTL, l2c_vrt_ctl.u64); 1050 } 1051 return 0; 1052} 1053 1054/** 1055 * Get maxium number of virtual IDs allowed in a machine. 1056 * 1057 * @return Return number of virtual machine IDs or -1 on failure. 1058 */ 1059int cvmx_l2c_vrt_get_max_virtids(void) 1060{ 1061 int virtids = -1; 1062 1063 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1064 { 1065 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1066 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1067 virtids = 1 << (l2c_vrt_ctl.s.numid + 1); 1068 if (virtids > CVMX_L2C_VRT_MAX_VIRTID_ALLOWED) 1069 { 1070 cvmx_dprintf("WARNING: cvmx_l2c_vrt_get_max_virtids: Invalid number of Virtual IDs initialized (%d)\n", virtids); 1071 return -1; 1072 } 1073 } 1074 return virtids; 1075} 1076 1077/** 1078 * @INTERNAL 1079 * Helper function to decode VALUE to memory space coverage of L2C_VRT_MEM. 1080 * Returns L2C_VRT_CTL[MEMSZ]. 1081 * 1082 * @param memsz Memory in GB. 1083 * @return On success, decode to MEMSZ, or on failure return -1. 1084 */ 1085static inline int __cvmx_l2c_vrt_decode_memsize(int memsz) 1086{ 1087 int bits = 0; 1088 int zero_bits = 0; 1089 1090 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1091 { 1092 if (memsz == 0 || memsz > CVMX_L2C_VRT_MAX_MEMSZ_ALLOWED) 1093 { 1094 cvmx_dprintf("WARNING: Invalid virtual memory size(%d) requested, should be <= %d\n", memsz, CVMX_L2C_VRT_MAX_MEMSZ_ALLOWED); 1095 return -1; 1096 } 1097 1098 while (memsz) 1099 { 1100 if ((memsz & 1) == 0) 1101 zero_bits++; 1102 1103 bits++; 1104 memsz >>= 1; 1105 } 1106 1107 if (bits == 1 || (bits - zero_bits) == 1) 1108 return zero_bits; 1109 } 1110 return -1; 1111} 1112 1113/** 1114 * Set the maxium size of memory space to be allocated for virtualization. 1115 * 1116 * @param memsz Size of the virtual memory in GB 1117 * @return Return 0 on success or -1 on failure. 1118 */ 1119int cvmx_l2c_vrt_set_max_memsz(int memsz) 1120{ 1121 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1122 { 1123 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1124 int decode = 0; 1125 1126 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1127 1128 if (l2c_vrt_ctl.s.enable) 1129 { 1130 cvmx_dprintf("WARNING: cvmx_l2c_vrt_set_memsz: Changing the size of the memory after Virtualization is enabled is not allowed.\n"); 1131 return -1; 1132 } 1133 1134 if (memsz >= (int)(cvmx_sysinfo_get()->system_dram_size / 1000000)) 1135 { 1136 cvmx_dprintf("WARNING: cvmx_l2c_vrt_set_memsz: Invalid memory size (%d GB), greater than available on the chip\n", memsz); 1137 return -1; 1138 } 1139 1140 decode = __cvmx_l2c_vrt_decode_memsize(memsz); 1141 if (decode == -1) 1142 { 1143 cvmx_dprintf("WARNING: cvmx_l2c_vrt_set_memsz: Invalid memory size (%d GB), refer to L2C_VRT_CTL[MEMSZ] for more information\n", memsz); 1144 return -1; 1145 } 1146 1147 l2c_vrt_ctl.s.memsz = decode; 1148 cvmx_write_csr(CVMX_L2C_VRT_CTL, l2c_vrt_ctl.u64); 1149 } 1150 return 0; 1151} 1152 1153/** 1154 * Set a Virtual ID to a set of cores. 1155 * 1156 * @param virtid Assign virtid to a set of cores. 1157 * @param coremask The group of cores to assign a unique virtual id. 1158 * @return Return 0 on success, otherwise -1. 1159 */ 1160int cvmx_l2c_vrt_assign_virtid(int virtid, uint32_t coremask) 1161{ 1162 uint32_t core = 0; 1163 1164 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1165 { 1166 int found = 0; 1167 int max_virtid = cvmx_l2c_vrt_get_max_virtids(); 1168 1169 if (virtid > max_virtid) 1170 { 1171 cvmx_dprintf("WARNING: cvmx_l2c_vrt_assign_virt_id: Max %d number of virtids are allowed, passed %d.\n", max_virtid, virtid); 1172 return -1; 1173 } 1174 1175 while (core < cvmx_octeon_num_cores()) 1176 { 1177 if ((coremask >> core) & 1) 1178 { 1179 cvmx_l2c_virtid_ppx_t l2c_virtid_ppx; 1180 cvmx_l2c_virtid_iobx_t l2c_virtid_iobx; 1181 l2c_virtid_ppx.u64 = cvmx_read_csr(CVMX_L2C_VIRTID_PPX(core)); 1182 1183 /* Check if the core already has a virtid assigned. */ 1184 if (l2c_virtid_ppx.s.id) 1185 { 1186 cvmx_dprintf("WARNING: cvmx_l2c_vrt_assign_virt_id: Changing virtid of core #%d to %d from %d.\n", 1187 (unsigned int)core, virtid, l2c_virtid_ppx.s.id); 1188 1189 /* Flush L2 cache to avoid write errors */ 1190 cvmx_l2c_flush(); 1191 } 1192 cvmx_write_csr(CVMX_L2C_VIRTID_PPX(core), virtid & 0x3f); 1193 1194 /* Set the IOB to normal mode. */ 1195 l2c_virtid_iobx.u64 = cvmx_read_csr(CVMX_L2C_VIRTID_IOBX(core)); 1196 l2c_virtid_iobx.s.id = 1; 1197 l2c_virtid_iobx.s.dwbid = 0; 1198 cvmx_write_csr(CVMX_L2C_VIRTID_IOBX(core), l2c_virtid_iobx.u64); 1199 found = 1; 1200 } 1201 core++; 1202 } 1203 1204 /* Invalid coremask passed. */ 1205 if (!found) 1206 { 1207 cvmx_dprintf("WARNING: cvmx_l2c_vrt_assign_virt_id: Invalid coremask(0x%x) passed\n", (unsigned int)coremask); 1208 return -1; 1209 } 1210 } 1211 return 0; 1212} 1213 1214/** 1215 * Remove a virt id assigned to a set of cores. Update the virtid mask and 1216 * virtid stored for each core. 1217 * 1218 * @param virtid Remove the specified Virtualization machine ID. 1219 */ 1220void cvmx_l2c_vrt_remove_virtid(int virtid) 1221{ 1222 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1223 { 1224 uint32_t core; 1225 cvmx_l2c_virtid_ppx_t l2c_virtid_ppx; 1226 1227 for (core = 0; core < cvmx_octeon_num_cores(); core++) 1228 { 1229 l2c_virtid_ppx.u64 = cvmx_read_csr(CVMX_L2C_VIRTID_PPX(core)); 1230 if (virtid == l2c_virtid_ppx.s.id) 1231 cvmx_write_csr(CVMX_L2C_VIRTID_PPX(core), 0); 1232 } 1233 } 1234} 1235 1236/** 1237 * Helper function to protect the memory region based on the granularity. 1238 */ 1239static uint64_t __cvmx_l2c_vrt_get_granularity(void) 1240{ 1241 uint64_t gran = 0; 1242 1243 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1244 { 1245 int nvid; 1246 uint64_t szd; 1247 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1248 1249 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1250 nvid = cvmx_l2c_vrt_get_max_virtids(); 1251 szd = (1ull << l2c_vrt_ctl.s.memsz) * 1024 * 1024 * 1024; 1252 gran = (unsigned long long)(szd * nvid)/(32ull * 1024); 1253 } 1254 return gran; 1255} 1256 1257/** 1258 * Block a memory region to be updated for a given virtual id. 1259 * 1260 * @param start_addr Starting address of memory region 1261 * @param size Size of the memory to protect 1262 * @param virtid Virtual ID to use 1263 * @param mode Allow/Disallow write access 1264 * = 0, Allow write access by virtid 1265 * = 1, Disallow write access by virtid 1266 */ 1267int cvmx_l2c_vrt_memprotect(uint64_t start_addr, int size, int virtid, int mode) 1268{ 1269 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1270 { 1271 /* Check the alignment of start address, should be aligned to the 1272 granularity. */ 1273 uint64_t gran = __cvmx_l2c_vrt_get_granularity(); 1274 uint64_t end_addr = start_addr + size; 1275 int byte_offset, virtid_offset; 1276 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1277 cvmx_l2c_vrt_memx_t l2c_vrt_mem; 1278 1279 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1280 1281 /* No need to protect if virtualization is not enabled */ 1282 if (!l2c_vrt_ctl.s.enable) 1283 { 1284 cvmx_dprintf("WARNING: cvmx_l2c_vrt_memprotect: Virtualization is not enabled.\n"); 1285 return -1; 1286 } 1287 1288 if (virtid > cvmx_l2c_vrt_get_max_virtids()) 1289 { 1290 cvmx_dprintf("WARNING: cvmx_l2c_vrt_memprotect: Virtualization id is greater than max allowed\n"); 1291 return -1; 1292 } 1293 1294 /* No need to protect if virtid is not assigned to a core */ 1295 { 1296 cvmx_l2c_virtid_ppx_t l2c_virtid_ppx; 1297 int found = 0; 1298 uint32_t core; 1299 1300 for (core = 0; core < cvmx_octeon_num_cores(); core++) 1301 { 1302 l2c_virtid_ppx.u64 = cvmx_read_csr(CVMX_L2C_VIRTID_PPX(core)); 1303 if (l2c_virtid_ppx.s.id == virtid) 1304 { 1305 found = 1; 1306 break; 1307 } 1308 } 1309 if (found == 0) 1310 { 1311 cvmx_dprintf("WARNING: cvmx_l2c_vrt_memprotect: Virtualization id (%d) is not assigned to any core.\n", virtid); 1312 return -1; 1313 } 1314 } 1315 1316 /* Make sure previous stores are through before protecting the memory. */ 1317 CVMX_SYNCW; 1318 1319 /* If the L2/DRAM physical address is >= 512 MB, subtract 256 MB 1320 to get the address to use. This is because L2C removes the 256MB 1321 "hole" between DR0 and DR1. */ 1322 if (start_addr >= (512 * 1024 * 1024)) 1323 start_addr -= 256 * 1024 * 1024; 1324 1325 if (start_addr != ((start_addr + (gran - 1)) & ~(gran - 1))) 1326 { 1327 cvmx_dprintf("WARNING: cvmx_l2c_vrt_memprotect: Start address is not aligned\n"); 1328 return -1; 1329 } 1330 1331 /* Check the size of the memory to protect, should be aligned to the 1332 granularity. */ 1333 if (end_addr != ((end_addr + (gran - 1)) & ~(gran - 1))) 1334 { 1335 end_addr = (start_addr + (gran - 1)) & ~(gran - 1); 1336 size = start_addr - end_addr; 1337 } 1338 1339 byte_offset = l2c_vrt_ctl.s.memsz + l2c_vrt_ctl.s.numid + 16; 1340 virtid_offset = 14 - l2c_vrt_ctl.s.numid; 1341 1342 cvmx_spinlock_lock(&cvmx_l2c_vrt_spinlock); 1343 1344 /* Enable memory protection for each virtid for the specified range. */ 1345 while (start_addr < end_addr) 1346 { 1347 /* When L2C virtualization is enabled and a bit is set in 1348 L2C_VRT_MEM(0..1023), then L2C prevents the selected virtual 1349 machine from storing to the selected L2C/DRAM region. */ 1350 int offset, position, i; 1351 int l2c_vrt_mem_bit_index = start_addr >> byte_offset; 1352 l2c_vrt_mem_bit_index |= (virtid << virtid_offset); 1353 1354 offset = l2c_vrt_mem_bit_index >> 5; 1355 position = l2c_vrt_mem_bit_index & 0x1f; 1356 1357 l2c_vrt_mem.u64 = cvmx_read_csr(CVMX_L2C_VRT_MEMX(offset)); 1358 /* Allow/Disallow write access to memory. */ 1359 if (mode == 0) 1360 l2c_vrt_mem.s.data &= ~(1 << position); 1361 else 1362 l2c_vrt_mem.s.data |= 1 << position; 1363 l2c_vrt_mem.s.parity = 0; 1364 /* PARITY<i> is the even parity of DATA<i*8+7:i*8>, which means 1365 that each bit<i> in PARITY[0..3], is the XOR of all the bits 1366 in the corresponding byte in DATA. */ 1367 for (i = 0; i <= 4; i++) 1368 { 1369 uint64_t mask = 0xffull << (i*8); 1370 if ((cvmx_pop(l2c_vrt_mem.s.data & mask) & 0x1)) 1371 l2c_vrt_mem.s.parity |= (1ull << i); 1372 } 1373 cvmx_write_csr(CVMX_L2C_VRT_MEMX(offset), l2c_vrt_mem.u64); 1374 start_addr += gran; 1375 } 1376 1377 cvmx_spinlock_unlock(&cvmx_l2c_vrt_spinlock); 1378 } 1379 return 0; 1380} 1381#endif 1382 1383/** 1384 * Enable virtualization. 1385 * 1386 * @param mode Whether out of bound writes are an error. 1387 */ 1388void cvmx_l2c_vrt_enable(int mode) 1389{ 1390 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1391 { 1392 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1393 1394 /* Enable global virtualization */ 1395 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1396 l2c_vrt_ctl.s.ooberr = mode; 1397 l2c_vrt_ctl.s.enable = 1; 1398 cvmx_write_csr(CVMX_L2C_VRT_CTL, l2c_vrt_ctl.u64); 1399 } 1400} 1401 1402/** 1403 * Disable virtualization. 1404 */ 1405void cvmx_l2c_vrt_disable(void) 1406{ 1407 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 1408 { 1409 cvmx_l2c_vrt_ctl_t l2c_vrt_ctl; 1410 1411 /* Disable global virtualization */ 1412 l2c_vrt_ctl.u64 = cvmx_read_csr(CVMX_L2C_VRT_CTL); 1413 l2c_vrt_ctl.s.enable = 0; 1414 cvmx_write_csr(CVMX_L2C_VRT_CTL, l2c_vrt_ctl.u64); 1415 } 1416} |
|