aboutsummaryrefslogtreecommitdiffstats
path: root/udelay.c
diff options
context:
space:
mode:
authorreinelt <reinelt@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>2001-03-12 13:44:58 +0000
committerreinelt <reinelt@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>2001-03-12 13:44:58 +0000
commit064f4880a2349039356945b3a9f2081f035c32c1 (patch)
treec028a9c468ef0c5d0389572fc8363c51e854e9c5 /udelay.c
parent62fdec1130f15faf0ed0562f79525f64f7f6e9bd (diff)
downloadlcd4linux-064f4880a2349039356945b3a9f2081f035c32c1.tar.gz
[lcd4linux @ 2001-03-12 13:44:58 by reinelt]
new udelay() using Time Stamp Counters git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@112 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
Diffstat (limited to 'udelay.c')
-rw-r--r--udelay.c140
1 files changed, 127 insertions, 13 deletions
diff --git a/udelay.c b/udelay.c
index e658436..e9a3231 100644
--- a/udelay.c
+++ b/udelay.c
@@ -1,4 +1,4 @@
-/* $Id: udelay.c,v 1.4 2001/03/12 12:39:36 reinelt Exp $
+/* $Id: udelay.c,v 1.5 2001/03/12 13:44:58 reinelt Exp $
*
* short delays
*
@@ -20,6 +20,10 @@
*
*
* $Log: udelay.c,v $
+ * Revision 1.5 2001/03/12 13:44:58 reinelt
+ *
+ * new udelay() using Time Stamp Counters
+ *
* Revision 1.4 2001/03/12 12:39:36 reinelt
*
* reworked autoconf a lot: drivers may be excluded, #define's went to config.h
@@ -52,23 +56,42 @@
* This function does busy-waiting! so use only for delays smaller
* than 10 msec
*
- * void udelay_calibrate (void)
+ * void udelay_calibrate (void) (if USE_OLD_UDELAY is defined)
* does a binary approximation for 'loops_per_usec'
* should be called several times on an otherwise idle machine
* the maximum value should be used
*
+ * void udelay_init (void)
+ * selects delay method (gettimeofday() ord rdtsc() according
+ * to processor features
+ *
*/
+#include "config.h"
#include <stdlib.h>
#include <stdio.h>
+
#ifdef USE_OLD_UDELAY
+
#include <time.h>
+
#else
-#include <sys/time.h>
+
+#include <math.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#ifdef HAVE_ASM_MSR_H
+#include <asm/msr.h>
+#endif
+
#endif
+
+#include "debug.h"
#include "udelay.h"
#ifdef USE_OLD_UDELAY
@@ -119,20 +142,111 @@ void udelay_calibrate (void)
#else
-void udelay (unsigned long usec)
+static unsigned int ticks_per_usec=0;
+
+static void getCPUinfo (int *hasTSC, double *MHz)
{
- struct timeval now, end;
+ int fd;
+ char buffer[4096], *p;
- gettimeofday (&end, NULL);
- end.tv_usec+=usec;
- while (end.tv_usec>1000000) {
- end.tv_usec-=1000000;
- end.tv_sec++;
+ *hasTSC=0;
+ *MHz=-1;
+
+ fd=open("/proc/cpuinfo", O_RDONLY);
+ if (fd==-1) {
+ error ("open(/proc/cpuinfo) failed: %s", strerror(errno));
+ return;
+ }
+ if (read (fd, &buffer, sizeof(buffer)-1)==-1) {
+ error ("read(/proc/cpuinfo) failed: %s", strerror(errno));
+ close (fd);
+ return;
+ }
+ close (fd);
+
+ p=strstr(buffer, "flags");
+ if (p==NULL) {
+ debug ("/proc/cpuinfo has no 'flags' line");
+ } else {
+ p=strstr(p, "tsc");
+ if (p==NULL) {
+ debug ("CPU does not support Time Stamp Counter");
+ } else {
+ debug ("CPU supports Time Stamp Counter");
+ *hasTSC=1;
+ }
}
- do {
- gettimeofday(&now, NULL);
- } while (now.tv_sec==end.tv_sec?now.tv_usec<end.tv_usec:now.tv_sec<end.tv_sec);
+ p=strstr(buffer, "cpu MHz");
+ if (p==NULL) {
+ debug ("/proc/cpuinfo has no 'cpu MHz' line");
+ } else {
+ if (sscanf(p+7, " : %lf", MHz)!=1) {
+ error ("parse(/proc/cpuinfo) failed: unknown 'cpu MHz' format");
+ *MHz=-1;
+ } else {
+ debug ("CPU runs at %f MHz", *MHz);
+ }
+ }
+
+}
+
+
+void udelay_init (void)
+{
+
+#ifdef HAVE_ASM_MSR_H
+
+ int tsc;
+ double mhz;
+
+ getCPUinfo (&tsc, &mhz);
+
+ if (tsc && mhz>0.0) {
+ ticks_per_usec=ceil(mhz);
+ debug ("using TSC delay loop, %u ticks per microsecond", ticks_per_usec);
+ } else {
+ ticks_per_usec=0;
+ debug ("using gettimeofday() delay loop");
+ }
+
+#else
+
+ debug ("lcd4linux has been compiled without asm/msr.h");
+ debug ("using gettimeofday() delay loop");
+
+#endif
+
+}
+
+void udelay (unsigned long usec)
+{
+ if (ticks_per_usec) {
+
+ unsigned int t1, t2;
+
+ usec*=ticks_per_usec;
+
+ rdtscl(t1);
+ do {
+ rdtscl(t2);
+ } while ((t2-t1)<usec);
+
+ } else {
+
+ struct timeval now, end;
+
+ gettimeofday (&end, NULL);
+ end.tv_usec+=usec;
+ while (end.tv_usec>1000000) {
+ end.tv_usec-=1000000;
+ end.tv_sec++;
+ }
+
+ do {
+ gettimeofday(&now, NULL);
+ } while (now.tv_sec==end.tv_sec?now.tv_usec<end.tv_usec:now.tv_sec<end.tv_sec);
+ }
}
#endif