158f07778SDavid Daney /***********************license start***************
258f07778SDavid Daney * Author: Cavium Networks
358f07778SDavid Daney *
458f07778SDavid Daney * Contact: support@caviumnetworks.com
558f07778SDavid Daney * This file is part of the OCTEON SDK
658f07778SDavid Daney *
715f68479SSteven J. Hill * Copyright (c) 2003-2017 Cavium, Inc.
858f07778SDavid Daney *
958f07778SDavid Daney * This file is free software; you can redistribute it and/or modify
1058f07778SDavid Daney * it under the terms of the GNU General Public License, Version 2, as
1158f07778SDavid Daney * published by the Free Software Foundation.
1258f07778SDavid Daney *
1358f07778SDavid Daney * This file is distributed in the hope that it will be useful, but
1458f07778SDavid Daney * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
1558f07778SDavid Daney * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
1658f07778SDavid Daney * NONINFRINGEMENT. See the GNU General Public License for more
1758f07778SDavid Daney * details.
1858f07778SDavid Daney *
1958f07778SDavid Daney * You should have received a copy of the GNU General Public License
2058f07778SDavid Daney * along with this file; if not, write to the Free Software
2158f07778SDavid Daney * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2258f07778SDavid Daney * or visit http://www.gnu.org/licenses/.
2358f07778SDavid Daney *
2458f07778SDavid Daney * This file may also be available under a different license from Cavium.
2558f07778SDavid Daney * Contact Cavium Networks for more information
2658f07778SDavid Daney ***********************license end**************************************/
2758f07778SDavid Daney
2858f07778SDavid Daney /*
29b8db85b5SDavid Daney * Implementation of the Level 2 Cache (L2C) control,
30b8db85b5SDavid Daney * measurement, and debugging facilities.
3158f07778SDavid Daney */
3258f07778SDavid Daney
33757be67fSRalf Baechle #include <linux/compiler.h>
3492d11594SJim Quinlan #include <linux/irqflags.h>
3558f07778SDavid Daney #include <asm/octeon/cvmx.h>
3658f07778SDavid Daney #include <asm/octeon/cvmx-l2c.h>
3758f07778SDavid Daney #include <asm/octeon/cvmx-spinlock.h>
3858f07778SDavid Daney
3958f07778SDavid Daney /*
4058f07778SDavid Daney * This spinlock is used internally to ensure that only one core is
4158f07778SDavid Daney * performing certain L2 operations at a time.
4258f07778SDavid Daney *
4358f07778SDavid Daney * NOTE: This only protects calls from within a single application -
4458f07778SDavid Daney * if multiple applications or operating systems are running, then it
4558f07778SDavid Daney * is up to the user program to coordinate between them.
4658f07778SDavid Daney */
476430ba58SAaro Koskinen static cvmx_spinlock_t cvmx_l2c_spinlock;
4858f07778SDavid Daney
cvmx_l2c_get_core_way_partition(uint32_t core)4958f07778SDavid Daney int cvmx_l2c_get_core_way_partition(uint32_t core)
5058f07778SDavid Daney {
5158f07778SDavid Daney uint32_t field;
5258f07778SDavid Daney
5358f07778SDavid Daney /* Validate the core number */
5458f07778SDavid Daney if (core >= cvmx_octeon_num_cores())
5558f07778SDavid Daney return -1;
5658f07778SDavid Daney
57b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX))
58b8db85b5SDavid Daney return cvmx_read_csr(CVMX_L2C_WPAR_PPX(core)) & 0xffff;
59b8db85b5SDavid Daney
6058f07778SDavid Daney /*
6158f07778SDavid Daney * Use the lower two bits of the coreNumber to determine the
6258f07778SDavid Daney * bit offset of the UMSK[] field in the L2C_SPAR register.
6358f07778SDavid Daney */
6458f07778SDavid Daney field = (core & 0x3) * 8;
6558f07778SDavid Daney
6658f07778SDavid Daney /*
6758f07778SDavid Daney * Return the UMSK[] field from the appropriate L2C_SPAR
6858f07778SDavid Daney * register based on the coreNumber.
6958f07778SDavid Daney */
7058f07778SDavid Daney
7158f07778SDavid Daney switch (core & 0xC) {
7258f07778SDavid Daney case 0x0:
73b8db85b5SDavid Daney return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> field;
7458f07778SDavid Daney case 0x4:
75b8db85b5SDavid Daney return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> field;
7658f07778SDavid Daney case 0x8:
77b8db85b5SDavid Daney return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> field;
7858f07778SDavid Daney case 0xC:
79b8db85b5SDavid Daney return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> field;
8058f07778SDavid Daney }
8158f07778SDavid Daney return 0;
8258f07778SDavid Daney }
8358f07778SDavid Daney
cvmx_l2c_set_core_way_partition(uint32_t core,uint32_t mask)8458f07778SDavid Daney int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask)
8558f07778SDavid Daney {
8658f07778SDavid Daney uint32_t field;
8758f07778SDavid Daney uint32_t valid_mask;
8858f07778SDavid Daney
8958f07778SDavid Daney valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1;
9058f07778SDavid Daney
9158f07778SDavid Daney mask &= valid_mask;
9258f07778SDavid Daney
93b8db85b5SDavid Daney /* A UMSK setting which blocks all L2C Ways is an error on some chips */
94b8db85b5SDavid Daney if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX))
9558f07778SDavid Daney return -1;
9658f07778SDavid Daney
9758f07778SDavid Daney /* Validate the core number */
9858f07778SDavid Daney if (core >= cvmx_octeon_num_cores())
9958f07778SDavid Daney return -1;
10058f07778SDavid Daney
101b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
102b8db85b5SDavid Daney cvmx_write_csr(CVMX_L2C_WPAR_PPX(core), mask);
103b8db85b5SDavid Daney return 0;
104b8db85b5SDavid Daney }
10558f07778SDavid Daney
106b8db85b5SDavid Daney /*
107b8db85b5SDavid Daney * Use the lower two bits of core to determine the bit offset of the
10858f07778SDavid Daney * UMSK[] field in the L2C_SPAR register.
10958f07778SDavid Daney */
11058f07778SDavid Daney field = (core & 0x3) * 8;
11158f07778SDavid Daney
112b8db85b5SDavid Daney /*
113b8db85b5SDavid Daney * Assign the new mask setting to the UMSK[] field in the appropriate
11458f07778SDavid Daney * L2C_SPAR register based on the core_num.
11558f07778SDavid Daney *
11658f07778SDavid Daney */
11758f07778SDavid Daney switch (core & 0xC) {
11858f07778SDavid Daney case 0x0:
11958f07778SDavid Daney cvmx_write_csr(CVMX_L2C_SPAR0,
120b8db85b5SDavid Daney (cvmx_read_csr(CVMX_L2C_SPAR0) & ~(0xFF << field)) |
121b8db85b5SDavid Daney mask << field);
12258f07778SDavid Daney break;
12358f07778SDavid Daney case 0x4:
12458f07778SDavid Daney cvmx_write_csr(CVMX_L2C_SPAR1,
125b8db85b5SDavid Daney (cvmx_read_csr(CVMX_L2C_SPAR1) & ~(0xFF << field)) |
126b8db85b5SDavid Daney mask << field);
12758f07778SDavid Daney break;
12858f07778SDavid Daney case 0x8:
12958f07778SDavid Daney cvmx_write_csr(CVMX_L2C_SPAR2,
130b8db85b5SDavid Daney (cvmx_read_csr(CVMX_L2C_SPAR2) & ~(0xFF << field)) |
131b8db85b5SDavid Daney mask << field);
13258f07778SDavid Daney break;
13358f07778SDavid Daney case 0xC:
13458f07778SDavid Daney cvmx_write_csr(CVMX_L2C_SPAR3,
135b8db85b5SDavid Daney (cvmx_read_csr(CVMX_L2C_SPAR3) & ~(0xFF << field)) |
136b8db85b5SDavid Daney mask << field);
13758f07778SDavid Daney break;
13858f07778SDavid Daney }
13958f07778SDavid Daney return 0;
14058f07778SDavid Daney }
14158f07778SDavid Daney
cvmx_l2c_set_hw_way_partition(uint32_t mask)14258f07778SDavid Daney int cvmx_l2c_set_hw_way_partition(uint32_t mask)
14358f07778SDavid Daney {
14458f07778SDavid Daney uint32_t valid_mask;
14558f07778SDavid Daney
146b8db85b5SDavid Daney valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1;
14758f07778SDavid Daney mask &= valid_mask;
14858f07778SDavid Daney
149b8db85b5SDavid Daney /* A UMSK setting which blocks all L2C Ways is an error on some chips */
150b8db85b5SDavid Daney if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX))
15158f07778SDavid Daney return -1;
15258f07778SDavid Daney
153b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX))
154b8db85b5SDavid Daney cvmx_write_csr(CVMX_L2C_WPAR_IOBX(0), mask);
155b8db85b5SDavid Daney else
15658f07778SDavid Daney cvmx_write_csr(CVMX_L2C_SPAR4,
15758f07778SDavid Daney (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask);
15858f07778SDavid Daney return 0;
15958f07778SDavid Daney }
16058f07778SDavid Daney
cvmx_l2c_get_hw_way_partition(void)16158f07778SDavid Daney int cvmx_l2c_get_hw_way_partition(void)
16258f07778SDavid Daney {
163b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX))
164b8db85b5SDavid Daney return cvmx_read_csr(CVMX_L2C_WPAR_IOBX(0)) & 0xffff;
165b8db85b5SDavid Daney else
16658f07778SDavid Daney return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF);
16758f07778SDavid Daney }
16858f07778SDavid Daney
cvmx_l2c_config_perf(uint32_t counter,enum cvmx_l2c_event event,uint32_t clear_on_read)16958f07778SDavid Daney void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event,
17058f07778SDavid Daney uint32_t clear_on_read)
17158f07778SDavid Daney {
172b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
17358f07778SDavid Daney union cvmx_l2c_pfctl pfctl;
17458f07778SDavid Daney
17558f07778SDavid Daney pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL);
17658f07778SDavid Daney
17758f07778SDavid Daney switch (counter) {
17858f07778SDavid Daney case 0:
17958f07778SDavid Daney pfctl.s.cnt0sel = event;
18058f07778SDavid Daney pfctl.s.cnt0ena = 1;
18158f07778SDavid Daney pfctl.s.cnt0rdclr = clear_on_read;
18258f07778SDavid Daney break;
18358f07778SDavid Daney case 1:
18458f07778SDavid Daney pfctl.s.cnt1sel = event;
18558f07778SDavid Daney pfctl.s.cnt1ena = 1;
18658f07778SDavid Daney pfctl.s.cnt1rdclr = clear_on_read;
18758f07778SDavid Daney break;
18858f07778SDavid Daney case 2:
18958f07778SDavid Daney pfctl.s.cnt2sel = event;
19058f07778SDavid Daney pfctl.s.cnt2ena = 1;
19158f07778SDavid Daney pfctl.s.cnt2rdclr = clear_on_read;
19258f07778SDavid Daney break;
19358f07778SDavid Daney case 3:
19458f07778SDavid Daney default:
19558f07778SDavid Daney pfctl.s.cnt3sel = event;
19658f07778SDavid Daney pfctl.s.cnt3ena = 1;
19758f07778SDavid Daney pfctl.s.cnt3rdclr = clear_on_read;
19858f07778SDavid Daney break;
19958f07778SDavid Daney }
20058f07778SDavid Daney
20158f07778SDavid Daney cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64);
202b8db85b5SDavid Daney } else {
203b8db85b5SDavid Daney union cvmx_l2c_tadx_prf l2c_tadx_prf;
204b8db85b5SDavid Daney int tad;
205b8db85b5SDavid Daney
206b8db85b5SDavid Daney cvmx_dprintf("L2C performance counter events are different for this chip, mapping 'event' to cvmx_l2c_tad_event_t\n");
207b8db85b5SDavid Daney if (clear_on_read)
208b8db85b5SDavid Daney cvmx_dprintf("L2C counters don't support clear on read for this chip\n");
209b8db85b5SDavid Daney
210b8db85b5SDavid Daney l2c_tadx_prf.u64 = cvmx_read_csr(CVMX_L2C_TADX_PRF(0));
211b8db85b5SDavid Daney
212b8db85b5SDavid Daney switch (counter) {
213b8db85b5SDavid Daney case 0:
214b8db85b5SDavid Daney l2c_tadx_prf.s.cnt0sel = event;
215b8db85b5SDavid Daney break;
216b8db85b5SDavid Daney case 1:
217b8db85b5SDavid Daney l2c_tadx_prf.s.cnt1sel = event;
218b8db85b5SDavid Daney break;
219b8db85b5SDavid Daney case 2:
220b8db85b5SDavid Daney l2c_tadx_prf.s.cnt2sel = event;
221b8db85b5SDavid Daney break;
222b8db85b5SDavid Daney default:
223b8db85b5SDavid Daney case 3:
224b8db85b5SDavid Daney l2c_tadx_prf.s.cnt3sel = event;
225b8db85b5SDavid Daney break;
226b8db85b5SDavid Daney }
227b8db85b5SDavid Daney for (tad = 0; tad < CVMX_L2C_TADS; tad++)
228b8db85b5SDavid Daney cvmx_write_csr(CVMX_L2C_TADX_PRF(tad),
229b8db85b5SDavid Daney l2c_tadx_prf.u64);
230b8db85b5SDavid Daney }
23158f07778SDavid Daney }
23258f07778SDavid Daney
cvmx_l2c_read_perf(uint32_t counter)23358f07778SDavid Daney uint64_t cvmx_l2c_read_perf(uint32_t counter)
23458f07778SDavid Daney {
23558f07778SDavid Daney switch (counter) {
23658f07778SDavid Daney case 0:
237b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
23858f07778SDavid Daney return cvmx_read_csr(CVMX_L2C_PFC0);
239b8db85b5SDavid Daney else {
240b8db85b5SDavid Daney uint64_t counter = 0;
241b8db85b5SDavid Daney int tad;
24215f68479SSteven J. Hill
243b8db85b5SDavid Daney for (tad = 0; tad < CVMX_L2C_TADS; tad++)
244b8db85b5SDavid Daney counter += cvmx_read_csr(CVMX_L2C_TADX_PFC0(tad));
245b8db85b5SDavid Daney return counter;
246b8db85b5SDavid Daney }
24758f07778SDavid Daney case 1:
248b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
24958f07778SDavid Daney return cvmx_read_csr(CVMX_L2C_PFC1);
250b8db85b5SDavid Daney else {
251b8db85b5SDavid Daney uint64_t counter = 0;
252b8db85b5SDavid Daney int tad;
25315f68479SSteven J. Hill
254b8db85b5SDavid Daney for (tad = 0; tad < CVMX_L2C_TADS; tad++)
255b8db85b5SDavid Daney counter += cvmx_read_csr(CVMX_L2C_TADX_PFC1(tad));
256b8db85b5SDavid Daney return counter;
257b8db85b5SDavid Daney }
25858f07778SDavid Daney case 2:
259b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
26058f07778SDavid Daney return cvmx_read_csr(CVMX_L2C_PFC2);
261b8db85b5SDavid Daney else {
262b8db85b5SDavid Daney uint64_t counter = 0;
263b8db85b5SDavid Daney int tad;
26415f68479SSteven J. Hill
265b8db85b5SDavid Daney for (tad = 0; tad < CVMX_L2C_TADS; tad++)
266b8db85b5SDavid Daney counter += cvmx_read_csr(CVMX_L2C_TADX_PFC2(tad));
267b8db85b5SDavid Daney return counter;
268b8db85b5SDavid Daney }
26958f07778SDavid Daney case 3:
27058f07778SDavid Daney default:
271b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
27258f07778SDavid Daney return cvmx_read_csr(CVMX_L2C_PFC3);
273b8db85b5SDavid Daney else {
274b8db85b5SDavid Daney uint64_t counter = 0;
275b8db85b5SDavid Daney int tad;
27615f68479SSteven J. Hill
277b8db85b5SDavid Daney for (tad = 0; tad < CVMX_L2C_TADS; tad++)
278b8db85b5SDavid Daney counter += cvmx_read_csr(CVMX_L2C_TADX_PFC3(tad));
279b8db85b5SDavid Daney return counter;
280b8db85b5SDavid Daney }
28158f07778SDavid Daney }
28258f07778SDavid Daney }
28358f07778SDavid Daney
284*16df55ceSRandy Dunlap /*
28558f07778SDavid Daney * @INTERNAL
28658f07778SDavid Daney * Helper function use to fault in cache lines for L2 cache locking
28758f07778SDavid Daney *
28858f07778SDavid Daney * @addr: Address of base of memory region to read into L2 cache
28958f07778SDavid Daney * @len: Length (in bytes) of region to fault in
29058f07778SDavid Daney */
fault_in(uint64_t addr,int len)29158f07778SDavid Daney static void fault_in(uint64_t addr, int len)
29258f07778SDavid Daney {
293757be67fSRalf Baechle char *ptr;
294757be67fSRalf Baechle
29558f07778SDavid Daney /*
29658f07778SDavid Daney * Adjust addr and length so we get all cache lines even for
297b8db85b5SDavid Daney * small ranges spanning two cache lines.
29858f07778SDavid Daney */
29958f07778SDavid Daney len += addr & CVMX_CACHE_LINE_MASK;
30058f07778SDavid Daney addr &= ~CVMX_CACHE_LINE_MASK;
301757be67fSRalf Baechle ptr = cvmx_phys_to_ptr(addr);
30258f07778SDavid Daney /*
30358f07778SDavid Daney * Invalidate L1 cache to make sure all loads result in data
30458f07778SDavid Daney * being in L2.
30558f07778SDavid Daney */
30658f07778SDavid Daney CVMX_DCACHE_INVALIDATE;
30758f07778SDavid Daney while (len > 0) {
30815f68479SSteven J. Hill READ_ONCE(*ptr);
30958f07778SDavid Daney len -= CVMX_CACHE_LINE_SIZE;
31058f07778SDavid Daney ptr += CVMX_CACHE_LINE_SIZE;
31158f07778SDavid Daney }
31258f07778SDavid Daney }
31358f07778SDavid Daney
cvmx_l2c_lock_line(uint64_t addr)31458f07778SDavid Daney int cvmx_l2c_lock_line(uint64_t addr)
31558f07778SDavid Daney {
316b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
317b8db85b5SDavid Daney int shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
318b8db85b5SDavid Daney uint64_t assoc = cvmx_l2c_get_num_assoc();
319b8db85b5SDavid Daney uint64_t tag = addr >> shift;
320b8db85b5SDavid Daney uint64_t index = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, cvmx_l2c_address_to_index(addr) << CVMX_L2C_IDX_ADDR_SHIFT);
321b8db85b5SDavid Daney uint64_t way;
322b8db85b5SDavid Daney union cvmx_l2c_tadx_tag l2c_tadx_tag;
323b8db85b5SDavid Daney
324b8db85b5SDavid Daney CVMX_CACHE_LCKL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, addr), 0);
325b8db85b5SDavid Daney
326b8db85b5SDavid Daney /* Make sure we were able to lock the line */
327b8db85b5SDavid Daney for (way = 0; way < assoc; way++) {
328b8db85b5SDavid Daney CVMX_CACHE_LTGL2I(index | (way << shift), 0);
329b8db85b5SDavid Daney /* make sure CVMX_L2C_TADX_TAG is updated */
330b8db85b5SDavid Daney CVMX_SYNC;
331b8db85b5SDavid Daney l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
332b8db85b5SDavid Daney if (l2c_tadx_tag.s.valid && l2c_tadx_tag.s.tag == tag)
333b8db85b5SDavid Daney break;
334b8db85b5SDavid Daney }
335b8db85b5SDavid Daney
336b8db85b5SDavid Daney /* Check if a valid line is found */
337b8db85b5SDavid Daney if (way >= assoc) {
338b8db85b5SDavid Daney /* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: line not found for locking at 0x%llx address\n", (unsigned long long)addr); */
339b8db85b5SDavid Daney return -1;
340b8db85b5SDavid Daney }
341b8db85b5SDavid Daney
342b8db85b5SDavid Daney /* Check if lock bit is not set */
343b8db85b5SDavid Daney if (!l2c_tadx_tag.s.lock) {
344b8db85b5SDavid Daney /* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: Not able to lock at 0x%llx address\n", (unsigned long long)addr); */
345b8db85b5SDavid Daney return -1;
346b8db85b5SDavid Daney }
347b8db85b5SDavid Daney return way;
348b8db85b5SDavid Daney } else {
34958f07778SDavid Daney int retval = 0;
35058f07778SDavid Daney union cvmx_l2c_dbg l2cdbg;
35158f07778SDavid Daney union cvmx_l2c_lckbase lckbase;
35258f07778SDavid Daney union cvmx_l2c_lckoff lckoff;
35358f07778SDavid Daney union cvmx_l2t_err l2t_err;
354b8db85b5SDavid Daney
355b8db85b5SDavid Daney cvmx_spinlock_lock(&cvmx_l2c_spinlock);
356b8db85b5SDavid Daney
35758f07778SDavid Daney l2cdbg.u64 = 0;
35858f07778SDavid Daney lckbase.u64 = 0;
35958f07778SDavid Daney lckoff.u64 = 0;
36058f07778SDavid Daney
36158f07778SDavid Daney /* Clear l2t error bits if set */
36258f07778SDavid Daney l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
36358f07778SDavid Daney l2t_err.s.lckerr = 1;
36458f07778SDavid Daney l2t_err.s.lckerr2 = 1;
36558f07778SDavid Daney cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
36658f07778SDavid Daney
36758f07778SDavid Daney addr &= ~CVMX_CACHE_LINE_MASK;
36858f07778SDavid Daney
36958f07778SDavid Daney /* Set this core as debug core */
37058f07778SDavid Daney l2cdbg.s.ppnum = cvmx_get_core_num();
37158f07778SDavid Daney CVMX_SYNC;
37258f07778SDavid Daney cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
37358f07778SDavid Daney cvmx_read_csr(CVMX_L2C_DBG);
37458f07778SDavid Daney
37558f07778SDavid Daney lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */
37658f07778SDavid Daney cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64);
37758f07778SDavid Daney cvmx_read_csr(CVMX_L2C_LCKOFF);
37858f07778SDavid Daney
37958f07778SDavid Daney if (((union cvmx_l2c_cfg)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) {
380b8db85b5SDavid Daney int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1;
381b8db85b5SDavid Daney uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS;
38215f68479SSteven J. Hill
38358f07778SDavid Daney lckbase.s.lck_base = addr_tmp >> 7;
38415f68479SSteven J. Hill
38558f07778SDavid Daney } else {
38658f07778SDavid Daney lckbase.s.lck_base = addr >> 7;
38758f07778SDavid Daney }
38858f07778SDavid Daney
38958f07778SDavid Daney lckbase.s.lck_ena = 1;
39058f07778SDavid Daney cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
391b8db85b5SDavid Daney /* Make sure it gets there */
392b8db85b5SDavid Daney cvmx_read_csr(CVMX_L2C_LCKBASE);
39358f07778SDavid Daney
39458f07778SDavid Daney fault_in(addr, CVMX_CACHE_LINE_SIZE);
39558f07778SDavid Daney
39658f07778SDavid Daney lckbase.s.lck_ena = 0;
39758f07778SDavid Daney cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
398b8db85b5SDavid Daney /* Make sure it gets there */
399b8db85b5SDavid Daney cvmx_read_csr(CVMX_L2C_LCKBASE);
40058f07778SDavid Daney
40158f07778SDavid Daney /* Stop being debug core */
40258f07778SDavid Daney cvmx_write_csr(CVMX_L2C_DBG, 0);
40358f07778SDavid Daney cvmx_read_csr(CVMX_L2C_DBG);
40458f07778SDavid Daney
40558f07778SDavid Daney l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
40658f07778SDavid Daney if (l2t_err.s.lckerr || l2t_err.s.lckerr2)
40758f07778SDavid Daney retval = 1; /* We were unable to lock the line */
40858f07778SDavid Daney
40958f07778SDavid Daney cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
41058f07778SDavid Daney return retval;
41158f07778SDavid Daney }
412b8db85b5SDavid Daney }
41358f07778SDavid Daney
cvmx_l2c_lock_mem_region(uint64_t start,uint64_t len)41458f07778SDavid Daney int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len)
41558f07778SDavid Daney {
41658f07778SDavid Daney int retval = 0;
41758f07778SDavid Daney
41858f07778SDavid Daney /* Round start/end to cache line boundaries */
41958f07778SDavid Daney len += start & CVMX_CACHE_LINE_MASK;
42058f07778SDavid Daney start &= ~CVMX_CACHE_LINE_MASK;
42158f07778SDavid Daney len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
42258f07778SDavid Daney
42358f07778SDavid Daney while (len) {
42458f07778SDavid Daney retval += cvmx_l2c_lock_line(start);
42558f07778SDavid Daney start += CVMX_CACHE_LINE_SIZE;
42658f07778SDavid Daney len -= CVMX_CACHE_LINE_SIZE;
42758f07778SDavid Daney }
42858f07778SDavid Daney return retval;
42958f07778SDavid Daney }
43058f07778SDavid Daney
cvmx_l2c_flush(void)43158f07778SDavid Daney void cvmx_l2c_flush(void)
43258f07778SDavid Daney {
43358f07778SDavid Daney uint64_t assoc, set;
43458f07778SDavid Daney uint64_t n_assoc, n_set;
43558f07778SDavid Daney
436b8db85b5SDavid Daney n_set = cvmx_l2c_get_num_sets();
437b8db85b5SDavid Daney n_assoc = cvmx_l2c_get_num_assoc();
43858f07778SDavid Daney
439b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
440b8db85b5SDavid Daney uint64_t address;
441b8db85b5SDavid Daney /* These may look like constants, but they aren't... */
442b8db85b5SDavid Daney int assoc_shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
443b8db85b5SDavid Daney int set_shift = CVMX_L2C_IDX_ADDR_SHIFT;
44415f68479SSteven J. Hill
44558f07778SDavid Daney for (set = 0; set < n_set; set++) {
44658f07778SDavid Daney for (assoc = 0; assoc < n_assoc; assoc++) {
447b8db85b5SDavid Daney address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
448b8db85b5SDavid Daney (assoc << assoc_shift) | (set << set_shift));
449b8db85b5SDavid Daney CVMX_CACHE_WBIL2I(address, 0);
450b8db85b5SDavid Daney }
451b8db85b5SDavid Daney }
452b8db85b5SDavid Daney } else {
453b8db85b5SDavid Daney for (set = 0; set < n_set; set++)
454b8db85b5SDavid Daney for (assoc = 0; assoc < n_assoc; assoc++)
455b8db85b5SDavid Daney cvmx_l2c_flush_line(assoc, set);
45658f07778SDavid Daney }
45758f07778SDavid Daney }
45858f07778SDavid Daney
45958f07778SDavid Daney
cvmx_l2c_unlock_line(uint64_t address)46058f07778SDavid Daney int cvmx_l2c_unlock_line(uint64_t address)
46158f07778SDavid Daney {
462b8db85b5SDavid Daney
463b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
46458f07778SDavid Daney int assoc;
46558f07778SDavid Daney union cvmx_l2c_tag tag;
466b8db85b5SDavid Daney uint32_t tag_addr;
467b8db85b5SDavid Daney uint32_t index = cvmx_l2c_address_to_index(address);
468b8db85b5SDavid Daney
469b8db85b5SDavid Daney tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
470b8db85b5SDavid Daney
471b8db85b5SDavid Daney /*
472b8db85b5SDavid Daney * For 63XX, we can flush a line by using the physical
473b8db85b5SDavid Daney * address directly, so finding the cache line used by
474b8db85b5SDavid Daney * the address is only required to provide the proper
475b8db85b5SDavid Daney * return value for the function.
476b8db85b5SDavid Daney */
477b8db85b5SDavid Daney for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
478b8db85b5SDavid Daney tag = cvmx_l2c_get_tag(assoc, index);
479b8db85b5SDavid Daney
480b8db85b5SDavid Daney if (tag.s.V && (tag.s.addr == tag_addr)) {
481b8db85b5SDavid Daney CVMX_CACHE_WBIL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0);
482b8db85b5SDavid Daney return tag.s.L;
483b8db85b5SDavid Daney }
484b8db85b5SDavid Daney }
485b8db85b5SDavid Daney } else {
486b8db85b5SDavid Daney int assoc;
487b8db85b5SDavid Daney union cvmx_l2c_tag tag;
48858f07778SDavid Daney uint32_t tag_addr;
48958f07778SDavid Daney
49058f07778SDavid Daney uint32_t index = cvmx_l2c_address_to_index(address);
49158f07778SDavid Daney
49258f07778SDavid Daney /* Compute portion of address that is stored in tag */
493b8db85b5SDavid Daney tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
49458f07778SDavid Daney for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
495b8db85b5SDavid Daney tag = cvmx_l2c_get_tag(assoc, index);
49658f07778SDavid Daney
49758f07778SDavid Daney if (tag.s.V && (tag.s.addr == tag_addr)) {
498b8db85b5SDavid Daney cvmx_l2c_flush_line(assoc, index);
49958f07778SDavid Daney return tag.s.L;
50058f07778SDavid Daney }
50158f07778SDavid Daney }
502b8db85b5SDavid Daney }
50358f07778SDavid Daney return 0;
50458f07778SDavid Daney }
50558f07778SDavid Daney
cvmx_l2c_unlock_mem_region(uint64_t start,uint64_t len)50658f07778SDavid Daney int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len)
50758f07778SDavid Daney {
50858f07778SDavid Daney int num_unlocked = 0;
50958f07778SDavid Daney /* Round start/end to cache line boundaries */
51058f07778SDavid Daney len += start & CVMX_CACHE_LINE_MASK;
51158f07778SDavid Daney start &= ~CVMX_CACHE_LINE_MASK;
51258f07778SDavid Daney len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK;
51358f07778SDavid Daney while (len > 0) {
51458f07778SDavid Daney num_unlocked += cvmx_l2c_unlock_line(start);
51558f07778SDavid Daney start += CVMX_CACHE_LINE_SIZE;
51658f07778SDavid Daney len -= CVMX_CACHE_LINE_SIZE;
51758f07778SDavid Daney }
51858f07778SDavid Daney
51958f07778SDavid Daney return num_unlocked;
52058f07778SDavid Daney }
52158f07778SDavid Daney
52258f07778SDavid Daney /*
52358f07778SDavid Daney * Internal l2c tag types. These are converted to a generic structure
52458f07778SDavid Daney * that can be used on all chips.
52558f07778SDavid Daney */
52658f07778SDavid Daney union __cvmx_l2c_tag {
52758f07778SDavid Daney uint64_t u64;
52858f07778SDavid Daney struct cvmx_l2c_tag_cn50xx {
52915f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t reserved:40,
53015f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t V:1, /* Line valid */
53115f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */
53215f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t L:1, /* Line locked */
53315f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */
53415f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t addr:20, /* Phys addr (33..14) */
53515f68479SSteven J. Hill ;))))))
53658f07778SDavid Daney } cn50xx;
53758f07778SDavid Daney struct cvmx_l2c_tag_cn30xx {
53815f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t reserved:41,
53915f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t V:1, /* Line valid */
54015f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */
54115f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t L:1, /* Line locked */
54215f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */
54315f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t addr:19, /* Phys addr (33..15) */
54415f68479SSteven J. Hill ;))))))
54558f07778SDavid Daney } cn30xx;
54658f07778SDavid Daney struct cvmx_l2c_tag_cn31xx {
54715f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t reserved:42,
54815f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t V:1, /* Line valid */
54915f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */
55015f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t L:1, /* Line locked */
55115f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */
55215f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t addr:18, /* Phys addr (33..16) */
55315f68479SSteven J. Hill ;))))))
55458f07778SDavid Daney } cn31xx;
55558f07778SDavid Daney struct cvmx_l2c_tag_cn38xx {
55615f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t reserved:43,
55715f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t V:1, /* Line valid */
55815f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */
55915f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t L:1, /* Line locked */
56015f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */
56115f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t addr:17, /* Phys addr (33..17) */
56215f68479SSteven J. Hill ;))))))
56358f07778SDavid Daney } cn38xx;
56458f07778SDavid Daney struct cvmx_l2c_tag_cn58xx {
56515f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t reserved:44,
56615f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t V:1, /* Line valid */
56715f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t D:1, /* Line dirty */
56815f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t L:1, /* Line locked */
56915f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t U:1, /* Use, LRU eviction */
57015f68479SSteven J. Hill __BITFIELD_FIELD(uint64_t addr:16, /* Phys addr (33..18) */
57115f68479SSteven J. Hill ;))))))
57258f07778SDavid Daney } cn58xx;
57358f07778SDavid Daney struct cvmx_l2c_tag_cn58xx cn56xx; /* 2048 sets */
57458f07778SDavid Daney struct cvmx_l2c_tag_cn31xx cn52xx; /* 512 sets */
57558f07778SDavid Daney };
57658f07778SDavid Daney
577b8db85b5SDavid Daney
578*16df55ceSRandy Dunlap /*
57958f07778SDavid Daney * @INTERNAL
58058f07778SDavid Daney * Function to read a L2C tag. This code make the current core
58158f07778SDavid Daney * the 'debug core' for the L2. This code must only be executed by
58258f07778SDavid Daney * 1 core at a time.
58358f07778SDavid Daney *
58458f07778SDavid Daney * @assoc: Association (way) of the tag to dump
58558f07778SDavid Daney * @index: Index of the cacheline
58658f07778SDavid Daney *
58758f07778SDavid Daney * Returns The Octeon model specific tag structure. This is
58858f07778SDavid Daney * translated by a wrapper function to a generic form that is
58958f07778SDavid Daney * easier for applications to use.
59058f07778SDavid Daney */
__read_l2_tag(uint64_t assoc,uint64_t index)59158f07778SDavid Daney static union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index)
59258f07778SDavid Daney {
59358f07778SDavid Daney
594b8db85b5SDavid Daney uint64_t debug_tag_addr = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, (index << 7) + 96);
59558f07778SDavid Daney uint64_t core = cvmx_get_core_num();
59658f07778SDavid Daney union __cvmx_l2c_tag tag_val;
59758f07778SDavid Daney uint64_t dbg_addr = CVMX_L2C_DBG;
59858f07778SDavid Daney unsigned long flags;
59958f07778SDavid Daney union cvmx_l2c_dbg debug_val;
60015f68479SSteven J. Hill
60158f07778SDavid Daney debug_val.u64 = 0;
60258f07778SDavid Daney /*
603b8db85b5SDavid Daney * For low core count parts, the core number is always small
604b8db85b5SDavid Daney * enough to stay in the correct field and not set any
605b8db85b5SDavid Daney * reserved bits.
60658f07778SDavid Daney */
60758f07778SDavid Daney debug_val.s.ppnum = core;
60858f07778SDavid Daney debug_val.s.l2t = 1;
60958f07778SDavid Daney debug_val.s.set = assoc;
610b8db85b5SDavid Daney
611b8db85b5SDavid Daney local_irq_save(flags);
61258f07778SDavid Daney /*
61358f07778SDavid Daney * Make sure core is quiet (no prefetches, etc.) before
61458f07778SDavid Daney * entering debug mode.
61558f07778SDavid Daney */
61658f07778SDavid Daney CVMX_SYNC;
61758f07778SDavid Daney /* Flush L1 to make sure debug load misses L1 */
61858f07778SDavid Daney CVMX_DCACHE_INVALIDATE;
61958f07778SDavid Daney
62058f07778SDavid Daney /*
62158f07778SDavid Daney * The following must be done in assembly as when in debug
62258f07778SDavid Daney * mode all data loads from L2 return special debug data, not
623b8db85b5SDavid Daney * normal memory contents. Also, interrupts must be disabled,
624b8db85b5SDavid Daney * since if an interrupt occurs while in debug mode the ISR
625b8db85b5SDavid Daney * will get debug data from all its memory * reads instead of
626b8db85b5SDavid Daney * the contents of memory.
62758f07778SDavid Daney */
62858f07778SDavid Daney
629b8db85b5SDavid Daney asm volatile (
630b8db85b5SDavid Daney ".set push\n\t"
631b8db85b5SDavid Daney ".set mips64\n\t"
632b8db85b5SDavid Daney ".set noreorder\n\t"
633b8db85b5SDavid Daney "sd %[dbg_val], 0(%[dbg_addr])\n\t" /* Enter debug mode, wait for store */
634b8db85b5SDavid Daney "ld $0, 0(%[dbg_addr])\n\t"
635b8db85b5SDavid Daney "ld %[tag_val], 0(%[tag_addr])\n\t" /* Read L2C tag data */
636b8db85b5SDavid Daney "sd $0, 0(%[dbg_addr])\n\t" /* Exit debug mode, wait for store */
637b8db85b5SDavid Daney "ld $0, 0(%[dbg_addr])\n\t"
638b8db85b5SDavid Daney "cache 9, 0($0)\n\t" /* Invalidate dcache to discard debug data */
639b8db85b5SDavid Daney ".set pop"
640b8db85b5SDavid Daney : [tag_val] "=r" (tag_val)
641b8db85b5SDavid Daney : [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr)
642b8db85b5SDavid Daney : "memory");
64358f07778SDavid Daney
64458f07778SDavid Daney local_irq_restore(flags);
64558f07778SDavid Daney
646b8db85b5SDavid Daney return tag_val;
64758f07778SDavid Daney }
64858f07778SDavid Daney
649b8db85b5SDavid Daney
cvmx_l2c_get_tag(uint32_t association,uint32_t index)65058f07778SDavid Daney union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index)
65158f07778SDavid Daney {
65258f07778SDavid Daney union cvmx_l2c_tag tag;
65358f07778SDavid Daney
65415f68479SSteven J. Hill tag.u64 = 0;
65558f07778SDavid Daney if ((int)association >= cvmx_l2c_get_num_assoc()) {
656b8db85b5SDavid Daney cvmx_dprintf("ERROR: cvmx_l2c_get_tag association out of range\n");
65758f07778SDavid Daney return tag;
65858f07778SDavid Daney }
65958f07778SDavid Daney if ((int)index >= cvmx_l2c_get_num_sets()) {
660b8db85b5SDavid Daney cvmx_dprintf("ERROR: cvmx_l2c_get_tag index out of range (arg: %d, max: %d)\n",
661b8db85b5SDavid Daney (int)index, cvmx_l2c_get_num_sets());
66258f07778SDavid Daney return tag;
66358f07778SDavid Daney }
664b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
665b8db85b5SDavid Daney union cvmx_l2c_tadx_tag l2c_tadx_tag;
666b8db85b5SDavid Daney uint64_t address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
667b8db85b5SDavid Daney (association << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
668b8db85b5SDavid Daney (index << CVMX_L2C_IDX_ADDR_SHIFT));
669b8db85b5SDavid Daney /*
670b8db85b5SDavid Daney * Use L2 cache Index load tag cache instruction, as
671b8db85b5SDavid Daney * hardware loads the virtual tag for the L2 cache
672b8db85b5SDavid Daney * block with the contents of L2C_TAD0_TAG
673b8db85b5SDavid Daney * register.
674b8db85b5SDavid Daney */
675b8db85b5SDavid Daney CVMX_CACHE_LTGL2I(address, 0);
676b8db85b5SDavid Daney CVMX_SYNC; /* make sure CVMX_L2C_TADX_TAG is updated */
677b8db85b5SDavid Daney l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
678b8db85b5SDavid Daney
679b8db85b5SDavid Daney tag.s.V = l2c_tadx_tag.s.valid;
680b8db85b5SDavid Daney tag.s.D = l2c_tadx_tag.s.dirty;
681b8db85b5SDavid Daney tag.s.L = l2c_tadx_tag.s.lock;
682b8db85b5SDavid Daney tag.s.U = l2c_tadx_tag.s.use;
683b8db85b5SDavid Daney tag.s.addr = l2c_tadx_tag.s.tag;
684b8db85b5SDavid Daney } else {
685b8db85b5SDavid Daney union __cvmx_l2c_tag tmp_tag;
68658f07778SDavid Daney /* __read_l2_tag is intended for internal use only */
68758f07778SDavid Daney tmp_tag = __read_l2_tag(association, index);
68858f07778SDavid Daney
68958f07778SDavid Daney /*
690b8db85b5SDavid Daney * Convert all tag structure types to generic version,
691b8db85b5SDavid Daney * as it can represent all models.
69258f07778SDavid Daney */
69358f07778SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
69458f07778SDavid Daney tag.s.V = tmp_tag.cn58xx.V;
69558f07778SDavid Daney tag.s.D = tmp_tag.cn58xx.D;
69658f07778SDavid Daney tag.s.L = tmp_tag.cn58xx.L;
69758f07778SDavid Daney tag.s.U = tmp_tag.cn58xx.U;
69858f07778SDavid Daney tag.s.addr = tmp_tag.cn58xx.addr;
69958f07778SDavid Daney } else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
70058f07778SDavid Daney tag.s.V = tmp_tag.cn38xx.V;
70158f07778SDavid Daney tag.s.D = tmp_tag.cn38xx.D;
70258f07778SDavid Daney tag.s.L = tmp_tag.cn38xx.L;
70358f07778SDavid Daney tag.s.U = tmp_tag.cn38xx.U;
70458f07778SDavid Daney tag.s.addr = tmp_tag.cn38xx.addr;
705b8db85b5SDavid Daney } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
70658f07778SDavid Daney tag.s.V = tmp_tag.cn31xx.V;
70758f07778SDavid Daney tag.s.D = tmp_tag.cn31xx.D;
70858f07778SDavid Daney tag.s.L = tmp_tag.cn31xx.L;
70958f07778SDavid Daney tag.s.U = tmp_tag.cn31xx.U;
71058f07778SDavid Daney tag.s.addr = tmp_tag.cn31xx.addr;
71158f07778SDavid Daney } else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) {
71258f07778SDavid Daney tag.s.V = tmp_tag.cn30xx.V;
71358f07778SDavid Daney tag.s.D = tmp_tag.cn30xx.D;
71458f07778SDavid Daney tag.s.L = tmp_tag.cn30xx.L;
71558f07778SDavid Daney tag.s.U = tmp_tag.cn30xx.U;
71658f07778SDavid Daney tag.s.addr = tmp_tag.cn30xx.addr;
71758f07778SDavid Daney } else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
71858f07778SDavid Daney tag.s.V = tmp_tag.cn50xx.V;
71958f07778SDavid Daney tag.s.D = tmp_tag.cn50xx.D;
72058f07778SDavid Daney tag.s.L = tmp_tag.cn50xx.L;
72158f07778SDavid Daney tag.s.U = tmp_tag.cn50xx.U;
72258f07778SDavid Daney tag.s.addr = tmp_tag.cn50xx.addr;
72358f07778SDavid Daney } else {
72458f07778SDavid Daney cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
72558f07778SDavid Daney }
726b8db85b5SDavid Daney }
72758f07778SDavid Daney return tag;
72858f07778SDavid Daney }
72958f07778SDavid Daney
cvmx_l2c_address_to_index(uint64_t addr)73058f07778SDavid Daney uint32_t cvmx_l2c_address_to_index(uint64_t addr)
73158f07778SDavid Daney {
73258f07778SDavid Daney uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT;
733b8db85b5SDavid Daney int indxalias = 0;
734b8db85b5SDavid Daney
735b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
736b8db85b5SDavid Daney union cvmx_l2c_ctl l2c_ctl;
73715f68479SSteven J. Hill
738b8db85b5SDavid Daney l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL);
739b8db85b5SDavid Daney indxalias = !l2c_ctl.s.disidxalias;
740b8db85b5SDavid Daney } else {
74158f07778SDavid Daney union cvmx_l2c_cfg l2c_cfg;
74215f68479SSteven J. Hill
74358f07778SDavid Daney l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
744b8db85b5SDavid Daney indxalias = l2c_cfg.s.idxalias;
745b8db85b5SDavid Daney }
74658f07778SDavid Daney
747b8db85b5SDavid Daney if (indxalias) {
748b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
749b8db85b5SDavid Daney uint32_t a_14_12 = (idx / (CVMX_L2C_MEMBANK_SELECT_SIZE/(1<<CVMX_L2C_IDX_ADDR_SHIFT))) & 0x7;
75015f68479SSteven J. Hill
751b8db85b5SDavid Daney idx ^= idx / cvmx_l2c_get_num_sets();
752b8db85b5SDavid Daney idx ^= a_14_12;
753b8db85b5SDavid Daney } else {
754b8db85b5SDavid Daney idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT);
755b8db85b5SDavid Daney }
75658f07778SDavid Daney }
75758f07778SDavid Daney idx &= CVMX_L2C_IDX_MASK;
75858f07778SDavid Daney return idx;
75958f07778SDavid Daney }
76058f07778SDavid Daney
cvmx_l2c_get_cache_size_bytes(void)76158f07778SDavid Daney int cvmx_l2c_get_cache_size_bytes(void)
76258f07778SDavid Daney {
76358f07778SDavid Daney return cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() *
76458f07778SDavid Daney CVMX_CACHE_LINE_SIZE;
76558f07778SDavid Daney }
76658f07778SDavid Daney
767*16df55ceSRandy Dunlap /*
76858f07778SDavid Daney * Return log base 2 of the number of sets in the L2 cache
76958f07778SDavid Daney */
cvmx_l2c_get_set_bits(void)77058f07778SDavid Daney int cvmx_l2c_get_set_bits(void)
77158f07778SDavid Daney {
77258f07778SDavid Daney int l2_set_bits;
77315f68479SSteven J. Hill
77458f07778SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
77558f07778SDavid Daney l2_set_bits = 11; /* 2048 sets */
776b8db85b5SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
77758f07778SDavid Daney l2_set_bits = 10; /* 1024 sets */
778b8db85b5SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
77958f07778SDavid Daney l2_set_bits = 9; /* 512 sets */
78058f07778SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
78158f07778SDavid Daney l2_set_bits = 8; /* 256 sets */
78258f07778SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
78358f07778SDavid Daney l2_set_bits = 7; /* 128 sets */
78458f07778SDavid Daney else {
78558f07778SDavid Daney cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
78658f07778SDavid Daney l2_set_bits = 11; /* 2048 sets */
78758f07778SDavid Daney }
78858f07778SDavid Daney return l2_set_bits;
78958f07778SDavid Daney }
79058f07778SDavid Daney
79158f07778SDavid Daney /* Return the number of sets in the L2 Cache */
cvmx_l2c_get_num_sets(void)79258f07778SDavid Daney int cvmx_l2c_get_num_sets(void)
79358f07778SDavid Daney {
79458f07778SDavid Daney return 1 << cvmx_l2c_get_set_bits();
79558f07778SDavid Daney }
79658f07778SDavid Daney
79758f07778SDavid Daney /* Return the number of associations in the L2 Cache */
cvmx_l2c_get_num_assoc(void)79858f07778SDavid Daney int cvmx_l2c_get_num_assoc(void)
79958f07778SDavid Daney {
80058f07778SDavid Daney int l2_assoc;
80115f68479SSteven J. Hill
80258f07778SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN56XX) ||
80358f07778SDavid Daney OCTEON_IS_MODEL(OCTEON_CN52XX) ||
80458f07778SDavid Daney OCTEON_IS_MODEL(OCTEON_CN58XX) ||
805b8db85b5SDavid Daney OCTEON_IS_MODEL(OCTEON_CN50XX) ||
806b8db85b5SDavid Daney OCTEON_IS_MODEL(OCTEON_CN38XX))
80758f07778SDavid Daney l2_assoc = 8;
808b8db85b5SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
809b8db85b5SDavid Daney l2_assoc = 16;
81058f07778SDavid Daney else if (OCTEON_IS_MODEL(OCTEON_CN31XX) ||
81158f07778SDavid Daney OCTEON_IS_MODEL(OCTEON_CN30XX))
81258f07778SDavid Daney l2_assoc = 4;
81358f07778SDavid Daney else {
81458f07778SDavid Daney cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
81558f07778SDavid Daney l2_assoc = 8;
81658f07778SDavid Daney }
81758f07778SDavid Daney
81858f07778SDavid Daney /* Check to see if part of the cache is disabled */
819b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
820b8db85b5SDavid Daney union cvmx_mio_fus_dat3 mio_fus_dat3;
82158f07778SDavid Daney
822b8db85b5SDavid Daney mio_fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
823b8db85b5SDavid Daney /*
824b8db85b5SDavid Daney * cvmx_mio_fus_dat3.s.l2c_crip fuses map as follows
825b8db85b5SDavid Daney * <2> will be not used for 63xx
826b8db85b5SDavid Daney * <1> disables 1/2 ways
827b8db85b5SDavid Daney * <0> disables 1/4 ways
828b8db85b5SDavid Daney * They are cumulative, so for 63xx:
829b8db85b5SDavid Daney * <1> <0>
830b8db85b5SDavid Daney * 0 0 16-way 2MB cache
831b8db85b5SDavid Daney * 0 1 12-way 1.5MB cache
832b8db85b5SDavid Daney * 1 0 8-way 1MB cache
833b8db85b5SDavid Daney * 1 1 4-way 512KB cache
834b8db85b5SDavid Daney */
835b8db85b5SDavid Daney
836b8db85b5SDavid Daney if (mio_fus_dat3.s.l2c_crip == 3)
837b8db85b5SDavid Daney l2_assoc = 4;
838b8db85b5SDavid Daney else if (mio_fus_dat3.s.l2c_crip == 2)
839b8db85b5SDavid Daney l2_assoc = 8;
840b8db85b5SDavid Daney else if (mio_fus_dat3.s.l2c_crip == 1)
841b8db85b5SDavid Daney l2_assoc = 12;
842b8db85b5SDavid Daney } else {
84315f68479SSteven J. Hill uint64_t l2d_fus3;
84415f68479SSteven J. Hill
84515f68479SSteven J. Hill l2d_fus3 = cvmx_read_csr(CVMX_L2D_FUS3);
846b8db85b5SDavid Daney /*
847b8db85b5SDavid Daney * Using shifts here, as bit position names are
848b8db85b5SDavid Daney * different for each model but they all mean the
849b8db85b5SDavid Daney * same.
850b8db85b5SDavid Daney */
85115f68479SSteven J. Hill if ((l2d_fus3 >> 35) & 0x1)
852b8db85b5SDavid Daney l2_assoc = l2_assoc >> 2;
85315f68479SSteven J. Hill else if ((l2d_fus3 >> 34) & 0x1)
854b8db85b5SDavid Daney l2_assoc = l2_assoc >> 1;
855b8db85b5SDavid Daney }
85658f07778SDavid Daney return l2_assoc;
85758f07778SDavid Daney }
85858f07778SDavid Daney
859*16df55ceSRandy Dunlap /*
86058f07778SDavid Daney * Flush a line from the L2 cache
86158f07778SDavid Daney * This should only be called from one core at a time, as this routine
86258f07778SDavid Daney * sets the core to the 'debug' core in order to flush the line.
86358f07778SDavid Daney *
86458f07778SDavid Daney * @assoc: Association (or way) to flush
86558f07778SDavid Daney * @index: Index to flush
86658f07778SDavid Daney */
cvmx_l2c_flush_line(uint32_t assoc,uint32_t index)86758f07778SDavid Daney void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index)
86858f07778SDavid Daney {
869b8db85b5SDavid Daney /* Check the range of the index. */
870b8db85b5SDavid Daney if (index > (uint32_t)cvmx_l2c_get_num_sets()) {
871b8db85b5SDavid Daney cvmx_dprintf("ERROR: cvmx_l2c_flush_line index out of range.\n");
872b8db85b5SDavid Daney return;
873b8db85b5SDavid Daney }
874b8db85b5SDavid Daney
875b8db85b5SDavid Daney /* Check the range of association. */
876b8db85b5SDavid Daney if (assoc > (uint32_t)cvmx_l2c_get_num_assoc()) {
877b8db85b5SDavid Daney cvmx_dprintf("ERROR: cvmx_l2c_flush_line association out of range.\n");
878b8db85b5SDavid Daney return;
879b8db85b5SDavid Daney }
880b8db85b5SDavid Daney
881b8db85b5SDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
882b8db85b5SDavid Daney uint64_t address;
883b8db85b5SDavid Daney /* Create the address based on index and association.
884b8db85b5SDavid Daney * Bits<20:17> select the way of the cache block involved in
885b8db85b5SDavid Daney * the operation
886b8db85b5SDavid Daney * Bits<16:7> of the effect address select the index
887b8db85b5SDavid Daney */
888b8db85b5SDavid Daney address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
889b8db85b5SDavid Daney (assoc << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
890b8db85b5SDavid Daney (index << CVMX_L2C_IDX_ADDR_SHIFT));
891b8db85b5SDavid Daney CVMX_CACHE_WBIL2I(address, 0);
892b8db85b5SDavid Daney } else {
89358f07778SDavid Daney union cvmx_l2c_dbg l2cdbg;
89458f07778SDavid Daney
89558f07778SDavid Daney l2cdbg.u64 = 0;
896b8db85b5SDavid Daney if (!OCTEON_IS_MODEL(OCTEON_CN30XX))
89758f07778SDavid Daney l2cdbg.s.ppnum = cvmx_get_core_num();
89858f07778SDavid Daney l2cdbg.s.finv = 1;
89958f07778SDavid Daney
90058f07778SDavid Daney l2cdbg.s.set = assoc;
901b8db85b5SDavid Daney cvmx_spinlock_lock(&cvmx_l2c_spinlock);
90258f07778SDavid Daney /*
903b8db85b5SDavid Daney * Enter debug mode, and make sure all other writes
904b8db85b5SDavid Daney * complete before we enter debug mode
90558f07778SDavid Daney */
906b8db85b5SDavid Daney CVMX_SYNC;
90758f07778SDavid Daney cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
90858f07778SDavid Daney cvmx_read_csr(CVMX_L2C_DBG);
90958f07778SDavid Daney
910b8db85b5SDavid Daney CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
911b8db85b5SDavid Daney index * CVMX_CACHE_LINE_SIZE),
912b8db85b5SDavid Daney 0);
91358f07778SDavid Daney /* Exit debug mode */
914b8db85b5SDavid Daney CVMX_SYNC;
91558f07778SDavid Daney cvmx_write_csr(CVMX_L2C_DBG, 0);
91658f07778SDavid Daney cvmx_read_csr(CVMX_L2C_DBG);
917b8db85b5SDavid Daney cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
918b8db85b5SDavid Daney }
91958f07778SDavid Daney }
920