root/sys/arch/mips/mips/cache_octeon.c
/*      $NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $  */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cache_octeon.c,v 1.4 2020/06/06 14:30:44 simonb Exp $");

#include <sys/param.h>
#include <sys/systm.h>

#include <mips/locore.h>
#include <mips/cache.h>
#include <mips/cache_octeon.h>

#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 */