]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-l2c.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-l2c.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
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:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
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  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Implementation of the Level 2 Cache (L2C) control,
48  * measurement, and debugging facilities.
49  *
50  * <hr>$Revision: 41586 $<hr>
51  *
52  */
53 #include "cvmx-config.h"
54 #include "cvmx.h"
55 #include "cvmx-l2c.h"
56 #include "cvmx-spinlock.h"
57 #include "cvmx-interrupt.h"
58
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 */
67 CVMX_SHARED cvmx_spinlock_t cvmx_l2c_spinlock;
68 #endif
69
70 static inline int l2_size_half(void)
71 {
72     uint64_t val = cvmx_read_csr(CVMX_L2D_FUS3);
73     return !!(val & (1ull << 34));
74 }
75 int 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
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      */
91
92     switch (core & 0xC)
93     {
94         case 0x0:
95             return((cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> field);
96         case 0x4:
97             return((cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> field);
98         case 0x8:
99             return((cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> field);
100         case 0xC:
101             return((cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> field);
102     }
103     return(0);
104 }
105
106 int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask)
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
115     /* A UMSK setting which blocks all L2C Ways is an error. */
116     if (mask == valid_mask)
117         return -1;
118
119     /* Validate the core number */
120     if (core >= cvmx_octeon_num_cores())
121         return -1;
122
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;
126
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      *
136      */
137     switch (core & 0xC)
138     {
139         case 0x0:
140             cvmx_write_csr(CVMX_L2C_SPAR0,
141                            (cvmx_read_csr(CVMX_L2C_SPAR0) & ~(0xFF << field)) |
142                            mask << field);
143             break;
144         case 0x4:
145             cvmx_write_csr(CVMX_L2C_SPAR1,
146                            (cvmx_read_csr(CVMX_L2C_SPAR1) & ~(0xFF << field)) |
147                            mask << field);
148             break;
149         case 0x8:
150             cvmx_write_csr(CVMX_L2C_SPAR2,
151                            (cvmx_read_csr(CVMX_L2C_SPAR2) & ~(0xFF << field)) |
152                            mask << field);
153             break;
154         case 0xC:
155             cvmx_write_csr(CVMX_L2C_SPAR3,
156                            (cvmx_read_csr(CVMX_L2C_SPAR3) & ~(0xFF << field)) |
157                            mask << field);
158             break;
159     }
160     return 0;
161 }
162
163
164 int 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
171     /* A UMSK setting which blocks all L2C Ways is an error. */
172     if (mask == valid_mask)
173         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
178     cvmx_write_csr(CVMX_L2C_SPAR4, (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask);
179     return 0;
180 }
181
182 int cvmx_l2c_get_hw_way_partition(void)
183 {
184     return(cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF));
185 }
186
187
188 void cvmx_l2c_config_perf(uint32_t counter, cvmx_l2c_event_t event,
189                           uint32_t clear_on_read)
190 {   cvmx_l2c_pfctl_t pfctl;
191
192     pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL);
193
194     switch (counter)
195     {
196         case 0:
197             pfctl.s.cnt0sel = event;
198             pfctl.s.cnt0ena = 1;
199             if (!cvmx_octeon_is_pass1())
200                 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())
206                 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())
212                 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())
219                 pfctl.s.cnt3rdclr = clear_on_read;
220             break;
221     }
222
223     cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64);
224 }
225
226 uint64_t cvmx_l2c_read_perf(uint32_t counter)
227 {
228     switch (counter)
229     {
230         case 0:
231             return(cvmx_read_csr(CVMX_L2C_PFC0));
232         case 1:
233             return(cvmx_read_csr(CVMX_L2C_PFC1));
234         case 2:
235             return(cvmx_read_csr(CVMX_L2C_PFC2));
236         case 3:
237         default:
238             return(cvmx_read_csr(CVMX_L2C_PFC3));
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  *
247  * @param addr   Address of base of memory region to read into L2 cache
248  * @param len    Length (in bytes) of region to fault in
249  */
250 static void fault_in(uint64_t addr, int len)
251 {
252     volatile char *ptr;
253     volatile char dummy;
254     /* Adjust addr and length so we get all cache lines even for
255     ** small ranges spanning two cache lines */
256     len += addr & CVMX_CACHE_LINE_MASK;
257     addr &= ~CVMX_CACHE_LINE_MASK;
258     ptr = (volatile char *)cvmx_phys_to_ptr(addr);
259     CVMX_DCACHE_INVALIDATE;  /* Invalidate L1 cache to make sure all loads result in data being in L2 */
260     while (len > 0)
261     {
262         dummy += *ptr;
263         len -= CVMX_CACHE_LINE_SIZE;
264         ptr += CVMX_CACHE_LINE_SIZE;
265     }
266 }
267
268 int cvmx_l2c_lock_line(uint64_t addr)
269 {
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;
278
279     cvmx_spinlock_lock(&cvmx_l2c_spinlock);
280
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);
286
287     addr &= ~CVMX_CACHE_LINE_MASK;
288
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);
294
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;
304     }
305     else
306     {
307         lckbase.s.lck_base = addr >> 7;
308     }
309
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
313
314     fault_in(addr, CVMX_CACHE_LINE_SIZE);
315
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
319
320     /* Stop being debug core */
321     cvmx_write_csr(CVMX_L2C_DBG, 0);
322     cvmx_read_csr(CVMX_L2C_DBG);
323
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 */
327
328     cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
329
330     return(retval);
331 }
332
333
334 int 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 */
339     len += start & CVMX_CACHE_LINE_MASK;
340     start &= ~CVMX_CACHE_LINE_MASK;
341     len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
342
343     while (len)
344     {
345         retval += cvmx_l2c_lock_line(start);
346         start += CVMX_CACHE_LINE_SIZE;
347         len -= CVMX_CACHE_LINE_SIZE;
348     }
349
350     return(retval);
351 }
352
353
354 void cvmx_l2c_flush(void)
355 {
356     uint64_t assoc, set;
357     uint64_t n_assoc, n_set;
358     cvmx_l2c_dbg_t l2cdbg;
359
360     cvmx_spinlock_lock(&cvmx_l2c_spinlock);
361
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++)
369     {
370         for(assoc = 0; assoc < n_assoc; assoc++)
371         {
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);
385         }
386     }
387
388     cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
389 }
390
391
392 int cvmx_l2c_unlock_line(uint64_t address)
393 {
394     int assoc;
395     cvmx_l2c_tag_t tag;
396     cvmx_l2c_dbg_t l2cdbg;
397     uint32_t tag_addr;
398
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++)
405     {
406         tag = cvmx_get_l2c_tag(assoc, index);
407
408         if (tag.s.V && (tag.s.addr == tag_addr))
409         {
410             l2cdbg.u64 = 0;
411             l2cdbg.s.ppnum = cvmx_get_core_num();
412             l2cdbg.s.set = assoc;
413             l2cdbg.s.finv = 1;
414
415             CVMX_SYNC;
416             cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); /* Enter debug mode */
417             cvmx_read_csr(CVMX_L2C_DBG);
418
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;
426         }
427     }
428     cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
429     return 0;
430 }
431
432 int 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;
437     start &= ~CVMX_CACHE_LINE_MASK;
438     len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
439     while (len > 0)
440     {
441         num_unlocked += cvmx_l2c_unlock_line(start);
442         start += CVMX_CACHE_LINE_SIZE;
443         len -= CVMX_CACHE_LINE_SIZE;
444     }
445
446     return num_unlocked;
447 }
448
449
450 /* Internal l2c tag types.  These are converted to a generic structure
451 ** that can be used on all chips */
452 typedef union
453 {
454     uint64_t u64;
455 #if __BYTE_ORDER == __BIG_ENDIAN
456     struct cvmx_l2c_tag_cn50xx
457     {
458         uint64_t reserved               : 40;
459         uint64_t V                      : 1;    // Line valid
460         uint64_t D                      : 1;    // Line dirty
461         uint64_t L                      : 1;    // Line locked
462         uint64_t U                      : 1;    // Use, LRU eviction
463         uint64_t addr                   : 20;   // Phys mem addr (33..14)
464     } cn50xx;
465     struct cvmx_l2c_tag_cn30xx
466     {
467         uint64_t reserved               : 41;
468         uint64_t V                      : 1;    // Line valid
469         uint64_t D                      : 1;    // Line dirty
470         uint64_t L                      : 1;    // Line locked
471         uint64_t U                      : 1;    // Use, LRU eviction
472         uint64_t addr                   : 19;   // Phys mem addr (33..15)
473     } cn30xx;
474     struct cvmx_l2c_tag_cn31xx
475     {
476         uint64_t reserved               : 42;
477         uint64_t V                      : 1;    // Line valid
478         uint64_t D                      : 1;    // Line dirty
479         uint64_t L                      : 1;    // Line locked
480         uint64_t U                      : 1;    // Use, LRU eviction
481         uint64_t addr                   : 18;   // Phys mem addr (33..16)
482     } cn31xx;
483     struct cvmx_l2c_tag_cn38xx
484     {
485         uint64_t reserved               : 43;
486         uint64_t V                      : 1;    // Line valid
487         uint64_t D                      : 1;    // Line dirty
488         uint64_t L                      : 1;    // Line locked
489         uint64_t U                      : 1;    // Use, LRU eviction
490         uint64_t addr                   : 17;   // Phys mem addr (33..17)
491     } cn38xx;
492     struct cvmx_l2c_tag_cn58xx
493     {
494         uint64_t reserved               : 44;
495         uint64_t V                      : 1;    // Line valid
496         uint64_t D                      : 1;    // Line dirty
497         uint64_t L                      : 1;    // Line locked
498         uint64_t U                      : 1;    // Use, LRU eviction
499         uint64_t addr                   : 16;   // Phys mem addr (33..18)
500     } cn58xx;
501     struct cvmx_l2c_tag_cn58xx   cn56xx; /* 2048 sets */
502     struct cvmx_l2c_tag_cn31xx   cn52xx; /* 512 sets */
503 #endif
504 } __cvmx_l2c_tag_t;
505
506
507 /**
508  * @INTERNAL
509  * Function to read a L2C tag.  This code make the current core
510  * the 'debug core' for the L2.  This code must only be executed by
511  * 1 core at a time.
512  *
513  * @param assoc  Association (way) of the tag to dump
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  */
519 static __cvmx_l2c_tag_t __read_l2_tag(uint64_t assoc, uint64_t index)
520 {
521
522     uint64_t debug_tag_addr = (((1ULL << 63) | (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;
526     uint32_t 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
539     flags = cvmx_interrupt_disable_save();
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
559     cvmx_interrupt_restore(flags);
560
561     return(tag_val);
562
563 }
564
565
566 cvmx_l2c_tag_t cvmx_l2c_get_tag(uint32_t association, uint32_t index)
567 {
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     {
574         cvmx_dprintf("ERROR: cvmx_get_l2c_tag association out of range\n");
575         return(tag);
576     }
577     if ((int)index >= cvmx_l2c_get_num_sets())
578     {
579         cvmx_dprintf("ERROR: cvmx_get_l2c_tag index out of range (arg: %d, max: %d)\n", (int)index, cvmx_l2c_get_num_sets());
580         return(tag);
581     }
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))
587     {
588         tag.s.V    = tmp_tag.cn58xx.V;
589         tag.s.D    = tmp_tag.cn58xx.D;
590         tag.s.L    = tmp_tag.cn58xx.L;
591         tag.s.U    = tmp_tag.cn58xx.U;
592         tag.s.addr = tmp_tag.cn58xx.addr;
593     }
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     {
628         cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__);
629     }
630
631     return tag;
632 }
633
634 #endif
635
636 uint32_t cvmx_l2c_address_to_index (uint64_t addr)
637 {
638     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);
641
642     if (l2c_cfg.s.idxalias)
643     {
644         idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT);
645     }
646     idx &= CVMX_L2C_IDX_MASK;
647     return(idx);
648 }
649
650 int 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  */
659 int 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 */
665     else if (OCTEON_IS_MODEL(OCTEON_CN38XX))
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
674     {
675         cvmx_dprintf("Unsupported OCTEON Model in %s\n", __FUNCTION__);
676         l2_set_bits =  11; /* 2048 sets */
677     }
678     return(l2_set_bits);
679
680 }
681
682 /* Return the number of sets in the L2 Cache */
683 int cvmx_l2c_get_num_sets(void)
684 {
685     return (1 << cvmx_l2c_get_set_bits());
686 }
687
688 /* Return the number of associations in the L2 Cache */
689 int cvmx_l2c_get_num_assoc(void)
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;
698     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 */
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;
712
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  */
726 void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index)
727 {
728     cvmx_l2c_dbg_t l2cdbg;
729
730     l2cdbg.u64 = 0;
731     l2cdbg.s.ppnum = cvmx_get_core_num();
732     l2cdbg.s.finv = 1;
733
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);
740
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);
746 }
747 #endif