#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cache_r5k.c,v 1.21 2020/06/14 15:12:56 tsutsui Exp $");
#include <sys/param.h>
#include <mips/cache.h>
#include <mips/cache_r4k.h>
#include <mips/cache_r5k.h>
#include <mips/locore.h>
#define round_line16(x) round_line(x, 16)
#define trunc_line16(x) trunc_line(x, 16)
#define round_line32(x) round_line(x, 32)
#define trunc_line32(x) trunc_line(x, 32)
#define round_line(x,n) (((x) + (register_t)(n) - 1) & -(register_t)(n))
#define trunc_line(x,n) ((x) & -(register_t)(n))
__asm(".set mips3");
void
r5k_picache_sync_all(void)
{
struct mips_cache_info * const mci = &mips_cache_info;
mips_intern_dcache_sync_all();
__asm volatile("sync");
mips_intern_icache_sync_range_index(MIPS_KSEG0_START,
mci->mci_picache_size);
}
void
r5k_picache_sync_range(register_t va, vsize_t size)
{
mips_intern_dcache_sync_range(va, size);
mips_intern_icache_sync_range(va, size);
}
void
r5k_picache_sync_range_index(vaddr_t va, vsize_t size)
{
struct mips_cache_info * const mci = &mips_cache_info;
const size_t ways = mci->mci_picache_ways;
const size_t line_size = mci->mci_picache_line_size;
const size_t way_size = mci->mci_picache_way_size;
const size_t way_mask = way_size - 1;
vaddr_t eva;
va = MIPS_PHYS_TO_KSEG0(va & way_mask);
eva = round_line(va + size, line_size);
va = trunc_line(va, line_size);
size = eva - va;
if (size >= way_size) {
r5k_picache_sync_all();
return;
}
for (size_t way = 0; way < ways; way++) {
mips_intern_dcache_sync_range_index(va, size);
mips_intern_icache_sync_range_index(va, size);
va += way_size;
eva += way_size;
}
}
void
r5k_pdcache_wbinv_all(void)
{
struct mips_cache_info * const mci = &mips_cache_info;
mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START,
mci->mci_pdcache_size);
}
void
r5k_pdcache_wbinv_range_index(vaddr_t va, vsize_t size)
{
struct mips_cache_info * const mci = &mips_cache_info;
const size_t ways = mci->mci_pdcache_ways;
const size_t line_size = mci->mci_pdcache_line_size;
const vaddr_t way_size = mci->mci_pdcache_way_size;
const vaddr_t way_mask = way_size - 1;
vaddr_t eva;
va = MIPS_PHYS_TO_KSEG0(va & way_mask);
eva = round_line(va + size, line_size);
va = trunc_line(va, line_size);
size = eva - va;
if (size >= way_size) {
mips_intern_pdcache_wbinv_range_index(MIPS_KSEG0_START,
mci->mci_pdcache_size);
return;
}
for (size_t way = 0; way < ways; way++) {
mips_intern_pdcache_wbinv_range_index(va, size);
va += way_size;
eva += way_size;
}
}
void
r4600v1_pdcache_wbinv_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
if (eva - va >= mips_cache_info.mci_pdcache_size) {
r5k_pdcache_wbinv_all();
return;
}
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
while (va < eva) {
__asm volatile("nop; nop; nop; nop");
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
va += 32;
}
mips_cp0_status_write(ostatus);
}
void
r4600v2_pdcache_wbinv_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
for (; (eva - va) >= (32 * 32); va += (32 * 32)) {
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
}
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
for (; va < eva; va += 32) {
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV);
}
mips_cp0_status_write(ostatus);
}
void
vr4131v1_pdcache_wbinv_range_16(register_t va, vsize_t size)
{
register_t eva = round_line16(va + size);
va = trunc_line16(va);
for (; (eva - va) >= (32 * 16); va += (32 * 16)) {
cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
}
for (; va < eva; va += 16) {
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
}
}
void
r4600v1_pdcache_inv_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
for (; va < eva; va += 32) {
__asm volatile("nop; nop; nop; nop;");
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
}
mips_cp0_status_write(ostatus);
}
void
r4600v2_pdcache_inv_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
for (; (eva - va) >= (32 * 32); va += (32 * 32)) {
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
}
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
for (; va < eva; va += 32) {
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV);
}
mips_cp0_status_write(ostatus);
}
void
r4600v1_pdcache_wb_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
for (; va < eva; va += 32) {
__asm volatile("nop; nop; nop; nop;");
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
}
mips_cp0_status_write(ostatus);
}
void
r4600v2_pdcache_wb_range_32(register_t va, vsize_t size)
{
const register_t eva = round_line32(va + size);
va = trunc_line32(va);
const uint32_t ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
for (; (eva - va) >= (32 * 32); va += (32 * 32)) {
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
}
(void) *(volatile int *)MIPS_PHYS_TO_KSEG1(0);
for (; va < eva; va += 32) {
cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB);
}
mips_cp0_status_write(ostatus);
}
__asm(".set mips3");
void
r5k_sdcache_wbinv_all(void)
{
r5k_sdcache_wbinv_range(MIPS_PHYS_TO_KSEG0(0), mips_cache_info.mci_sdcache_size);
}
void
r5k_sdcache_wbinv_range_index(vaddr_t va, vsize_t size)
{
va = MIPS_PHYS_TO_KSEG0(va & (mips_cache_info.mci_sdcache_size - 1));
r5k_sdcache_wbinv_range((intptr_t)va, size);
}
void
r5k_sdcache_wbinv_range(register_t va, vsize_t size)
{
uint32_t ostatus, taglo;
register_t eva = mips_r5k_round_page(va + size);
va = mips_r5k_trunc_page(va);
ostatus = mips_cp0_status_read();
mips_cp0_status_write(ostatus & ~MIPS_SR_INT_IE);
__asm volatile("mfc0 %0, $28" : "=r"(taglo));
__asm volatile("mtc0 $0, $28");
for (; va < eva; va += R5K_SC_PAGESIZE) {
cache_op_r4k_line(va, CACHEOP_R5K_Page_Invalidate_S);
}
mips_cp0_status_write(ostatus);
__asm volatile("mtc0 %0, $28; nop" :: "r"(taglo));
}