[7150f00f] | 1 | /*-------------------------------------------------------------------------+ |
---|
| 2 | | ckinit.c v1.1 - PC386 BSP - 1997/08/07 |
---|
| 3 | +--------------------------------------------------------------------------+ |
---|
| 4 | | This file contains the PC386 clock package. |
---|
| 5 | +--------------------------------------------------------------------------+ |
---|
| 6 | | (C) Copyright 1997 - |
---|
| 7 | | - NavIST Group - Real-Time Distributed Systems and Industrial Automation |
---|
| 8 | | |
---|
| 9 | | http://pandora.ist.utl.pt |
---|
| 10 | | |
---|
| 11 | | Instituto Superior Tecnico * Lisboa * PORTUGAL |
---|
| 12 | +--------------------------------------------------------------------------+ |
---|
| 13 | | Disclaimer: |
---|
| 14 | | |
---|
| 15 | | This file is provided "AS IS" without warranty of any kind, either |
---|
| 16 | | expressed or implied. |
---|
| 17 | +--------------------------------------------------------------------------+ |
---|
| 18 | | This code is based on: |
---|
| 19 | | ckinit.c,v 1.4 1995/12/19 20:07:13 joel Exp - go32 BSP |
---|
| 20 | | With the following copyright notice: |
---|
| 21 | | ************************************************************************** |
---|
[60b791ad] | 22 | | * COPYRIGHT (c) 1989-1998. |
---|
[6f9c75c3] | 23 | | * On-Line Applications Research Corporation (OAR). |
---|
| 24 | | * Copyright assigned to U.S. Government, 1994. |
---|
| 25 | | * |
---|
| 26 | | * The license and distribution terms for this file may be |
---|
| 27 | | * found in found in the file LICENSE in this distribution or at |
---|
| 28 | | * http://www.OARcorp.com/rtems/license.html. |
---|
[7150f00f] | 29 | | ************************************************************************** |
---|
[6f9c75c3] | 30 | | |
---|
| 31 | | $Id$ |
---|
[7150f00f] | 32 | +--------------------------------------------------------------------------*/ |
---|
| 33 | |
---|
| 34 | |
---|
| 35 | #include <stdlib.h> |
---|
| 36 | |
---|
| 37 | #include <bsp.h> |
---|
| 38 | #include <irq.h> |
---|
| 39 | #include <rtems/libio.h> |
---|
| 40 | |
---|
| 41 | /*-------------------------------------------------------------------------+ |
---|
| 42 | | Macros |
---|
| 43 | +--------------------------------------------------------------------------*/ |
---|
| 44 | #if 0 |
---|
| 45 | /* This was dropped in the last revision. Its a nice thing to know. */ |
---|
| 46 | #define TICKS_PER_SECOND() \ |
---|
| 47 | (1000000 / (Clock_isrs_per_tick * microseconds_per_isr)) |
---|
| 48 | #endif /* 0 */ |
---|
| 49 | |
---|
| 50 | /*-------------------------------------------------------------------------+ |
---|
| 51 | | Global Variables |
---|
| 52 | +--------------------------------------------------------------------------*/ |
---|
| 53 | |
---|
| 54 | volatile rtems_unsigned32 Clock_driver_ticks; /* Tick (interrupt) counter. */ |
---|
| 55 | rtems_unsigned32 Clock_isrs_per_tick; /* ISRs per tick. */ |
---|
| 56 | rtems_unsigned32 Clock_isrs; /* ISRs until next tick. */ |
---|
| 57 | |
---|
| 58 | /* The following variables are set by the clock driver during its init */ |
---|
| 59 | |
---|
| 60 | rtems_device_major_number rtems_clock_major = ~0; |
---|
| 61 | rtems_device_minor_number rtems_clock_minor; |
---|
| 62 | |
---|
| 63 | /*-------------------------------------------------------------------------+ |
---|
| 64 | | Function: clockIsr |
---|
[67a2288] | 65 | | Description: Interrupt Service Routine for clock (0h) interruption. |
---|
[7150f00f] | 66 | | Global Variables: Clock_driver_ticks, Clock_isrs. |
---|
| 67 | | Arguments: vector - standard RTEMS argument - see documentation. |
---|
| 68 | | Returns: standard return value - see documentation. |
---|
| 69 | +--------------------------------------------------------------------------*/ |
---|
[67a2288] | 70 | static void clockIsr() |
---|
[7150f00f] | 71 | { |
---|
| 72 | /*-------------------------------------------------------------------------+ |
---|
| 73 | | PLEASE NOTE: The following is directly transcribed from the go32 BSP for |
---|
| 74 | | those who wish to use it with PENTIUM based machine. It needs |
---|
| 75 | | to be correctly integrated with the rest of the code!!! |
---|
| 76 | +--------------------------------------------------------------------------*/ |
---|
| 77 | |
---|
| 78 | #if 0 && defined(pentium) /* more accurate clock for PENTIUMs (not supported) */ |
---|
| 79 | { |
---|
| 80 | extern long long Last_RDTSC; |
---|
| 81 | __asm __volatile(".byte 0x0F, 0x31" : "=A" (Last_RDTSC)); |
---|
| 82 | } |
---|
| 83 | #endif /* 0 && pentium */ |
---|
| 84 | |
---|
| 85 | Clock_driver_ticks++; |
---|
| 86 | |
---|
| 87 | if ( Clock_isrs == 1 ) |
---|
| 88 | { |
---|
| 89 | rtems_clock_tick(); |
---|
| 90 | Clock_isrs = Clock_isrs_per_tick; |
---|
| 91 | } |
---|
| 92 | else |
---|
| 93 | Clock_isrs--; |
---|
| 94 | |
---|
| 95 | } /* clockIsr */ |
---|
| 96 | |
---|
| 97 | /*-------------------------------------------------------------------------+ |
---|
| 98 | | Function: Clock_exit |
---|
| 99 | | Description: Clock cleanup routine at RTEMS exit. NOTE: This routine is |
---|
| 100 | | not really necessary, since there will be a reset at exit. |
---|
| 101 | | Global Variables: None. |
---|
| 102 | | Arguments: None. |
---|
| 103 | | Returns: Nothing. |
---|
| 104 | +--------------------------------------------------------------------------*/ |
---|
[67a2288] | 105 | void clockOff(const rtems_irq_connect_data* unused) |
---|
[7150f00f] | 106 | { |
---|
| 107 | if (BSP_Configuration.ticks_per_timeslice) |
---|
| 108 | { |
---|
| 109 | /* reset timer mode to standard (BIOS) value */ |
---|
| 110 | outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); |
---|
| 111 | outport_byte(TIMER_CNTR0, 0); |
---|
| 112 | outport_byte(TIMER_CNTR0, 0); |
---|
| 113 | } |
---|
| 114 | } /* Clock_exit */ |
---|
| 115 | |
---|
| 116 | |
---|
| 117 | /*-------------------------------------------------------------------------+ |
---|
| 118 | | Function: Install_clock |
---|
| 119 | | Description: Initialize and install clock interrupt handler. |
---|
| 120 | | Global Variables: None. |
---|
| 121 | | Arguments: None. |
---|
| 122 | | Returns: Nothing. |
---|
| 123 | +--------------------------------------------------------------------------*/ |
---|
[67a2288] | 124 | static void clockOn(const rtems_irq_connect_data* unused) |
---|
[7150f00f] | 125 | { |
---|
| 126 | rtems_unsigned32 microseconds_per_isr; |
---|
| 127 | |
---|
| 128 | #if 0 |
---|
| 129 | /* Initialize clock from on-board real time clock. This breaks the */ |
---|
| 130 | /* test code which assumes which assumes the application will do it. */ |
---|
| 131 | { |
---|
| 132 | rtems_time_of_day now; |
---|
| 133 | |
---|
| 134 | /* External Prototypes */ |
---|
| 135 | extern void init_rtc(void); /* defined in 'rtc.c' */ |
---|
| 136 | extern long rtc_read(rtems_time_of_day *); /* defined in 'rtc.c' */ |
---|
| 137 | |
---|
| 138 | init_rtc(); |
---|
| 139 | if (rtc_read(&now) >= 0) |
---|
| 140 | clock_set(&now); |
---|
| 141 | } |
---|
| 142 | #endif /* 0 */ |
---|
| 143 | |
---|
| 144 | /* Start by assuming hardware counter is large enough, then scale it until |
---|
| 145 | it actually fits. */ |
---|
| 146 | |
---|
| 147 | Clock_driver_ticks = 0; |
---|
| 148 | Clock_isrs_per_tick = 1; |
---|
| 149 | |
---|
| 150 | if (BSP_Configuration.microseconds_per_tick == 0) |
---|
| 151 | microseconds_per_isr = 10000; /* default 10 ms */ |
---|
| 152 | else |
---|
| 153 | microseconds_per_isr = BSP_Configuration.microseconds_per_tick; |
---|
| 154 | while (US_TO_TICK(microseconds_per_isr) > 65535) |
---|
| 155 | { |
---|
| 156 | Clock_isrs_per_tick *= 10; |
---|
| 157 | microseconds_per_isr /= 10; |
---|
| 158 | } |
---|
| 159 | |
---|
| 160 | Clock_isrs = Clock_isrs_per_tick; /* Initialize Clock_isrs */ |
---|
| 161 | |
---|
| 162 | if (BSP_Configuration.ticks_per_timeslice) |
---|
| 163 | { |
---|
| 164 | /* 105/88 approximates TIMER_TICK * 1e-6 */ |
---|
| 165 | rtems_unsigned32 count = US_TO_TICK(microseconds_per_isr); |
---|
| 166 | |
---|
| 167 | outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); |
---|
| 168 | outport_byte(TIMER_CNTR0, count >> 0 & 0xff); |
---|
| 169 | outport_byte(TIMER_CNTR0, count >> 8 & 0xff); |
---|
| 170 | } |
---|
| 171 | |
---|
[67a2288] | 172 | } |
---|
[7150f00f] | 173 | |
---|
[67a2288] | 174 | int clockIsOn(const rtems_irq_connect_data* unused) |
---|
| 175 | { |
---|
| 176 | return ((i8259s_cache & 0x1) == 0); |
---|
| 177 | } |
---|
| 178 | |
---|
| 179 | static rtems_irq_connect_data clockIrqData = {PC_386_PERIODIC_TIMER, |
---|
| 180 | clockIsr, |
---|
| 181 | clockOn, |
---|
| 182 | clockOff, |
---|
| 183 | clockIsOn}; |
---|
| 184 | |
---|
| 185 | |
---|
[7150f00f] | 186 | |
---|
| 187 | /*-------------------------------------------------------------------------+ |
---|
| 188 | | Clock device driver INITIALIZE entry point. |
---|
| 189 | +--------------------------------------------------------------------------+ |
---|
| 190 | | Initilizes the clock driver. |
---|
| 191 | +--------------------------------------------------------------------------*/ |
---|
| 192 | rtems_device_driver |
---|
| 193 | Clock_initialize(rtems_device_major_number major, |
---|
| 194 | rtems_device_minor_number minor, |
---|
| 195 | void *pargp) |
---|
| 196 | { |
---|
[67a2288] | 197 | |
---|
| 198 | if (!pc386_install_rtems_irq_handler (&clockIrqData)) { |
---|
| 199 | printk("Unable to initialize system clock\n"); |
---|
| 200 | rtems_fatal_error_occurred(1); |
---|
| 201 | } |
---|
[7150f00f] | 202 | /* make major/minor avail to others such as shared memory driver */ |
---|
| 203 | |
---|
| 204 | rtems_clock_major = major; |
---|
| 205 | rtems_clock_minor = minor; |
---|
| 206 | |
---|
| 207 | return RTEMS_SUCCESSFUL; |
---|
| 208 | } /* Clock_initialize */ |
---|
| 209 | |
---|
[67a2288] | 210 | |
---|
[7150f00f] | 211 | /*-------------------------------------------------------------------------+ |
---|
| 212 | | Console device driver CONTROL entry point |
---|
| 213 | +--------------------------------------------------------------------------*/ |
---|
| 214 | rtems_device_driver |
---|
| 215 | Clock_control(rtems_device_major_number major, |
---|
| 216 | rtems_device_minor_number minor, |
---|
| 217 | void *pargp) |
---|
| 218 | { |
---|
| 219 | if (pargp != NULL) |
---|
| 220 | { |
---|
| 221 | rtems_libio_ioctl_args_t *args = pargp; |
---|
| 222 | |
---|
| 223 | /*-------------------------------------------------------------------------+ |
---|
| 224 | | This is hokey, but until we get a defined interface to do this, it will |
---|
| 225 | | just be this simple... |
---|
| 226 | +-------------------------------------------------------------------------*/ |
---|
| 227 | |
---|
| 228 | if (args->command == rtems_build_name('I', 'S', 'R', ' ')) |
---|
[67a2288] | 229 | clockIsr(); |
---|
[7150f00f] | 230 | else if (args->command == rtems_build_name('N', 'E', 'W', ' ')) |
---|
| 231 | { |
---|
[67a2288] | 232 | if (!pc386_install_rtems_irq_handler (&clockIrqData)) { |
---|
[7150f00f] | 233 | printk("Error installing clock interrupt handler!\n"); |
---|
[67a2288] | 234 | rtems_fatal_error_occurred(1); |
---|
[7150f00f] | 235 | } |
---|
| 236 | } |
---|
| 237 | } |
---|
| 238 | |
---|
| 239 | return RTEMS_SUCCESSFUL; |
---|
| 240 | } /* Clock_control */ |
---|
| 241 | |
---|
[67a2288] | 242 | void Clock_exit() |
---|
| 243 | { |
---|
| 244 | pc386_remove_rtems_irq_handler (&clockIrqData); |
---|
| 245 | } |
---|
[7150f00f] | 246 | |
---|
| 247 | /*-------------------------------------------------------------------------+ |
---|
| 248 | | PLEASE NOTE: The following is directly transcribed from the go32 BSP for |
---|
| 249 | | those who wish to use it with PENTIUM based machine. It needs |
---|
| 250 | | to be correctly integrated with the rest of the code!!! |
---|
| 251 | +--------------------------------------------------------------------------*/ |
---|
| 252 | |
---|
| 253 | |
---|
| 254 | #if 0 && defined(pentium) |
---|
| 255 | |
---|
| 256 | /* This can be used to get extremely accurate timing on a pentium. */ |
---|
| 257 | /* It isn't supported. [bryce] */ |
---|
| 258 | |
---|
| 259 | #define HZ 90.0 |
---|
| 260 | |
---|
| 261 | volatile long long Last_RDTSC; |
---|
| 262 | |
---|
| 263 | #define RDTSC()\ |
---|
| 264 | ({ long long _now; __asm __volatile (".byte 0x0F,0x31":"=A"(_now)); _now; }) |
---|
| 265 | |
---|
| 266 | long long Kernel_Time_ns( void ) |
---|
| 267 | { |
---|
| 268 | extern rtems_unsigned32 _TOD_Ticks_per_second; |
---|
| 269 | |
---|
| 270 | unsigned isrs_per_second = Clock_isrs_per_tick * _TOD_Ticks_per_second; |
---|
| 271 | long long now; |
---|
| 272 | int flags; |
---|
| 273 | |
---|
| 274 | disable_intr(flags); |
---|
| 275 | now = 1e9 * Clock_driver_ticks / isrs_per_second + |
---|
| 276 | (RDTSC() - Last_RDTSC) * (1000.0/HZ); |
---|
| 277 | enable_intr(flags); |
---|
| 278 | return now; |
---|
| 279 | } /* Kernel_Time_ns */ |
---|
| 280 | |
---|
| 281 | #endif /* 0 && pentium */ |
---|