diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2008-02-07 21:28:11 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2008-02-07 21:28:11 +0000 |
commit | b62009c38ac9b3971bb0d9ec0dfa785b1f574167 (patch) | |
tree | f28fc04c1b706f0e9229429b977768e89a28b962 /c/src/lib/libbsp/i386/pc386/clock/ckinit.c | |
parent | 2008-02-06 Joel Sherrill <joel.sherrill@oarcorp.com> (diff) | |
download | rtems-b62009c38ac9b3971bb0d9ec0dfa785b1f574167.tar.bz2 |
2008-02-07 Joel Sherrill <joel.sherrill@oarcorp.com>
* clock/ckinit.c: Rework clock driver to use template and to provide
nanoseconds since last tick capability.
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/clock/ckinit.c | 349 |
1 files changed, 135 insertions, 214 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c index 29a746a9d0..daee42d62b 100644 --- a/c/src/lib/libbsp/i386/pc386/clock/ckinit.c +++ b/c/src/lib/libbsp/i386/pc386/clock/ckinit.c @@ -1,237 +1,158 @@ -/*-------------------------------------------------------------------------+ -| ckinit.c v1.1 - PC386 BSP - 1997/08/07 -+--------------------------------------------------------------------------+ -| This file contains the PC386 clock package. -+--------------------------------------------------------------------------+ -| (C) Copyright 1997 - -| - NavIST Group - Real-Time Distributed Systems and Industrial Automation -| -| http://pandora.ist.utl.pt -| -| Instituto Superior Tecnico * Lisboa * PORTUGAL -+--------------------------------------------------------------------------+ -| Disclaimer: -| -| This file is provided "AS IS" without warranty of any kind, either -| expressed or implied. -+--------------------------------------------------------------------------+ -| This code is based on: -| ckinit.c,v 1.4 1995/12/19 20:07:13 joel Exp - go32 BSP -| With the following copyright notice: -| ************************************************************************** -| * COPYRIGHT (c) 1989-1999. -| * On-Line Applications Research Corporation (OAR). -| * -| * The license and distribution terms for this file may be -| * found in found in the file LICENSE in this distribution or at -| * http://www.rtems.com/license/LICENSE. -| ************************************************************************** -| -| $Id$ -+--------------------------------------------------------------------------*/ - -#include <stdlib.h> +/* + * Clock Tick Device Driver + * + * History: + * + Original driver was go32 clock by Joel Sherrill + * + go32 clock driver hardware code was inserted into new + * boilerplate when the pc386 BSP by: + * Pedro Miguel Da Cruz Neto Romano <pmcnr@camoes.rnl.ist.utl.pt> + * Jose Rufino <ruf@asterix.ist.utl.pt> + * + Reworked by Joel Sherrill to use clock driver template. + * This removes all boilerplate and leave original hardware + * code I developed for the go32 BSP. + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ #include <bsp.h> #include <bsp/irq.h> -#include <rtems/libio.h> - -/*-------------------------------------------------------------------------+ -| Macros -+--------------------------------------------------------------------------*/ -#if 0 -/* This was dropped in the last revision. Its a nice thing to know. */ -#define TICKS_PER_SECOND() \ - (1000000 / (Clock_isrs_per_tick * microseconds_per_isr)) -#endif /* 0 */ - -/*-------------------------------------------------------------------------+ -| Global Variables -+--------------------------------------------------------------------------*/ - -volatile uint32_t Clock_driver_ticks; /* Tick (interrupt) counter. */ - uint32_t Clock_isrs_per_tick; /* ISRs per tick. */ - uint32_t Clock_isrs; /* ISRs until next tick. */ - -/* The following variables are set by the clock driver during its init */ - -rtems_device_major_number rtems_clock_major = ~0; -rtems_device_minor_number rtems_clock_minor; - -/*-------------------------------------------------------------------------+ -| Function: clockIsr -| Description: Interrupt Service Routine for clock (0h) interruption. -| Global Variables: Clock_driver_ticks, Clock_isrs. -| Arguments: vector - standard RTEMS argument - see documentation. -| Returns: standard return value - see documentation. -+--------------------------------------------------------------------------*/ -static void clockIsr() -{ - /*-------------------------------------------------------------------------+ - | PLEASE NOTE: The following is directly transcribed from the go32 BSP for - | those who wish to use it with PENTIUM based machine. It needs - | to be correctly integrated with the rest of the code!!! - +--------------------------------------------------------------------------*/ - -#if 0 && defined(pentium) /* more accurate clock for PENTIUMs (not supported) */ - { - extern long long Last_RDTSC; - __asm __volatile(".byte 0x0F, 0x31" : "=A" (Last_RDTSC)); - } -#endif /* 0 && pentium */ - - Clock_driver_ticks++; - - if ( Clock_isrs == 1 ) - { - rtems_clock_tick(); - Clock_isrs = Clock_isrs_per_tick; - } - else - Clock_isrs--; - -} /* clockIsr */ - -/*-------------------------------------------------------------------------+ -| Function: Clock_exit -| Description: Clock 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. -+--------------------------------------------------------------------------*/ -void clockOff(const rtems_irq_connect_data* unused) -{ - /* reset timer mode to standard (BIOS) value */ - outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); - outport_byte(TIMER_CNTR0, 0); - outport_byte(TIMER_CNTR0, 0); -} /* Clock_exit */ +#include <bspopts.h> -/*-------------------------------------------------------------------------+ -| Function: Install_clock -| Description: Initialize and install clock interrupt handler. -| Global Variables: None. -| Arguments: None. -| Returns: Nothing. -+--------------------------------------------------------------------------*/ -static void clockOn(const rtems_irq_connect_data* unused) -{ - uint32_t microseconds_per_isr; +#define CLOCK_VECTOR 0 -#if 0 - /* Initialize clock from on-board real time clock. This breaks the */ - /* test code which assumes which assumes the application will do it. */ - { - rtems_time_of_day now; +volatile uint32_t pc386_microseconds_per_isr; +volatile uint32_t pc386_isrs_per_tick; +uint32_t pc386_clock_click_count; - /* External Prototypes */ - extern void init_rtc(void); /* defined in 'rtc.c' */ - extern long rtc_read(rtems_time_of_day *); /* defined in 'rtc.c' */ - init_rtc(); - if (rtc_read(&now) >= 0) - clock_set(&now); - } -#endif /* 0 */ - - /* Start by assuming hardware counter is large enough, then scale it until - it actually fits. */ - - Clock_driver_ticks = 0; - Clock_isrs_per_tick = 1; - - if (rtems_configuration_get_microseconds_per_tick() == 0) - microseconds_per_isr = 10000; /* default 10 ms */ - else - microseconds_per_isr = rtems_configuration_get_microseconds_per_tick(); - while (US_TO_TICK(microseconds_per_isr) > 65535) - { - Clock_isrs_per_tick *= 10; - microseconds_per_isr /= 10; - } - - Clock_isrs = Clock_isrs_per_tick; /* Initialize Clock_isrs */ +/* this driver may need to count ISRs per tick */ - { - /* 105/88 approximates TIMER_TICK * 1e-6 */ - uint32_t count = US_TO_TICK(microseconds_per_isr); +#define CLOCK_DRIVER_ISRS_PER_TICK pc386_isrs_per_tick - outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); - outport_byte(TIMER_CNTR0, count >> 0 & 0xff); - outport_byte(TIMER_CNTR0, count >> 8 & 0xff); - } +#define Clock_driver_support_at_tick() -} +#define Clock_driver_support_install_isr( _new, _old ) \ + do { \ + } while(0) -int clockIsOn(const rtems_irq_connect_data* unused) +uint32_t bsp_clock_nanoseconds_since_last_tick(void) { - return ((i8259s_cache & 0x1) == 0); + uint32_t usecs, clicks, isrs; + uint32_t usecs1, usecs2; + uint8_t lsb, msb; + extern volatile uint32_t Clock_driver_isrs; + rtems_interrupt_level level; + + /* + * Fetch all the data in an interrupt critical section. + */ + rtems_interrupt_disable(level); + outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); + inport_byte(TIMER_CNTR0, lsb); + inport_byte(TIMER_CNTR0, msb); + isrs = Clock_driver_isrs; + rtems_interrupt_enable(level); + + /* + * Now do the math + */ + /* convert values read into counter clicks */ + clicks = ((msb << 8) | lsb); + + /* whole ISRs we have done since the last tick */ + usecs1 = (pc386_isrs_per_tick - isrs - 1) * pc386_microseconds_per_isr; + + /* the partial ISR we in the middle of now */ + usecs2 = pc386_microseconds_per_isr - TICK_TO_US(clicks); + + /* total microseconds */ + usecs = usecs1 + usecs2; + #if 0 + printk( "usecs1=%d usecs2=%d ", usecs1, usecs2 ); + printk( "maxclicks=%d clicks=%d ISRs=%d ISRsper=%d usersPer=%d usecs=%d\n", + pc386_clock_click_count, clicks, + Clock_driver_isrs, pc386_isrs_per_tick, + pc386_microseconds_per_isr, usecs ); + #endif + + /* return it in nanoseconds */ + return usecs * 1000; } -static rtems_irq_connect_data clockIrqData = {BSP_PERIODIC_TIMER, - clockIsr, - 0, - clockOn, - clockOff, - clockIsOn}; - -/*-------------------------------------------------------------------------+ -| Clock device driver INITIALIZE entry point. -+--------------------------------------------------------------------------+ -| Initilizes the clock driver. -+--------------------------------------------------------------------------*/ -rtems_device_driver -Clock_initialize(rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp) +#define Clock_driver_nanoseconds_since_last_tick \ + bsp_clock_nanoseconds_since_last_tick + +static void clockOn( + const rtems_irq_connect_data* unused +) { + pc386_isrs_per_tick = 1; + pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick(); - if (!BSP_install_rtems_irq_handler (&clockIrqData)) { - printk("Unable to initialize system clock\n"); - rtems_fatal_error_occurred(1); + while (US_TO_TICK(pc386_microseconds_per_isr) > 65535) { + pc386_isrs_per_tick *= 10; + pc386_microseconds_per_isr /= 10; } - /* make major/minor avail to others such as shared memory driver */ - - rtems_clock_major = major; - rtems_clock_minor = minor; - - return RTEMS_SUCCESSFUL; -} /* Clock_initialize */ + pc386_clock_click_count = US_TO_TICK(pc386_microseconds_per_isr); + + #if 0 + printk( "configured usecs per tick=%d \n", + rtems_configuration_get_microseconds_per_tick() ); + printk( "Microseconds per ISR =%d\n", pc386_microseconds_per_isr ); + printk( "final ISRs per=%d\n", pc386_isrs_per_tick ); + printk( "final timer counts=%d\n", pc386_clock_click_count ); + #endif + + outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); + outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 0 & 0xff); + outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 8 & 0xff); +} -/*-------------------------------------------------------------------------+ -| Console device driver CONTROL entry point -+--------------------------------------------------------------------------*/ -rtems_device_driver -Clock_control(rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp) +void clockOff(const rtems_irq_connect_data* unused) { - if (pargp != NULL) - { - rtems_libio_ioctl_args_t *args = pargp; - - /*-------------------------------------------------------------------------+ - | This is hokey, but until we get a defined interface to do this, it will - | just be this simple... - +-------------------------------------------------------------------------*/ - - if (args->command == rtems_build_name('I', 'S', 'R', ' ')) - clockIsr(); - else if (args->command == rtems_build_name('N', 'E', 'W', ' ')) - { - if (!BSP_install_rtems_irq_handler (&clockIrqData)) { - printk("Error installing clock interrupt handler!\n"); - rtems_fatal_error_occurred(1); - } - } - } - - return RTEMS_SUCCESSFUL; -} /* Clock_control */ + /* reset timer mode to standard (BIOS) value */ + outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); + outport_byte(TIMER_CNTR0, 0); + outport_byte(TIMER_CNTR0, 0); +} /* Clock_exit */ -void Clock_exit() +int clockIsOn(const rtems_irq_connect_data* unused) { - BSP_remove_rtems_irq_handler (&clockIrqData); + return ((i8259s_cache & 0x1) == 0); } +/* a bit of a hack since the ISR models do not match */ +rtems_isr Clock_isr( + rtems_vector_number vector +); +static rtems_irq_connect_data clockIrqData = { + BSP_PERIODIC_TIMER, + (void *)Clock_isr, + 0, + clockOn, + clockOff, + clockIsOn +}; + +#define Clock_driver_support_initialize_hardware() \ + do { \ + if (!BSP_install_rtems_irq_handler (&clockIrqData)) { \ + printk("Unable to initialize system clock\n"); \ + rtems_fatal_error_occurred(1); \ + } \ + } while (0) + +#define Clock_driver_support_shutdown_hardware() \ + do { \ + BSP_remove_rtems_irq_handler (&clockIrqData); \ + } while (0) + +#include "../../../shared/clockdrv_shell.c" + |