00001 /* 00002 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License as 00006 * published by the Free Software Foundation; either version 2 of the 00007 * License, or any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, but 00010 * WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 FILE_LICENCE ( GPL2_OR_LATER ); 00020 00021 /** @file 00022 * 00023 * RDTSC timer 00024 * 00025 */ 00026 00027 #include <assert.h> 00028 #include <gpxe/timer.h> 00029 #include <gpxe/timer2.h> 00030 00031 /** 00032 * Number of TSC ticks per microsecond 00033 * 00034 * This is calibrated on the first use of the timer. 00035 */ 00036 static unsigned long rdtsc_ticks_per_usec; 00037 00038 /** 00039 * Delay for a fixed number of microseconds 00040 * 00041 * @v usecs Number of microseconds for which to delay 00042 */ 00043 static void rdtsc_udelay ( unsigned long usecs ) { 00044 unsigned long start; 00045 unsigned long elapsed; 00046 00047 /* Sanity guard, since we may divide by this */ 00048 if ( ! usecs ) 00049 usecs = 1; 00050 00051 start = currticks(); 00052 if ( rdtsc_ticks_per_usec ) { 00053 /* Already calibrated; busy-wait until done */ 00054 do { 00055 elapsed = ( currticks() - start ); 00056 } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) ); 00057 } else { 00058 /* Not yet calibrated; use timer2 and calibrate 00059 * based on result. 00060 */ 00061 timer2_udelay ( usecs ); 00062 elapsed = ( currticks() - start ); 00063 rdtsc_ticks_per_usec = ( elapsed / usecs ); 00064 DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs " 00065 "(%ld MHz)\n", elapsed, usecs, 00066 ( rdtsc_ticks_per_usec << TSC_SHIFT ) ); 00067 } 00068 } 00069 00070 /** 00071 * Get number of ticks per second 00072 * 00073 * @ret ticks_per_sec Number of ticks per second 00074 */ 00075 static unsigned long rdtsc_ticks_per_sec ( void ) { 00076 00077 /* Calibrate timer, if not already done */ 00078 if ( ! rdtsc_ticks_per_usec ) 00079 udelay ( 1 ); 00080 00081 /* Sanity check */ 00082 assert ( rdtsc_ticks_per_usec != 0 ); 00083 00084 return ( rdtsc_ticks_per_usec * 1000 * 1000 ); 00085 } 00086 00087 PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay ); 00088 PROVIDE_TIMER_INLINE ( rdtsc, currticks ); 00089 PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
1.5.7.1