/* $NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $ */ #include __KERNEL_RCSID(0, "$NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $"); #include #include #include #include #include #define SYNC __asm volatile("sync") #ifdef OCTEON_ICACHE_DEBUG int octeon_cache_debug = 0; #define ICACHE_DEBUG_PRINTF(x) \ if (__predict_false(octeon_cache_debug != 0)) \ printf x; #else #define ICACHE_DEBUG_PRINTF(x) /* nothing */ #endif static inline void mips_synci(vaddr_t va) { __asm __volatile("synci 0(%0)" :: "r"(va)); } void octeon_icache_sync_all(void) { ICACHE_DEBUG_PRINTF(("%s\n", __func__)); mips_synci(MIPS_KSEG0_START); SYNC; } void octeon_icache_sync_range(register_t va, vsize_t size) { ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n", __func__, va, size)); mips_synci(MIPS_KSEG0_START); SYNC; } void octeon_icache_sync_range_index(vaddr_t va, vsize_t size) { ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n", __func__, va, size)); mips_synci(MIPS_KSEG0_START); SYNC; } void octeon_pdcache_inv_all(void) { ICACHE_DEBUG_PRINTF(("%s\n", __func__)); cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); SYNC; } void octeon_pdcache_inv_range(register_t va, vsize_t size) { ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxREGISTER", size=%#"PRIxVSIZE"\n", __func__, va, size)); cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); SYNC; } void octeon_pdcache_inv_range_index(vaddr_t va, vsize_t size) { ICACHE_DEBUG_PRINTF(("%s: va=%#"PRIxVADDR", size=%#"PRIxVSIZE"\n", __func__, va, size)); cache_octeon_invalidate(CACHEOP_OCTEON_INV_ALL | CACHE_OCTEON_D); SYNC; } /* ---- debug dump */ #ifdef OCTEON_ICACHE_DEBUG /* XXX does the following even make sense for Octeon II/III? */ /* icache: 16KB, 2ways */ #define OCTEON_ICACHE_VA_WAY(_va) (((_va) & __BITS(14, 13)) >> 13) #define OCTEON_ICACHE_VA_INDEX(_va) (((_va) & __BITS(12, 7)) >> 7) #define OCTEON_ICACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3) #define OCTEON_ICACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62) #define OCTEON_ICACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52) #define OCTEON_ICACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 13)) >> 13) #define OCTEON_ICACHE_TAGLO_INDEX(_taglo) (((_taglo) & __BITS(12, 7)) >> 7) #define OCTEON_ICACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1) #define OCTEON_ICACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0) /* dcache: 8KB, 64ways */ #define OCTEON_DCACHE_VA_WAY(_va) (((_va) & __BITS(12, 7)) >> 7) #define OCTEON_DCACHE_VA_WORD(_va) (((_va) & __BITS( 6, 3)) >> 3) #define OCTEON_DCACHE_TAGLO_R(_taglo) (((_taglo) & __BITS(63, 62)) >> 62) #define OCTEON_DCACHE_TAGLO_ASID(_taglo) (((_taglo) & __BITS(59, 52)) >> 52) #define OCTEON_DCACHE_TAGLO_TAG(_taglo) (((_taglo) & __BITS(48, 7)) >> 7) #define OCTEON_DCACHE_TAGLO_G(_taglo) (((_taglo) & __BITS( 1, 1)) >> 1) #define OCTEON_DCACHE_TAGLO_VALID(_taglo) (((_taglo) & __BITS( 0, 0)) >> 0) #define OCTEON_DCACHE_TAGHI_PTAG(_taghi) (((_taghi) & __BITS(35, 7)) >> 7) #define OCTEON_DCACHE_TAGHI_VALID(_taghi) (((_taghi) & __BITS( 0, 0)) >> 0) void octeon_icache_dump_all(void); void octeon_icache_dump_way(int); void octeon_icache_dump_index(int, int); void octeon_icache_dump_va(register_t); void octeon_dcache_dump_all(void); void octeon_dcache_dump_way(int); void octeon_dcache_dump_index(int, int); void octeon_dcache_dump_va(register_t); void octeon_icache_dump_all(void) { /* way = (0 .. 3) */ const int maxway = 2; /* XXX 2 << (14 - 13 + 1) == 4? */ int way; for (way = 0; way < maxway; way++) octeon_icache_dump_way(way); } void octeon_icache_dump_way(int way) { /* index = (0 .. 127) */ const int maxindex = 64; /* XXX 2 << (12 - 7 + 1) == 128? */; int index; for (index = 0; index < maxindex; index++) octeon_icache_dump_index(way, index); } void octeon_icache_dump_index(int way, int index) { const vaddr_t va = (way << 13) | (index << 7); octeon_icache_dump_va(va); } void octeon_icache_dump_va(register_t va) { uint64_t taglo, datalo, datahi; /* icache */ __asm __volatile ( " .set push \n" " .set noreorder \n" " .set arch=octeon \n" " cache 4, 0(%[va]) \n" " dmfc0 %[taglo], $28, 0 \n" " dmfc0 %[datalo], $28, 1 \n" " dmfc0 %[datahi], $29, 1 \n" " .set pop \n" : [taglo] "=r" (taglo), [datalo] "=r" (datalo), [datahi] "=r" (datahi) : [va] "r" (va)); printf("%s: va=%08x " "(way=%01x, index=%02x"/* ", word=%01d" */"), " "taglo=%016"PRIx64" " "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", index=%02"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), " "datahi=%01"PRIx64", datalo=%016"PRIx64"" "\n", __func__, (int)((taglo) & __BITS(48, 7)), /* (int)va */ (int)OCTEON_ICACHE_VA_WAY(va), (int)OCTEON_ICACHE_VA_INDEX(va), /* (int)OCTEON_ICACHE_VA_WORD(va), */ taglo, OCTEON_ICACHE_TAGLO_R(taglo), OCTEON_ICACHE_TAGLO_ASID(taglo), OCTEON_ICACHE_TAGLO_TAG(taglo), OCTEON_ICACHE_TAGLO_INDEX(taglo), OCTEON_ICACHE_TAGLO_G(taglo), OCTEON_ICACHE_TAGLO_VALID(taglo), datahi, datalo); } void octeon_dcache_dump_all(void) { /* way = (0 .. 63) */ const int maxway = 64; int way; for (way = 0; way < maxway; way++) octeon_dcache_dump_way(way); } void octeon_dcache_dump_way(int way) { /* index = (0 .. 0) */ const int maxindex = 1; int index; for (index = 0; index < maxindex; index++) octeon_dcache_dump_index(way, index); } void octeon_dcache_dump_index(int way, int index) { const vaddr_t va = (way << 7); /* no index in dcache */ octeon_dcache_dump_va(va); } void octeon_dcache_dump_va(register_t va) { uint64_t taglo, taghi, datalo, datahi; /* dcache */ __asm __volatile ( " .set push \n" " .set noreorder \n" " .set arch=octeon \n" " cache 5, 0(%[va]) \n" " dmfc0 %[taglo], $28, 2 \n" " dmfc0 %[taghi], $29, 2 \n" " dmfc0 %[datalo], $28, 3 \n" " dmfc0 %[datahi], $29, 3 \n" " .set pop \n" : [taglo] "=r" (taglo), [taghi] "=r" (taghi), [datalo] "=r" (datalo), [datahi] "=r" (datahi) : [va] "r" (va)); printf("%s: va=%08x " "(way=%02x"/* ", word=%01d" */"), " "taglo=%016"PRIx64" " "(R=%01"PRIx64", asid=%02"PRIx64", tag=%09"PRIx64", G=%01"PRIx64", valid=%01"PRIx64"), " "taghi=%016"PRIx64" " "(ptag=%08"PRIx64", valid=%01"PRIx64"), " "datahi=%02"PRIx64", datalo=%016"PRIx64"" "\n", __func__, (int)((taglo) & __BITS(48, 13)), /* (int)va */ (int)OCTEON_DCACHE_VA_WAY(va), /* (int)OCTEON_DCACHE_VA_WORD(va), */ taglo, OCTEON_DCACHE_TAGLO_R(taglo), OCTEON_DCACHE_TAGLO_ASID(taglo), OCTEON_DCACHE_TAGLO_TAG(taglo), OCTEON_DCACHE_TAGLO_G(taglo), OCTEON_DCACHE_TAGLO_VALID(taglo), taghi, OCTEON_DCACHE_TAGHI_PTAG(taghi), OCTEON_DCACHE_TAGHI_VALID(taghi), datahi, datalo); } #endif /* OCTEON_ICACHE_DEBUG */