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

4.104.114.84.95
Last change on this file since 458bd34 was 458bd34, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 5, 1999 at 4:44:02 PM

This is another pass at making sure that nothing outside the BSP
unnecessarily uses any variables defined by the BSP. On this
sweep, use of BSP_Configuration and Cpu_table was eliminated.

A significant part of this modification was the addition of
macros to access fields in the RTEMS configuration structures.

This is necessary to strengthen the division between the BSP independent
parts of RTEMS and the BSPs themselves. This started after
comments and analysis by Ralf Corsepius <corsepiu@…>.

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