Deleted Added
full compact
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}