/* $OpenBSD: cache_octeon.c,v 1.13 2018/12/04 16:24:13 visa Exp $ */ /* * Copyright (c) 2010 Takuya ASADA. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Copyright (c) 1998-2004 Opsycon AB (www.opsycon.se) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #define SYNCI() \ asm volatile( \ ".set push\n" \ ".set mips64r2\n" \ ".word 0x041f0000\n" \ "nop\n" \ ".set pop") void Octeon_ConfigCache(struct cpu_info *ci) { uint32_t cfg; uint32_t s, l, a; switch (ci->ci_hw.type) { default: /* OCTEON and OCTEON Plus */ cfg = cp0_get_config_1(); /* * Octeon L1 cache information does not follow the mips64 * standard encoding. */ a = (cfg >> 16) & 0x07; l = (cfg >> 19) & 0x07; s = (cfg >> 22) & 0x07; ci->ci_l1inst.linesize = 2 << l; ci->ci_l1inst.setsize = (64 << s) * ci->ci_l1inst.linesize; if (a >= 1) ci->ci_l1inst.sets = 1 << (a - 1); else ci->ci_l1inst.sets = 1; ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; ci->ci_l1data.linesize = 128; ci->ci_l1data.setsize = 2 * 128; ci->ci_l1data.sets = 64; ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; break; case MIPS_CN61XX: case MIPS_CN63XX: case MIPS_CN66XX: case MIPS_CN68XX: /* OCTEON II */ ci->ci_l1inst.linesize = 128; ci->ci_l1inst.setsize = 8 * 128; ci->ci_l1inst.sets = 37; ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; ci->ci_l1data.linesize = 128; ci->ci_l1data.setsize = 8 * 128; ci->ci_l1data.sets = 32; ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; break; case MIPS_CN71XX: case MIPS_CN73XX: case MIPS_CN78XX: /* OCTEON III */ ci->ci_l1inst.linesize = 128; ci->ci_l1inst.setsize = 16 * 128; ci->ci_l1inst.sets = 39; ci->ci_l1inst.size = ci->ci_l1inst.sets * ci->ci_l1inst.setsize; ci->ci_l1data.linesize = 128; ci->ci_l1data.setsize = 8 * 128; ci->ci_l1data.sets = 32; ci->ci_l1data.size = ci->ci_l1data.sets * ci->ci_l1data.setsize; break; } cfg = cp0_get_config_2(); a = 1 + ((cfg >> 0) & 0x0f); l = (cfg >> 4) & 0x0f; s = (cfg >> 8) & 0x0f; ci->ci_l2.linesize = 2 << l; ci->ci_l2.sets = a; ci->ci_l2.setsize = (64 << s) * ci->ci_l2.linesize; ci->ci_l2.size = ci->ci_l2.sets * ci->ci_l2.setsize; memset(&ci->ci_l3, 0, sizeof(struct cache_info)); ci->ci_SyncCache = Octeon_SyncCache; ci->ci_InvalidateICache = Octeon_InvalidateICache; ci->ci_InvalidateICachePage = Octeon_InvalidateICachePage; ci->ci_SyncICache = Octeon_SyncICache; ci->ci_SyncDCachePage = Octeon_SyncDCachePage; ci->ci_HitSyncDCachePage = Octeon_SyncDCachePage; ci->ci_HitSyncDCache = Octeon_HitSyncDCache; ci->ci_HitInvalidateDCache = Octeon_HitInvalidateDCache; ci->ci_IOSyncDCache = Octeon_IOSyncDCache; } void Octeon_SyncCache(struct cpu_info *ci) { mips_sync(); } void Octeon_InvalidateICache(struct cpu_info *ci, vaddr_t va, size_t len) { /* A SYNCI flushes the entire icache on OCTEON */ SYNCI(); } /* * Register a given page for I$ invalidation. */ void Octeon_InvalidateICachePage(struct cpu_info *ci, vaddr_t va) { /* * Since there is apparently no way to operate on a subset of I$, * all we need to do here is remember there are postponed flushes. */ ci->ci_cachepending_l1i = 1; } /* * Perform postponed I$ invalidation. */ void Octeon_SyncICache(struct cpu_info *ci) { if (ci->ci_cachepending_l1i != 0) { SYNCI(); /* Octeon_InvalidateICache(ci, 0, PAGE_SIZE); */ ci->ci_cachepending_l1i = 0; } } void Octeon_SyncDCachePage(struct cpu_info *ci, vaddr_t va, paddr_t pa) { } void Octeon_HitSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len) { } void Octeon_HitInvalidateDCache(struct cpu_info *ci, vaddr_t va, size_t len) { } void Octeon_IOSyncDCache(struct cpu_info *ci, vaddr_t va, size_t len, int how) { switch (how) { default: case CACHE_SYNC_R: break; case CACHE_SYNC_W: /* writeback */ case CACHE_SYNC_X: /* writeback and invalidate */ mips_sync(); break; } } void Octeon_lock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz) { size_t linesize = ci->ci_l2.linesize; size_t sz; paddr_t pa; vaddr_t end, va; pa = _pa & ~(linesize - 1); sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa; va = PHYS_TO_XKPHYS(pa, 0ul); end = va + sz; while (va < end) { asm volatile ("cache 31, (%0)" : : "r" (va)); va += linesize; } /* Wait for the lock operations to finish. */ mips_sync(); } void Octeon_unlock_secondary_cache(struct cpu_info *ci, paddr_t _pa, size_t _sz) { size_t linesize = ci->ci_l2.linesize; size_t sz; paddr_t pa; vaddr_t end, va; pa = _pa & ~(linesize - 1); sz = ((_pa + _sz + linesize - 1) & ~(linesize - 1)) - pa; va = PHYS_TO_XKPHYS(pa, 0ul); end = va + sz; while (va < end) { asm volatile ("cache 23, (%0)" : : "r" (va)); va += linesize; } }