Commit 4bebb908 authored by Alessandro Rubini's avatar Alessandro Rubini

userspace/libwr: change the udelay function

To delay for less than 1ms (was: 10ms) we must busy-loop, because the
kernel is jiffy-based. No way out of it.

The implementation, however, was based on gettimeofday(), which means
we couldn't really strace the hal process, as it appeared to
only call gettimeofday all the time.

This code uses a local software loop, after a calibration step of
around 20ms (depends on CPU speed). Moreover, by calling usleep() for
longer-than-1ms delays it doesn't use 100% cpu power during the
initial led blinking.

Now strace on the process shows what it really is doing (besides
user-spac-only i2c accesses).
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 96290994
......@@ -6,6 +6,7 @@
#define atoidef(str,def) (str)?atoi(str):def
void shw_udelay_init(void);
void shw_udelay(uint32_t microseconds);
uint64_t shw_get_tics();
......
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <libwr/util.h>
void shw_udelay(uint32_t microseconds)
static int loops_per_msec = -1;
/* Calculate how many loops per millisecond we make in this CPU */
void shw_udelay_init(void)
{
uint64_t t_start, t_cur;
struct timeval tv;
volatile int i;
int j, cur, min = 0;
struct timeval tv1, tv2;
for (j = 0; j < 10; j++) {
gettimeofday(&tv1, NULL);
for (i = 0; i < 100*1000; i++)
;
gettimeofday(&tv2, NULL);
cur = (tv2.tv_sec - tv1.tv_sec) * 1000 * 1000
+ tv2.tv_usec - tv1.tv_usec;
/* keep minimum time, assuming we were scheduled-off less */
if (!min || cur < min)
min = cur;
}
loops_per_msec = i * 1000 / min;
gettimeofday(&tv, NULL);
t_start = (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
if (0)
printf("loops per msec %i\n", loops_per_msec);
/*
* I get 39400 more or less; it makes sense at 197 bogomips.
* The loop is 6 instructions with 3 (cached) memory accesses
* and 1 jump. 197/39.4 = 5.0 .
*/
}
/*
* This function is needed to for slow delays to overcome the jiffy-grained
* delays that the kernel offers. We can't wait for 1ms when needing 4us.
*/
void shw_udelay(uint32_t microseconds)
{
volatile int i;
do {
gettimeofday(&tv, NULL);
t_cur =
(uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
if (loops_per_msec < 0)
shw_udelay_init();
} while (t_cur <= t_start + (uint64_t) microseconds);
if (microseconds > 1000) {
usleep(microseconds);
return;
}
for (i = 0; i < loops_per_msec * microseconds / 1000; i++)
;
}
uint64_t shw_get_tics()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment