source: rtems/c/src/lib/libbsp/shared/clockdrv_shell.h @ 90d8567

Last change on this file since 90d8567 was 90d8567, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 18, 2016 at 7:36:16 AM

score: Distribute clock tick to all online CPUs

Update #2554.

  • Property mode set to 100644
File size: 5.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_clock
5 *
6 * @brief Clock Tick Device Driver Shell
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2014.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#include <stdlib.h>
19
20#include <bsp.h>
21#include <rtems/clockdrv.h>
22#include <rtems/score/percpu.h>
23#include <rtems/score/smpimpl.h>
24
25#ifdef Clock_driver_nanoseconds_since_last_tick
26#error "Update driver to use the timecounter instead of nanoseconds extension"
27#endif
28
29/**
30 * @defgroup bsp_clock Clock Support
31 *
32 * @ingroup bsp_shared
33 *
34 * @brief Clock support
35 *
36 */
37#if CLOCK_DRIVER_USE_FAST_IDLE && CLOCK_DRIVER_ISRS_PER_TICK
38#error "clockdrv_shell.h: Fast Idle PLUS n ISRs per tick is not supported"
39#endif
40
41/**
42 * @brief This method is rarely used so default it.
43 */
44#ifndef Clock_driver_support_find_timer
45  #define Clock_driver_support_find_timer()
46#endif
47
48/**
49 * @brief Do nothing by default.
50 */
51#ifndef Clock_driver_support_at_tick
52  #define Clock_driver_support_at_tick()
53#endif
54
55/**
56 * @brief Do nothing by default.
57 */
58#ifndef Clock_driver_support_set_interrupt_affinity
59  #define Clock_driver_support_set_interrupt_affinity(online_processors)
60#endif
61
62/*
63 * A specialized clock driver may use for example rtems_timecounter_tick_simple()
64 * instead of the default.
65 */
66#ifndef Clock_driver_timecounter_tick
67  #ifdef CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
68    #define Clock_driver_timecounter_tick() rtems_clock_tick()
69  #else
70    #define Clock_driver_timecounter_tick() rtems_timecounter_tick()
71  #endif
72#endif
73
74/**
75 * @brief ISRs until next clock tick
76 */
77#if CLOCK_DRIVER_ISRS_PER_TICK
78  volatile uint32_t  Clock_driver_isrs;
79#endif
80
81/**
82 * @brief Clock ticks since initialization
83 */
84volatile uint32_t    Clock_driver_ticks;
85
86void Clock_exit( void );
87
88/**
89 *  @brief Clock_isr
90 *
91 *  This is the clock tick interrupt handler.
92 *
93 *  @param vector Vector number.
94 */
95#if defined(BSP_FEATURE_IRQ_EXTENSION) || \
96    (CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE)
97void Clock_isr(void *arg);
98void Clock_isr(void *arg)
99{
100#else
101rtems_isr Clock_isr(rtems_vector_number vector);
102rtems_isr Clock_isr(
103  rtems_vector_number vector
104)
105{
106#endif
107  /*
108   *  Accurate count of ISRs
109   */
110  Clock_driver_ticks += 1;
111
112  #if CLOCK_DRIVER_USE_FAST_IDLE
113    {
114      struct timecounter *tc = _Timecounter;
115      uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
116      uint32_t interval = (uint32_t)
117        ((tc->tc_frequency * us_per_tick) / 1000000);
118
119      Clock_driver_timecounter_tick();
120
121      while (
122        _Thread_Heir == _Thread_Executing
123          && _Thread_Executing->Start.Entry.Kinds.Idle.entry
124            == rtems_configuration_get_idle_task()
125      ) {
126        ISR_lock_Context lock_context;
127
128        _Timecounter_Acquire(&lock_context);
129        _Timecounter_Tick_simple(
130          interval,
131          (*tc->tc_get_timecount)(tc),
132          &lock_context
133        );
134      }
135
136      Clock_driver_support_at_tick();
137    }
138  #else
139    /*
140     *  Do the hardware specific per-tick action.
141     *
142     *  The counter/timer may or may not be set to automatically reload.
143     */
144    Clock_driver_support_at_tick();
145
146    #if CLOCK_DRIVER_ISRS_PER_TICK
147      /*
148       *  The driver is multiple ISRs per clock tick.
149       */
150      if ( !Clock_driver_isrs ) {
151        Clock_driver_timecounter_tick();
152
153        Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
154      }
155      Clock_driver_isrs--;
156    #else
157      /*
158       *  The driver is one ISR per clock tick.
159       */
160      Clock_driver_timecounter_tick();
161    #endif
162  #endif
163}
164
165/**
166 *  @brief Clock_exit
167 *
168 *  This routine allows the clock driver to exit by masking the interrupt and
169 *  disabling the clock's counter.
170 */
171void Clock_exit( void )
172{
173  Clock_driver_support_shutdown_hardware();
174
175  /* do not restore old vector */
176}
177
178/**
179 * @brief Clock_initialize
180 *
181 * This routine initializes the clock driver.
182 *
183 * @param[in] major Clock device major number.
184 * @param[in] minor Clock device minor number.
185 * @param[in] parg  Pointer to optional device driver arguments
186 *
187 * @retval rtems_device_driver status code
188 */
189rtems_device_driver Clock_initialize(
190  rtems_device_major_number major,
191  rtems_device_minor_number minor,
192  void *pargp
193)
194{
195  rtems_isr_entry  Old_ticker;
196
197  Clock_driver_ticks = 0;
198
199  /*
200   *  Find timer -- some BSPs search buses for hardware timer
201   */
202  Clock_driver_support_find_timer();
203
204  /*
205   *  Install vector
206   */
207  (void) Old_ticker;
208  Clock_driver_support_install_isr( Clock_isr, Old_ticker );
209
210  #ifdef RTEMS_SMP
211    Clock_driver_support_set_interrupt_affinity( _SMP_Online_processors );
212  #endif
213
214  /*
215   *  Now initialize the hardware that is the source of the tick ISR.
216   */
217  Clock_driver_support_initialize_hardware();
218
219  atexit( Clock_exit );
220
221  /*
222   *  If we are counting ISRs per tick, then initialize the counter.
223   */
224  #if CLOCK_DRIVER_ISRS_PER_TICK
225    Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK_VALUE;
226  #endif
227
228  return RTEMS_SUCCESSFUL;
229}
Note: See TracBrowser for help on using the repository browser.