source: rtems/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c @ cc9073d

4.104.114.84.95
Last change on this file since cc9073d was cc9073d, checked in by Till Straumann <strauman@…>, on 11/03/05 at 18:35:07

2005-11-03 straumanatslacdotstanford.edu

  • mpc6xx/clock/c_clock.c: disable interrupts around decrementer update to eliminate a race condition
  • Property mode set to 100644
File size: 4.7 KB
Line 
1/*
2 *  Clock Tick Device Driver
3 *
4 *  This routine utilizes the Decrementer Register common to the PPC family.
5 *
6 *  The tick frequency is directly programmed to the configured number of
7 *  microseconds per tick.
8 *
9 *  COPYRIGHT (c) 1989-1997.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may in
13 *  the file LICENSE in this distribution or at
14 *  http://www.rtems.com/license/LICENSE.
15 *
16 *  Modified to support the MPC750.
17 *  Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
18 *
19 *  $Id$
20 */
21
22#include <rtems/system.h>
23#include <rtems.h>
24#include <rtems/libio.h>
25#include <stdlib.h>                     /* for atexit() */
26#include <assert.h>
27#include <libcpu/c_clock.h>
28#include <rtems/bspIo.h>                     /* for printk() */
29
30extern int BSP_connect_clock_handler (void);
31
32/*
33 *  Clock ticks since initialization
34 */
35
36volatile uint32_t   Clock_driver_ticks;
37
38/*
39 *  This is the value programmed into the count down timer.
40 */
41
42uint32_t   Clock_Decrementer_value;
43
44/*
45 * These are set by clock driver during its init
46 */
47 
48rtems_device_major_number rtems_clock_major = ~0;
49rtems_device_minor_number rtems_clock_minor;
50
51void clockOff(void* unused)
52{
53  /*
54   * Nothing to do as we cannot disable all interrupts and
55   * the decrementer interrupt enable is MSR_EE
56   */
57}
58void clockOn(void* unused)
59{
60  PPC_Set_decrementer( Clock_Decrementer_value );
61}
62
63/*
64 *  Clock_isr
65 *
66 *  This is the clock tick interrupt handler.
67 *
68 *  Input parameters:
69 *    vector - vector number
70 *
71 *  Output parameters:  NONE
72 *
73 *  Return values:      NONE
74 *
75 */
76
77void clockIsr(void *unused)
78{
79int decr;
80  /*
81   *  The driver has seen another tick.
82   */
83  do {
84        register uint32_t flags;
85        rtems_interrupt_disable(flags);
86        asm volatile ("mfdec %0; add %0, %0, %1; mtdec %0":"=&r"(decr):"r"(Clock_Decrementer_value));
87        rtems_interrupt_enable(flags);
88
89        Clock_driver_ticks += 1;
90
91        /*
92         *  Real Time Clock counter/timer is set to automatically reload.
93         */
94        rtems_clock_tick();
95  } while ( decr < 0 );
96}
97
98int clockIsOn(void* unused)
99{
100  uint32_t   msr_value;
101
102  _CPU_MSR_GET( msr_value );
103  if (msr_value & MSR_EE) return 1;
104  return 0;
105}
106
107
108/*
109 *  Clock_exit
110 *
111 *  This routine allows the clock driver to exit by masking the interrupt and
112 *  disabling the clock's counter.
113 *
114 *  Input parameters:   NONE
115 *
116 *  Output parameters:  NONE
117 *
118 *  Return values:      NONE
119 *
120 */
121
122void Clock_exit( void )
123{
124  (void) BSP_disconnect_clock_handler ();
125}
126 
127/*
128 *  Clock_initialize
129 *
130 *  This routine initializes the clock driver.
131 *
132 *  Input parameters:
133 *    major - clock device major number
134 *    minor - clock device minor number
135 *    parg  - pointer to optional device driver arguments
136 *
137 *  Output parameters:  NONE
138 *
139 *  Return values:
140 *    rtems_device_driver status code
141 */
142
143rtems_device_driver Clock_initialize(
144  rtems_device_major_number major,
145  rtems_device_minor_number minor,
146  void *pargp
147)
148{
149  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
150            (rtems_configuration_get_microseconds_per_tick()/1000);
151
152  /* set the decrementer now, prior to installing the handler
153   * so no interrupts will happen in a while.
154   */
155  PPC_Set_decrementer( (unsigned)-1 );
156
157  /* if a decrementer exception was pending, it is cleared by
158   * executing the default (nop) handler at this point;
159   * The next exception will then be taken by our clock handler.
160   * Clock handler installation initializes the decrementer to
161   * the correct value.
162   */
163
164  if (!BSP_connect_clock_handler ()) {
165    printk("Unable to initialize system clock\n");
166    rtems_fatal_error_occurred(1);
167  }
168  /* make major/minor avail to others such as shared memory driver */
169 
170  rtems_clock_major = major;
171  rtems_clock_minor = minor;
172
173  return RTEMS_SUCCESSFUL;
174} /* Clock_initialize */
175 
176/*
177 *  Clock_control
178 *
179 *  This routine is the clock device driver control entry point.
180 *
181 *  Input parameters:
182 *    major - clock device major number
183 *    minor - clock device minor number
184 *    parg  - pointer to optional device driver arguments
185 *
186 *  Output parameters:  NONE
187 *
188 *  Return values:
189 *    rtems_device_driver status code
190 */
191
192rtems_device_driver Clock_control(
193  rtems_device_major_number major,
194  rtems_device_minor_number minor,
195  void *pargp
196)
197{
198    rtems_libio_ioctl_args_t *args = pargp;
199 
200    if (args == 0)
201        goto done;
202 
203    Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
204      (rtems_configuration_get_microseconds_per_tick()/1000);
205
206    if      (args->command == rtems_build_name('I', 'S', 'R', ' '))
207      clockIsr(NULL);
208    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
209    {
210                Clock_initialize(major, minor, 0);
211    }
212done:
213    return RTEMS_SUCCESSFUL;
214}
Note: See TracBrowser for help on using the repository browser.