summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2005-10-05 02:39:35 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2005-10-05 02:39:35 +0000
commitfb573a71f1fdec968446b1bb39856fa1ac958e24 (patch)
tree4a8a7757c60113417af3cb80cf31e7caefa84ee8 /c
parent2005-09-12 Thomas Doerfler <Thomas.Doerfler@imd-systems.de> (diff)
downloadrtems-fb573a71f1fdec968446b1bb39856fa1ac958e24.tar.bz2
2005-08-23 Karel Gardas <kgardas@objectsecurity.com>>
* timer/timer.c: Enhance to use either interupt-based timer functions on older CPUs or to use TSC-based timer functions on more recent (Pentium and above) CPUs. The decision is made in Timer_initialize function when it is called for the first time based on a result obtained from cpuid instruction during the BSP initialization phase. During the first call, there are also late bindings to the implementation functions initialized to appropriate values.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/i386/pc386/ChangeLog11
-rw-r--r--c/src/lib/libbsp/i386/pc386/timer/timer.c168
2 files changed, 112 insertions, 67 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/ChangeLog b/c/src/lib/libbsp/i386/pc386/ChangeLog
index e34bcfb605..3d2c17dedc 100644
--- a/c/src/lib/libbsp/i386/pc386/ChangeLog
+++ b/c/src/lib/libbsp/i386/pc386/ChangeLog
@@ -1,3 +1,14 @@
+2005-08-23 Karel Gardas <kgardas@objectsecurity.com>>
+
+ * timer/timer.c: Enhance to use either interupt-based timer
+ functions on older CPUs or to use TSC-based timer functions on
+ more recent (Pentium and above) CPUs. The decision is made in
+ Timer_initialize function when it is called for the first time
+ based on a result obtained from cpuid instruction during the BSP
+ initialization phase. During the first call, there are also late
+ bindings to the implementation functions initialized to
+ appropriate values.
+
2005-09-29 Thomas Doerfler <Thomas.Doerfler@imd-systems.de>
PR649/filesystem
diff --git a/c/src/lib/libbsp/i386/pc386/timer/timer.c b/c/src/lib/libbsp/i386/pc386/timer/timer.c
index 0e0f1d9003..b9a4d0549d 100644
--- a/c/src/lib/libbsp/i386/pc386/timer/timer.c
+++ b/c/src/lib/libbsp/i386/pc386/timer/timer.c
@@ -38,7 +38,6 @@
| $Id$
+--------------------------------------------------------------------------*/
-
#include <stdlib.h>
#include <bsp.h>
@@ -51,7 +50,7 @@
#define LEAST_VALID 1 /* Don't trust a value lower than this. */
#define SLOW_DOWN_IO 0x80 /* io which does nothing */
-#define TWO_MS (rtems_unsigned32)(2000) /* TWO_MS = 2000us (sic!) */
+#define TWO_MS (uint32_t)(2000) /* TWO_MS = 2000us (sic!) */
#define MSK_NULL_COUNT 0x40 /* bit counter available for reading */
@@ -59,27 +58,36 @@
/*-------------------------------------------------------------------------+
| Global Variables
+--------------------------------------------------------------------------*/
-volatile rtems_unsigned32 Ttimer_val;
+volatile uint32_t Ttimer_val;
rtems_boolean Timer_driver_Find_average_overhead = TRUE;
volatile unsigned int fastLoop1ms, slowLoop1ms;
+void (*Timer_initialize_function)(void) = 0;
+uint32_t (*Read_timer_function)(void) = 0;
+void (*Timer_exit_function)(void) = 0;
/*-------------------------------------------------------------------------+
| External Prototypes
+--------------------------------------------------------------------------*/
extern void timerisr(void);
/* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */
+extern int x86_capability;
+
+/*
+ * forward declarations
+ */
+
+void Timer_exit();
/*-------------------------------------------------------------------------+
| Pentium optimized timer handling.
+--------------------------------------------------------------------------*/
-#if defined(pentium)
/*-------------------------------------------------------------------------+
| Function: rdtsc
| Description: Read the value of PENTIUM on-chip cycle counter.
| Global Variables: None.
| Arguments: None.
-| Returns: Value of PENTIUM on-chip cycle counter.
+| Returns: Value of PENTIUM on-chip cycle counter.
+--------------------------------------------------------------------------*/
static inline unsigned long long
rdtsc(void)
@@ -90,30 +98,28 @@ rdtsc(void)
return result;
} /* rdtsc */
-
/*-------------------------------------------------------------------------+
| Function: Timer_exit
| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
| not really necessary, since there will be a reset at exit.
| Global Variables: None.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
-Timer_exit(void)
+tsc_timer_exit(void)
{
-} /* Timer_exit */
-
+} /* tsc_timer_exit */
/*-------------------------------------------------------------------------+
| Function: Timer_initialize
| Description: Timer initialization routine.
| Global Variables: Ttimer_val.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
-Timer_initialize(void)
+tsc_timer_initialize(void)
{
static rtems_boolean First = TRUE;
@@ -124,22 +130,21 @@ Timer_initialize(void)
atexit(Timer_exit); /* Try not to hose the system at exit. */
}
Ttimer_val = rdtsc(); /* read starting time */
-} /* Timer_initialize */
-
+} /* tsc_timer_initialize */
/*-------------------------------------------------------------------------+
| Function: Read_timer
| Description: Read hardware timer value.
| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
-rtems_unsigned32
-Read_timer(void)
+uint32_t
+tsc_read_timer(void)
{
- register rtems_unsigned32 total;
+ register uint32_t total;
- total = (rtems_unsigned32)(rdtsc() - Ttimer_val);
+ total = (uint32_t)(rdtsc() - Ttimer_val);
if (Timer_driver_Find_average_overhead)
return total;
@@ -147,23 +152,20 @@ Read_timer(void)
return 0; /* below timer resolution */
else
return (total - AVG_OVERHEAD);
-} /* Read_timer */
-
-#else /* pentium */
+} /* tsc_read_timer */
/*-------------------------------------------------------------------------+
| Non-Pentium timer handling.
+--------------------------------------------------------------------------*/
#define US_PER_ISR 250 /* Number of micro-seconds per timer interruption */
-
/*-------------------------------------------------------------------------+
| Function: Timer_exit
| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is
| not really necessary, since there will be a reset at exit.
| Global Variables: None.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
static void
timerOff(const rtems_raw_irq_connect_data* used)
@@ -178,8 +180,7 @@ timerOff(const rtems_raw_irq_connect_data* used)
outport_byte(TIMER_CNTR0, 0);
} /* Timer_exit */
-
-static void
+static void
timerOn(const rtems_raw_irq_connect_data* used)
{
/* load timer for US_PER_ISR microsecond period */
@@ -192,10 +193,11 @@ timerOn(const rtems_raw_irq_connect_data* used)
BSP_irq_enable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
}
-static int
+static int
timerIsOn(const rtems_raw_irq_connect_data *used)
{
- return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);}
+ return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);
+}
static rtems_raw_irq_connect_data timer_raw_irq_data = {
BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
@@ -211,10 +213,10 @@ static rtems_raw_irq_connect_data timer_raw_irq_data = {
| not really necessary, since there will be a reset at exit.
| Global Variables: None.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
-Timer_exit(void)
+i386_timer_exit(void)
{
i386_delete_idt_entry (&timer_raw_irq_data);
} /* Timer_exit */
@@ -224,10 +226,10 @@ Timer_exit(void)
| Description: Timer initialization routine.
| Global Variables: Ttimer_val.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
-Timer_initialize(void)
+i386_timer_initialize(void)
{
static rtems_boolean First = TRUE;
@@ -248,19 +250,18 @@ Timer_initialize(void)
Ttimer_val = 0;
} /* Timer_initialize */
-
/*-------------------------------------------------------------------------+
| Function: Read_timer
| Description: Read hardware timer value.
| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
-rtems_unsigned32
-Read_timer(void)
+uint32_t
+i386_read_timer(void)
{
- register rtems_unsigned32 total, clicks;
- register rtems_unsigned8 lsb, msb;
+ register uint32_t total, clicks;
+ register uint8_t lsb, msb;
outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
inport_byte(TIMER_CNTR0, lsb);
@@ -276,28 +277,68 @@ Read_timer(void)
return (total - AVG_OVERHEAD);
}
-#endif /* pentium */
+/*
+ * General timer functions using either TSC-based implementation
+ * or interrupt-based implementation
+ */
+
+void
+Timer_initialize(void)
+{
+ static rtems_boolean First = TRUE;
+
+ if (First) {
+ if (x86_capability & (1 << 4) ) {
+#if defined(DEBUG)
+ printk("TSC: timer initialization\n");
+#endif
+ Timer_initialize_function = &tsc_timer_initialize;
+ Read_timer_function = &tsc_read_timer;
+ Timer_exit_function = &tsc_timer_exit;
+ }
+ else {
+#if defined(DEBUG)
+ printk("ISR: timer initialization\n");
+#endif
+ Timer_initialize_function = &i386_timer_initialize;
+ Read_timer_function = &i386_read_timer;
+ Timer_exit_function = &i386_timer_exit;
+ }
+ First = FALSE;
+ }
+ (*Timer_initialize_function)();
+}
+
+uint32_t
+Read_timer()
+{
+ return (*Read_timer_function)();
+}
+void
+Timer_exit()
+{
+ return (*Timer_exit_function)();
+}
/*-------------------------------------------------------------------------+
| Function: Empty_function
| Description: Empty function used in time tests.
| Global Variables: None.
| Arguments: None.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
rtems_status_code Empty_function(void)
{
return RTEMS_SUCCESSFUL;
} /* Empty function */
-
/*-------------------------------------------------------------------------+
| Function: Set_find_average_overhead
| Description: Set internal Timer_driver_Find_average_overhead flag value.
| Global Variables: Timer_driver_Find_average_overhead.
| Arguments: find_flag - new value of the flag.
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
Set_find_average_overhead(rtems_boolean find_flag)
@@ -319,11 +360,10 @@ void loadTimerValue( unsigned short loadedValue )
outport_byte(TIMER_CNTR0, (loadedValue >> 8) & 0xff);
}
-
/*-------------------------------------------------------------------------+
-| Description: Reads the current value of the timer, and converts the
-| number of ticks to micro-seconds.
-| Returns: number of clock bits elapsed since last load.
+| Description: Reads the current value of the timer, and converts the
+| number of ticks to micro-seconds.
+| Returns: number of clock bits elapsed since last load.
+--------------------------------------------------------------------------*/
unsigned int readTimer0()
{
@@ -338,7 +378,7 @@ unsigned int readTimer0()
count = ( msb << 8 ) | lsb ;
if (status & RB_OUTPUT )
count += lastLoadedValue;
-
+
return (2*lastLoadedValue - count);
}
@@ -372,19 +412,19 @@ Calibrate_loop_1ms(void)
unsigned int targetClockBits, currentClockBits;
unsigned int slowLoopGranularity, fastLoopGranularity;
rtems_interrupt_level level;
-
+
#ifdef DEBUG_CALIBRATE
printk( "Calibrate_loop_1ms is starting, please wait ( but not too loooong. )\n" );
-#endif
+#endif
targetClockBits = US_TO_TICK(1000);
-
+
rtems_interrupt_disable(level);
/*
* Fill up the cache to get a correct offset
*/
Timer0Reset();
readTimer0();
- /*
+ /*
* Compute the minimal offset to apply due to read counter register.
*/
offset = 0xffffffff;
@@ -437,24 +477,24 @@ Calibrate_loop_1ms(void)
while (1);
}
slowLoopGranularity = (res - offset - emptyCall)/ 10;
-
+
if (slowLoopGranularity == 0) {
printk("Problem #3 in Calibrate_loop_1ms in file libbsp/i386/pc386/timer/timer.c\n");
while (1);
}
targetClockBits += offset;
-#ifdef DEBUG_CALIBRATE
+#ifdef DEBUG_CALIBRATE
printk("offset = %u, emptyCall = %u, targetClockBits = %u\n",
offset, emptyCall, targetClockBits);
printk("slowLoopGranularity = %u fastLoopGranularity = %u\n",
slowLoopGranularity, fastLoopGranularity);
-#endif
+#endif
slowLoop1ms = (targetClockBits - emptyCall) / slowLoopGranularity;
if (slowLoop1ms != 0) {
fastLoop1ms = targetClockBits % slowLoopGranularity;
if (fastLoop1ms > emptyCall) fastLoop1ms -= emptyCall;
- }
+ }
else
fastLoop1ms = targetClockBits - emptyCall / fastLoopGranularity;
@@ -462,7 +502,7 @@ Calibrate_loop_1ms(void)
/*
* calibrate slow loop
*/
-
+
while(1)
{
int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
@@ -497,7 +537,7 @@ Calibrate_loop_1ms(void)
/*
* calibrate fast loop
*/
-
+
if (fastLoopGranularity != 0 ) {
while(1) {
int previousSign = 0; /* 0 = unset, 1 = incrementing, 2 = decrementing */
@@ -525,11 +565,11 @@ Calibrate_loop_1ms(void)
}
}
}
-#ifdef DEBUG_CALIBRATE
+#ifdef DEBUG_CALIBRATE
printk("slowLoop1ms = %u, fastLoop1ms = %u\n", slowLoop1ms, fastLoop1ms);
-#endif
+#endif
rtems_interrupt_enable(level);
-
+
}
/*-------------------------------------------------------------------------+
@@ -537,7 +577,7 @@ Calibrate_loop_1ms(void)
| Description: loop which waits at least timeToWait ms
| Global Variables: loop1ms
| Arguments: timeToWait
-| Returns: Nothing.
+| Returns: Nothing.
+--------------------------------------------------------------------------*/
void
Wait_X_ms( unsigned int timeToWait){
@@ -550,9 +590,3 @@ Wait_X_ms( unsigned int timeToWait){
}
}
-
-
-
-
-
-