#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/mipsregs.h>

/*------------------------------------------------------------------------------------------*\
 *  WatchLo Register
 *
 *  Bits 31:3   VAdre
 *  Bit   2     1: enabled for instruction fetch
 *  Bit   1     1: enabled for load instruction (data)
 *  Bit   0     1: enabled for store instaruction (data)
 *
 *  WatchHi Register
 *
 *  Bit  31:    1: a nother pair of WatchLo/WatchHi register avail
 *  Bit  30     1: any adress that matches will cause an exception
 *  Bits 23:16  ASID value is requeired to match that in the Hi register if the G (30) bit is zero 
 *              in the WatchHi register
 *  Bits 15:12  must be zero
 *  Bits 11:3   Mask: bit mash that qualifies the WatchLo Register 
\*------------------------------------------------------------------------------------------*/

union _watch_lo_register {
    struct __watch_lo_register {
        unsigned int enable_data_write  : 1;
        unsigned int enable_data_read   : 1;
        unsigned int enable_instruction : 1;
        unsigned int double_word_addr   : 29;
    } Bits;
    unsigned int Register;
};

union _watch_hi_register {
    struct __watch_hi_register {
        unsigned int rev2_write_match : 1;
        unsigned int rev2_read_match  : 1;
        unsigned int rev2_instruction_match : 1;
        unsigned int mask : 9:
        unsigned int reserved1 : 4;
        unsigned int asid: 8;
        unsigned int reserved2 : 6;
        unsigned int global : 1;
        unsigned int one_more_register : 1;
    } Bits;
    unsigned int Register;
};

static unsigned int ohio_max_watchpoint_registers = 0;

/*------------------------------------------------------------------------------------------*\
\*------------------------------------------------------------------------------------------*/
void ohio_setup_watchpoint(unsigned int index, void *addr, unsigned int instruction, unsigned int data_read, unsigned int ) {
    union _watch_lo_register lo;
    union _watch_hi_register hi;

    if(addr == (void *)-1) {
        hi.Register = __read_32bit_c0_register($19, index);
        hi.Bits.mask &= ~(1 << index);
        __write_32bit_c0_register($19, index, hi.Register);
        return;
    }
    lo.Bits.addr = addr >> 3;
    lo.Bits.enable_data_write  = data_write ? 1 : 0;
    lo.Bits.enable_data_read   = data_read ? 1 : 0;
    lo.Bits.enable_instruction = instruction ? 1 : 0;

    hi.Register = __read_32bit_c0_register($19, index);
    if(hi.Bits.mask & (1 << index)) {
        printk("ERROR: watchdog register %u in use\n", index);
        return;
    }

    __write_32bit_c0_register($18, index, lo.Register);
    hi.Bits.mask |= (1 << index);
    __write_32bit_c0_register($19, index, hi.Register);
    return;
}



