/**
 * \file   reset_inval.c
 * \date   December 14, 2014
 * \author Cesar Fuguet
 */

#include <reset_inval.h>
#include <io.h>
#include <defs.h>

#ifndef SEG_MMC_BASE
#   error "SEG_MMC_BASE constant must be defined in the hard_config.h file"
#endif

static int* const mcc_address = (int* const)SEG_MMC_BASE;

enum memc_registers
{
    MCC_LOCK      = 0,
    MCC_ADDR_LO   = 1,
    MCC_ADDR_HI   = 2,
    MCC_LENGTH    = 3,
    MCC_CMD       = 4
};

enum memc_operations
{
    MCC_CMD_NOP   = 0,
    MCC_CMD_INVAL = 1,
    MCC_CMD_SYNC  = 2
};

/**
 * \brief Invalidate all data cache lines corresponding to a memory buffer
 *        (identified by an address and a size) in L2 cache.
 */
void reset_mcc_invalidate (void* const buffer, size_t size)
{
    // get the hard lock assuring exclusive access to MEMC
    while (ioread32(&mcc_address[MCC_LOCK]));

    // write invalidate paremeters on the memory cache this preloader
    // use only the cluster 0 and then the HI bits are not used

    iowrite32(&mcc_address[MCC_ADDR_LO], (unsigned int) buffer);
    iowrite32(&mcc_address[MCC_ADDR_HI], (unsigned int) 0);
    iowrite32(&mcc_address[MCC_LENGTH] , (unsigned int) size);
    iowrite32(&mcc_address[MCC_CMD]    , (unsigned int) MCC_CMD_INVAL);

    // release the lock protecting MEMC
    iowrite32(&mcc_address[MCC_LOCK], (unsigned int) 0);
}

/**
 * \brief Invalidate all data cache lines corresponding to a memory buffer
 *        (identified by an address and a size) in L1 cache and L2 cache.
 */
void reset_buf_invalidate (void* const buffer, size_t size, int inval_memc)
{
    unsigned int i;

    /*
     * iterate on cache lines containing target buffer to invalidate them
     */
    for (i = 0; i <= size; i += CACHE_LINE_SIZE)
    {
        asm volatile(
            " cache %0, %1"
            : /* no outputs */
            : "i" (0x11), "R" (*((char*)buffer + i))
            : "memory"
            );
    }

    if (inval_memc) reset_mcc_invalidate(buffer, size);
}

/*
 * vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab
 */
