source: rtems/c/src/lib/libbsp/i386/pc386/clock/ckinit.c @ 67a2288

4.104.114.84.95
Last change on this file since 67a2288 was 67a2288, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 23, 1998 at 10:02:34 PM

Patch from Eric VALETTE <valette@…>:

Here is a enhanced version of my previous patch. This patch enables
to potentially share the new interrupt management code for all Intel targets
(pc386, go32 and force386) bsp.

Note : this patch is complete only for pc386. It still needs to

be completed for go32 and force386. I carrefully checked
that anything needed is in for force386 (only some function
name changes for IDT manipulation and GDT segment
manipulation). But anyway I will not be able to test any
of theses targets...

  • Property mode set to 100644
File size: 9.3 KB
Line 
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| **************************************************************************
22| *  COPYRIGHT (c) 1989-1998.
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.
29| **************************************************************************
30|
31|  $Id$
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
54volatile 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
60rtems_device_major_number rtems_clock_major = ~0;
61rtems_device_minor_number rtems_clock_minor;
62
63/*-------------------------------------------------------------------------+
64|         Function: clockIsr
65|      Description: Interrupt Service Routine for clock (0h) interruption.
66| Global Variables: Clock_driver_ticks, Clock_isrs.
67|        Arguments: vector - standard RTEMS argument - see documentation.
68|          Returns: standard return value - see documentation.
69+--------------------------------------------------------------------------*/
70static void clockIsr()
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+--------------------------------------------------------------------------*/
105void clockOff(const rtems_irq_connect_data* unused)
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+--------------------------------------------------------------------------*/
124static void clockOn(const rtems_irq_connect_data* unused)
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
172} 
173
174int clockIsOn(const rtems_irq_connect_data* unused)
175{
176  return ((i8259s_cache & 0x1) == 0);
177}
178
179static rtems_irq_connect_data clockIrqData = {PC_386_PERIODIC_TIMER,
180                                              clockIsr,
181                                              clockOn,
182                                              clockOff,
183                                              clockIsOn};
184                                             
185                                             
186
187/*-------------------------------------------------------------------------+
188| Clock device driver INITIALIZE entry point.
189+--------------------------------------------------------------------------+
190| Initilizes the clock driver.
191+--------------------------------------------------------------------------*/
192rtems_device_driver
193Clock_initialize(rtems_device_major_number major,
194                 rtems_device_minor_number minor,
195                 void                      *pargp)
196{
197
198  if (!pc386_install_rtems_irq_handler (&clockIrqData)) {
199    printk("Unable to initialize system clock\n");
200    rtems_fatal_error_occurred(1);
201  }
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
210                                             
211/*-------------------------------------------------------------------------+
212| Console device driver CONTROL entry point
213+--------------------------------------------------------------------------*/
214rtems_device_driver
215Clock_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', ' '))
229      clockIsr();
230    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
231    {
232      if (!pc386_install_rtems_irq_handler (&clockIrqData)) {
233        printk("Error installing clock interrupt handler!\n");
234        rtems_fatal_error_occurred(1);
235      }
236    }
237  }
238
239  return RTEMS_SUCCESSFUL;
240} /* Clock_control */
241
242void Clock_exit()
243{
244  pc386_remove_rtems_irq_handler (&clockIrqData);
245}
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
261volatile long long Last_RDTSC;
262
263#define RDTSC()\
264  ({ long long _now; __asm __volatile (".byte 0x0F,0x31":"=A"(_now)); _now; })
265
266long 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 */
Note: See TracBrowser for help on using the repository browser.