/*
 * nasd_rpcc.c
 *
 * Read-cycle-counter ops for Pentium-family processors.
 *
 * Author: Marc Unangst
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_timer.h>
#ifdef KERNEL
#include <asm/delay.h>
#else /* KERNEL */
#include <time.h>
#include <unistd.h>
#endif /* KERNEL */

nasd_uint64 nasd_ctimer_ticks;

/* this is sort of a hack, but there is no way to ask the processor
   what its clock speed is. */
nasd_status_t
nasd_get_clock_speed(nasd_uint64 *ticksp)
{
  struct timeval stv, etv;
  nasd_uint32 spcc, epcc;
  nasd_uint32 elap, elap_cc;
  static nasd_uint64 result;

  if(!result) {
    nasd_fast_gettime(&stv);
    spcc = NASD_rpcc();
#ifdef KERNEL
    udelay(100000);
#else /* KERNEL */
    usleep(100000);		/* 100ms */
#endif /* KERNEL */
    epcc = NASD_rpcc();
    nasd_fast_gettime(&etv);

    elap = ((etv.tv_sec - stv.tv_sec) * 1000000) + (etv.tv_usec - stv.tv_usec);
    elap_cc = epcc - spcc;
    result = ((nasd_uint64)elap_cc * 1000000) / elap;
  }

  *ticksp = result;
  return NASD_SUCCESS;
}

/* Read the Pentium timestamp counter and return the low 32 bits. */
nasd_uint32
NASD_rpcc(void)
{
  nasd_uint32 low;
  nasd_uint32 high;

  __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); /* RDTSC */
  return low;
}

/* Version of NASD_rpcc that returns all 64 bits of the TSC value. */
void
NASD_rpcc_int64(nasd_uint32 *high, nasd_uint32 *low)
{
  __asm__(".byte 0x0f,0x31" :"=a" (*low), "=d" (*high)); /* RDTSC */
  return;
}
