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

4.104.114.84.95
Last change on this file since f817b02 was f817b02, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 4, 1999 at 6:05:09 PM

The files in libcpu should not be directly dependent on any BSP. In
particular, using bsp.h, or getting information from the BSP which
should properly be obtained from RTEMS is forbidden. 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@…>.
The changes primarily eliminated the need to include bsp.h and
peeking at BSP_Configuration. The use of Cpu_table in each
BSP needs to be eliminated.

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