/*
* operations on all memory data or unified caches, a no-op cache,
* and an l1-only cache ops cache.
* i-caches are not handled here.
*
* there are only three cache operations that we care about:
* force cache contents to memory (before dma out or shutdown),
* ignore cache contents in favour of memory (initialisation, after dma in),
* both (update page tables and force cpu to read new contents).
*/

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

static Cacheimpl allcaches, nullcaches, l1caches;

void
cachesinfo(Memcache *cp)
{
       memset(cp, 0, sizeof *cp);
       cp->setsways = Cara | Cawa | Cawt | Cawb;
       cp->l1ip = 3<<14;                               /* PIPT */
       cp->log2linelen = log2(CACHELINESZ);
}

void
allcacheson(void)
{
       l2pl310init();
       allcache = &allcaches;
       nocache = &nullcaches;
       l1cache = &l1caches;
}

void
cachesoff(void)
{
       l2cache->off();
}

void
cachesinvse(void *va, int bytes)
{
       int s;

       s = splhi();
       l2cache->invse(va, bytes);
       cachedinvse(va, bytes);
       splx(s);
}

void
cacheswbse(void *va, int bytes)
{
       int s;

       s = splhi();
       cachedwbse(va, bytes);
       l2cache->wbse(va, bytes);
       splx(s);
}

void
cacheswbinvse(void *va, int bytes)
{
       int s;

       s = splhi();
       cachedwbse(va, bytes);
       l2cache->wbinvse(va, bytes);
       cachedwbinvse(va, bytes);
       splx(s);
}


void
cachesinv(void)
{
       int s;

       s = splhi();
       l2cache->inv();
       cachedinv();
       splx(s);
}

void
cacheswb(void)
{
       int s;

       s = splhi();
       cachedwb();
       l2cache->wb();
       splx(s);
}

void
cacheswbinv(void)
{
       int s;

       s = splhi();
       cachedwb();
       l2cache->wbinv();
       cachedwbinv();
       splx(s);
}

static Cacheimpl allcaches = {
       .info   = cachesinfo,
       .on     = allcacheson,
       .off    = cachesoff,

       .inv    = cachesinv,
       .wb     = cacheswb,
       .wbinv  = cacheswbinv,

       .invse  = cachesinvse,
       .wbse   = cacheswbse,
       .wbinvse= cacheswbinvse,
};


/*
* null cache ops
*/

void
nullinfo(Memcache *cp)
{
       memset(cp, 0, sizeof *cp);
       cp->log2linelen = 2;
}

void
nullon(void)
{
       nocache = &nullcaches;
}

void
nullop(void)
{
}

void
nullse(void *, int)
{
}

static Cacheimpl nullcaches = {
       .info   = nullinfo,
       .on     = nullon,
       .off    = nullop,

       .inv    = nullop,
       .wb     = nullop,
       .wbinv  = nullop,

       .invse  = nullse,
       .wbse   = nullse,
       .wbinvse= nullse,
};

/*
* l1-only ops
*/

void
l1cachesinfo(Memcache *)
{
}

void
l1cacheson(void)
{
       l1cache = &l1caches;
}

static Cacheimpl l1caches = {
       .info   = l1cachesinfo,
       .on     = l1cacheson,
       .off    = nullop,

       .inv    = cachedinv,
       .wb     = cachedwb,
       .wbinv  = cachedwbinv,

       .invse  = cachedinvse,
       .wbse   = cachedwbse,
       .wbinvse= cachedwbinvse,
};