/*
 * Author   : Kavita Bala 
 * Email    : kaybee@lcs.mit.edu
 * Comment  : Statistics gathering code.
 */


#include <mach/vm_param.h>
#include <mips/kb_stlb.h>
#include <mach/error.h>
#include <machine/machspl.h>
#include <strings.h>
#include <mips/mips_cpu.h>


extern int tlb_miss_bug  ;
extern int tlb_miss_double  ;	        /* double misses */
extern int tlb_miss_double_punt  ;
extern int tlb_miss_kernel_pt  ;	/* misses on kernel page table pages */
extern int tlb_miss_user_pt  ;	        /* misses on user page table pages */
extern int tlb_miss_kernel  ;	        /* misses on kernel pages */
extern int tlb_miss_user  ;		/* misses on user pages */
extern int kb_nested_l2   ;
extern int kb_nested_l1k  ;
extern int kb_nested_user_pt  ;



        

prefetch_stats_t kb_stats;

int kb_prefetch_trace_on, kb_prefetch_index;
int kb_sys_trace_index, kb_server_pc_index;
unsigned int kb_overhead_added;
int prefetch_intercept_enabled;

/* kb
 * The kernel call to collect statistics 
 */
kern_return_t kb_prefetch_call (command, argument, stats)
  int command, argument;
  prefetch_stats_t *stats;
{
  int s, kr, i, temp;


  s = splhigh();  

  kr = check_command_arguments(command, argument);

  if (kr == KERN_SUCCESS)
    switch (command) {
      
    case KB_PREFETCH_RESET:
      kr = kb_prefetch_reset (stats);
      break;

    case KB_PREFETCH_STATS:
      kr = kb_prefetch_stats (stats);
      break;
      
    case KB_PREFETCH_START:
      kr = kb_prefetch_start ();
      break;

    case KB_PREFETCH_STOP:
      kr = kb_prefetch_stop ();
      break;

    default:
      kr = KERN_INVALID_ARGUMENT;
      break;
    }
  
  splx(s);
  return(kr);
}



/*
 *------------------------------------------------------
 * Function:     check_command_arguments
 * Description:  Makes sure an argument makes sense before proceeding.  
 *                Returns an error code.
 *-------------------------------------------------------
 */

int check_command_arguments(command, argument)
  int command;
  int argument;
{
  if ((command < 0) || (command > MAX_COMMAND))
    return(KERN_INVALID_ARGUMENT);

  return(KERN_SUCCESS);
}



/*
 *-----------------------------------------------------------
 * Function:     kb_prefetch_reset
 * Description:  Reset all data structures
 *-----------------------------------------------------------
 */

int kb_prefetch_reset(stats)
  prefetch_stats_t *stats;
{
  int i, j, k, max;
  int kr;
  int                       old_intercept_state, old_trace_state;

  kr = KERN_SUCCESS;

  /* Make sure that simulator is disabled */
  old_intercept_state        = prefetch_intercept_enabled;
  old_trace_state            = kb_prefetch_trace_on;
  prefetch_intercept_enabled = FALSE;
  kb_prefetch_trace_on       = FALSE;

  kb_prefetch_index          = 0;
  kb_sys_trace_index         = 0;
  kb_server_pc_index         = 0;


  kb_already_there = 0;
  kb_prefetch_l2   = 0;
  kb_prefetch_l1k  = 0;
  kb_prefetch_kpt  = 0;


  kb_overhead_added = 0;



  *((int *) kb_stlb_tmp_space_ptr + KB_TOTAL_TRAPS_PTR) = 0;
  *((int *) kb_stlb_tmp_space_ptr + KB_STLB_SERVICED_PTR) = 0;


  tlb_miss_double = 0;
  kb_nested_l2 = 0;
  kb_nested_l1k = 0;
  kb_nested_user_pt = 0;
  tlb_miss_kernel_pt = 0;
  tlb_miss_user_pt = 0;
  tlb_miss_user = 0;
  tlb_miss_kernel = 0;
  
  prefetch_intercept_enabled = old_intercept_state;
  kb_prefetch_trace_on       = old_trace_state;

  return(kr);
}


/*
 *-----------------------------------------------------------
 * Function:     kb_prefetch_start
 * Description:  Start stats gathering
 *-----------------------------------------------------------
 */

int kb_prefetch_start()
{
  int kr;

  kr = KERN_SUCCESS;

  kb_prefetch_reset ();
  /* Make sure that simulator is enabled */
  prefetch_intercept_enabled = TRUE;
  kb_prefetch_trace_on       = TRUE;
  kb_prefetch_index          = 0;
  kb_sys_trace_index         = 0;
  kb_server_pc_index         = 0;

  return(kr);
}

/*
 *-----------------------------------------------------------
 * Function:     kb_prefetch_stop
 * Description:  Stop stats gathering
 *-----------------------------------------------------------
 */

int kb_prefetch_stop()
{
  int kr;

  kr = KERN_SUCCESS;

  prefetch_intercept_enabled = FALSE;
  kb_prefetch_trace_on       = FALSE;

  return(kr);

}


/*--------------------------------------------------------------------
Function:     kb_prefetch_stats
Description:  Extracts and copies out to user space a bunch of useful 
              statistics and internal state.
----------------------------------------------------------------------*/

int kb_prefetch_stats(stats)
  prefetch_stats_t *stats;
{
  int                       kr, old_intercept_state, old_trace_state, min, max;
  int                       i;
  extern prefetch_stats_t   kb_stats;
  unsigned int total, l2_time;
  unsigned int stlb_time;
  unsigned int other_time;
  int  stlb_serviced;

  kr = KERN_SUCCESS;

  /* Then disable simulator (if it wasn't already) */
  old_intercept_state = prefetch_intercept_enabled;
  old_trace_state     = kb_prefetch_trace_on;
  prefetch_intercept_enabled = FALSE;
  kb_prefetch_trace_on       = FALSE;


  total = *((int *) kb_stlb_tmp_space_ptr + KB_TOTAL_TRAPS_PTR);

  kb_stats.already_there           = kb_already_there;
  kb_stats.prefetch_l2             = kb_prefetch_l2;
  kb_stats.prefetch_l1k            = kb_prefetch_l1k;
  kb_stats.prefetch_kpt            = kb_prefetch_kpt;

  kb_stats.basic_user_pt           = tlb_miss_user_pt;
  kb_stats.basic_l2                = tlb_miss_double;
  kb_stats.basic_kpt               = tlb_miss_kernel_pt;
  kb_stats.basic_l1k               = tlb_miss_kernel;
  kb_stats.other                   = tlb_miss_user;
  kb_stats.tmr_min                 = min;


  stlb_serviced               = *((int *) kb_stlb_tmp_space_ptr +
                                       KB_STLB_SERVICED_PTR); 

  kb_stats.nested_l2               = kb_nested_l2;
  kb_stats.nested_l1k              = kb_nested_l1k;
  kb_stats.nested_user_pt          = kb_nested_user_pt;


  copyout (&stlb_serviced, &stats->stlb_serviced,
           sizeof(kb_stats.stlb_serviced));

  copyout (&kb_stats.already_there, &stats->already_there,
           sizeof(kb_stats.already_there));

  copyout (&kb_stats.nested_l2, &stats->nested_l2,
           sizeof(kb_stats.nested_l2));
  copyout (&kb_stats.nested_user_pt, &stats->nested_user_pt,
           sizeof(kb_stats.nested_user_pt));
  copyout (&kb_stats.nested_l1k, &stats->nested_l1k,
           sizeof(kb_stats.nested_l1k));

  copyout (&kb_stats.prefetch_l2, &stats->prefetch_l2,
           sizeof(kb_stats.prefetch_l2));
  copyout (&kb_stats.prefetch_l1k, &stats->prefetch_l1k,
           sizeof(kb_stats.prefetch_l1k));
  copyout (&kb_stats.prefetch_kpt, &stats->prefetch_kpt,
           sizeof(kb_stats.prefetch_kpt));

  copyout (&kb_stats.basic_user_pt, &stats->basic_user_pt,
           sizeof(kb_stats.basic_user_pt));
  copyout (&kb_stats.other, &stats->other,
           sizeof(kb_stats.other));
  copyout (&kb_stats.basic_l2, &stats->basic_l2,
           sizeof(kb_stats.basic_l2));
  copyout (&kb_stats.basic_l1k, &stats->basic_l1k,
           sizeof(kb_stats.basic_l1k));
  copyout (&kb_stats.basic_kpt, &stats->basic_kpt,
           sizeof(kb_stats.basic_kpt));

  copyout (&total, &stats->tlb_traps, sizeof(stats->tlb_traps)); 

  
  kb_already_there = 0;
  kb_prefetch_l2   = 0;
  kb_prefetch_l1k  = 0;
  kb_prefetch_kpt  = 0;

  kb_overhead_added = 0;

  *((int *) kb_stlb_tmp_space_ptr + KB_TOTAL_TRAPS_PTR) = 0;
  *((int *) kb_stlb_tmp_space_ptr + KB_STLB_SERVICED_PTR) = 0;


  kb_nested_l2 = 0;
  kb_nested_l1k = 0;
  kb_nested_user_pt = 0;

  tlb_miss_kernel_pt = 0;
  tlb_miss_user_pt = 0;
  tlb_miss_user = 0;
  tlb_miss_kernel = 0;
  tlb_miss_double = 0;

  /* Put back into old state */
  prefetch_intercept_enabled = old_intercept_state;
  kb_prefetch_trace_on       = old_trace_state;

  return(kr);
}













