source: rtems/c/src/lib/libcpu/hppa1.1/clock/clock.c @ df49c60

4.104.114.84.95
Last change on this file since df49c60 was 0dd1d44, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 11, 2000 at 5:34:20 PM

Removed old hack of using Configuration Table entry ticks_per_timeslice
being set to 0 to indicate that there should be no Clock Tick. This
was used by the Timing Tests to avoid clock tick overhead perturbing
execution times. Now the Timing Tests simply leave the Clock Tick
Driver out of the Device Driver Table.

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/*  Clock
2 *
3 *  This routine initializes the interval timer on the
4 *  PA-RISC CPU.  The tick frequency is specified by the bsp.
5 *
6 *  COPYRIGHT (c) 1989-1999.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.OARcorp.com/rtems/license.html.
12 *
13 *  $Id$
14 */
15
16#include <rtems.h>
17#include <rtems/libio.h>
18
19/* should get this from bsp.h, but it is not installed yet */
20rtems_isr_entry set_vector(rtems_isr_entry, rtems_vector_number, int);
21
22#include <stdlib.h>                     /* for atexit() */
23
24typedef unsigned long long hppa_click_count_t;
25
26/*
27 * These are set by clock driver during its init
28 */
29
30rtems_device_major_number rtems_clock_major = ~0;
31rtems_device_minor_number rtems_clock_minor;
32
33/*
34 * CPU_HPPA_CLICKS_PER_TICK is either a #define or an rtems_unsigned32
35 *   allocated and set by bsp_start()
36 */
37
38#ifndef CPU_HPPA_CLICKS_PER_TICK
39extern rtems_unsigned32 CPU_HPPA_CLICKS_PER_TICK;
40#endif
41
42volatile rtems_unsigned32 Clock_driver_ticks;
43rtems_unsigned32 Clock_isrs;              /* ISRs until next tick */
44
45rtems_unsigned32   most_recent_itimer_value;
46
47rtems_unsigned64   Clock_clicks;        /* running total of cycles */
48
49rtems_unsigned32   Clock_clicks_interrupt;
50
51void  Clock_exit(void);
52
53void
54ReInstall_clock(rtems_isr_entry new_clock_isr)
55{
56    rtems_unsigned32 isrlevel = 0;
57
58    rtems_interrupt_disable(isrlevel);
59    (void) set_vector(
60      new_clock_isr,
61      HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER,
62      1
63    );
64    rtems_interrupt_enable(isrlevel);
65}
66
67/*
68 * read itimer and update Clock_clicks as appropriate
69 */
70
71rtems_unsigned32
72Clock_read_itimer()
73{
74    rtems_unsigned32 isrlevel;
75    rtems_unsigned32 itimer_value;
76    rtems_unsigned32 wrap_count;
77    rtems_unsigned32 recent_count;
78
79    rtems_interrupt_disable(isrlevel);
80
81    wrap_count = (Clock_clicks & 0xFFFFFFFF00000000ULL) >> 32;
82    recent_count = (rtems_unsigned32) Clock_clicks;
83
84    itimer_value = get_itimer();
85
86    if (itimer_value < recent_count)
87        wrap_count++;
88    Clock_clicks = (((rtems_unsigned64) wrap_count) << 32) + itimer_value;
89
90    rtems_interrupt_enable(isrlevel);
91
92    return itimer_value;
93}
94
95
96void Install_clock(rtems_isr_entry clock_isr)
97{
98    Clock_driver_ticks = 0;
99    Clock_clicks_interrupt = 0;
100    Clock_clicks = 0;
101
102    Clock_isrs = rtems_configuration_get_milliseconds_per_tick();
103
104    /*
105     * initialize the interval here
106     * First tick is set to right amount of time in the future
107     * Future ticks will be incremented over last value set
108     * in order to provide consistent clicks in the face of
109     * interrupt overhead
110     */
111
112    Clock_clicks_interrupt = Clock_read_itimer() + CPU_HPPA_CLICKS_PER_TICK;
113    set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
114
115    (void) set_vector(clock_isr, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
116    atexit(Clock_exit);
117}
118
119rtems_isr
120Clock_isr(rtems_vector_number vector)
121{
122    rtems_unsigned32 clicks_til_next_interrupt;
123    rtems_unsigned32 itimer_value;
124
125    /*
126     * setup for next interrupt; making sure the new value is reasonably
127     * in the future.... in case we lost out on an interrupt somehow
128     */
129
130    itimer_value = Clock_read_itimer();
131    Clock_clicks_interrupt += CPU_HPPA_CLICKS_PER_TICK;
132
133    /*
134     * how far away is next interrupt *really*
135     * It may be a long time; this subtraction works even if
136     * Clock_clicks_interrupt < Clock_clicks_low_order via
137     * the miracle of unsigned math.
138     */
139    clicks_til_next_interrupt = Clock_clicks_interrupt - itimer_value;
140
141    /*
142     * If it is too soon then bump it up.
143     * This should only happen if CPU_HPPA_CLICKS_PER_TICK is too small.
144     * But setting it low is useful for debug, so...
145     */
146
147    if (clicks_til_next_interrupt < 400)
148    {
149        Clock_clicks_interrupt = itimer_value + 1000;
150        /* XXX: count these! this should be rare */
151    }
152
153    /*
154     * If it is too late, that means we missed the interrupt somehow.
155     * Rather than wait 35-50s for a wrap, we just fudge it here.
156     */
157
158    if (clicks_til_next_interrupt > CPU_HPPA_CLICKS_PER_TICK)
159    {
160        Clock_clicks_interrupt = itimer_value + 1000;
161        /* XXX: count these! this should never happen :-) */
162    }
163
164    set_itimer((rtems_unsigned32) Clock_clicks_interrupt);
165
166    Clock_driver_ticks++;
167
168    if (Clock_isrs == 1)
169    {
170        rtems_clock_tick();
171        Clock_isrs = rtems_configuration_get_milliseconds_per_tick();
172        if (Clock_isrs == 0)
173            Clock_isrs = 1;
174    }
175    else
176        Clock_isrs--;
177}
178
179/*
180 * Called via atexit()
181 * Remove the clock interrupt handler by setting handler to NULL
182 */
183
184void
185Clock_exit(void)
186{
187  (void) set_vector(0, HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER, 1);
188}
189
190/*
191 * spin delay for specified number of microseconds
192 * used by RTEMS delay macro
193 */
194
195void
196Clock_delay(rtems_unsigned32 microseconds)
197{
198    rtems_unsigned64 future_time;
199
200    (void) Clock_read_itimer();
201    future_time = Clock_clicks +
202      ((rtems_unsigned64) microseconds) *
203        rtems_cpu_configuration_get_itimer_clicks_per_microsecond();
204
205    for (;;)
206    {
207        (void) Clock_read_itimer();
208        if (future_time <= Clock_clicks)
209            break;
210    }
211}
212
213rtems_device_driver Clock_initialize(
214  rtems_device_major_number major,
215  rtems_device_minor_number minor,
216  void *pargp
217)
218{
219    Install_clock(Clock_isr);
220
221    /*
222     * make major/minor avail to others such as shared memory driver
223     */
224    rtems_clock_major = major;
225    rtems_clock_minor = minor;
226
227    return RTEMS_SUCCESSFUL;
228}
229
230rtems_device_driver Clock_control(
231  rtems_device_major_number major,
232  rtems_device_minor_number minor,
233  void *pargp
234)
235{
236    rtems_libio_ioctl_args_t *args = pargp;
237
238    if (args == 0)
239        goto done;
240
241    /*
242     * This is hokey, but until we get a defined interface
243     * to do this, it will just be this simple...
244     */
245
246    if (args->command == rtems_build_name('I', 'S', 'R', ' '))
247    {
248        Clock_isr(HPPA_INTERRUPT_EXTERNAL_INTERVAL_TIMER);
249    }
250    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
251    {
252        ReInstall_clock(args->buffer);
253    }
254   
255done:
256    return RTEMS_SUCCESSFUL;
257}
Note: See TracBrowser for help on using the repository browser.