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

4.115
Last change on this file since aff220d was aff220d, checked in by Sebastian Huber <sebastian.huber@…>, on 05/29/15 at 06:59:41

bsps/powerpc: Fix potential integer overflow

Update #2356.

  • Property mode set to 100644
File size: 5.9 KB
RevLine 
[4e8de7e]1/**
2 *  @brief Clock Tick Device Driver
[acc25ee]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.
[4e8de7e]8 */
9
10/*
[ad51436]11 *  COPYRIGHT (c) 1989-2014.
[acc25ee]12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may in
15 *  the file LICENSE in this distribution or at
[c499856]16 *  http://www.rtems.org/license/LICENSE.
[acc25ee]17 *
18 *  Modified to support the MPC750.
19 *  Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
20 */
21
22#include <rtems.h>
23#include <rtems/libio.h>
[4e8de7e]24#include <rtems/clockdrv.h>
[acc25ee]25#include <stdlib.h>                     /* for atexit() */
26#include <assert.h>
27#include <libcpu/c_clock.h>
[3fa48ee]28#include <libcpu/cpuIdent.h>
29#include <libcpu/spr.h>
[9c325fb2]30#include <rtems/bspIo.h>                /* for printk() */
[5930196]31#include <libcpu/powerpc-utility.h>
[75acd9e]32#include <rtems/timecounter.h>
[9c325fb2]33
34#include <bspopts.h>   /* for CLOCK_DRIVER_USE_FAST_IDLE */
[acc25ee]35
[3fa48ee]36SPR_RW(BOOKE_TCR)
37SPR_RW(BOOKE_TSR)
38SPR_RW(BOOKE_DECAR)
39
[cebb89b]40extern int BSP_connect_clock_handler (void);
41
[acc25ee]42/*
43 *  Clock ticks since initialization
44 */
[66c373bf]45volatile uint32_t   Clock_driver_ticks;
[acc25ee]46
47/*
48 *  This is the value programmed into the count down timer.
49 */
[d11b711]50static uint32_t   Clock_Decrementer_value;
51
[75acd9e]52static struct timecounter Clock_TC;
53
54static uint32_t Clock_Get_timecount(struct timecounter *tc)
55{
56  return ppc_time_base();
57}
[acc25ee]58
59void clockOff(void* unused)
60{
[4e8de7e]61  rtems_interrupt_level l;
[3fa48ee]62
63  if ( ppc_cpu_is_bookE() ) {
64    rtems_interrupt_disable(l);
65    _write_BOOKE_TCR(_read_BOOKE_TCR() & ~BOOKE_TCR_DIE);
66    rtems_interrupt_enable(l);
67  } else {
[4e8de7e]68    /*
69     * Nothing to do as we cannot disable all interrupts and
70     * the decrementer interrupt enable is MSR_EE
71     */
[3fa48ee]72  }
[acc25ee]73}
[3fa48ee]74
[acc25ee]75void clockOn(void* unused)
76{
[4e8de7e]77  rtems_interrupt_level l;
[3fa48ee]78
[acc25ee]79  PPC_Set_decrementer( Clock_Decrementer_value );
[3fa48ee]80
81  if ( ppc_cpu_is_bookE() ) {
82    _write_BOOKE_DECAR( Clock_Decrementer_value );
83
84    rtems_interrupt_disable(l);
85
86    /* clear pending/stale irq */
87    _write_BOOKE_TSR( BOOKE_TSR_DIS );
88    /* enable */
89    _write_BOOKE_TCR( _read_BOOKE_TCR() | BOOKE_TCR_DIE );
90
91    rtems_interrupt_enable(l);
92
93  }
[acc25ee]94}
95
[56758965]96static void clockHandler(void)
97{
[3c4d041c]98  #if (CLOCK_DRIVER_USE_FAST_IDLE == 1)
[75acd9e]99    rtems_interrupt_level level;
100    uint32_t tb;
101
102    rtems_interrupt_disable(level);
103
104    tb = ppc_time_base();
105    rtems_timecounter_tick();
106
107    while (
[e3be6915]108      _Thread_Heir == _Thread_Executing
109        && _Thread_Executing->Start.entry_point
[ad51436]110          == (Thread_Entry) rtems_configuration_get_idle_task()
[75acd9e]111    ) {
112      tb += Clock_Decrementer_value;
113      ppc_set_time_base( tb );
114      rtems_timecounter_tick();
115    }
[9c325fb2]116
[75acd9e]117    rtems_interrupt_enable(level);
[9c325fb2]118  #else
[75acd9e]119    rtems_timecounter_tick();
[9c325fb2]120  #endif
[56758965]121}
122
123static void (*clock_handler)(void);
124
[acc25ee]125/*
126 *  Clock_isr
127 *
128 *  This is the clock tick interrupt handler.
129 *
130 *  Input parameters:
131 *    vector - vector number
132 *
133 *  Output parameters:  NONE
134 *
135 *  Return values:      NONE
136 *
137 */
[d3d9ef37]138void clockIsr(void *unused)
[acc25ee]139{
[4e8de7e]140  int decr;
141
[acc25ee]142  /*
143   *  The driver has seen another tick.
144   */
[c984fb3]145  do {
[4e8de7e]146    register uint32_t flags;
147
148    rtems_interrupt_disable(flags);
149      __asm__ volatile (
150        "mfdec %0; add %0, %0, %1; mtdec %0"
151        : "=&r"(decr)
152        : "r"(Clock_Decrementer_value)
153      );
154    rtems_interrupt_enable(flags);
155
156    Clock_driver_ticks += 1;
157    /*
158     *  Real Time Clock counter/timer is set to automatically reload.
159     */
160    clock_handler();
[c984fb3]161  } while ( decr < 0 );
[acc25ee]162}
163
[3fa48ee]164/*
165 *  Clock_isr_bookE
166 *
167 *  This is the clock tick interrupt handler
168 *  for bookE CPUs. For efficiency reasons we
169 *  provide a separate handler rather than
170 *  checking the CPU type each time.
171 */
172void clockIsrBookE(void *unused)
173{
174  /* Note: TSR bit has already been cleared in the exception handler */
175
176  /*
177   *  The driver has seen another tick.
178   */
179
180  Clock_driver_ticks += 1;
181
182  /*
183   *  Real Time Clock counter/timer is set to automatically reload.
184   */
185  clock_handler();
186}
187
[acc25ee]188int clockIsOn(void* unused)
189{
[4e8de7e]190  uint32_t   msr_value;
[acc25ee]191
[9c325fb2]192  _CPU_MSR_GET( msr_value );
[3fa48ee]193
[9c325fb2]194  if ( ppc_cpu_is_bookE() && ! (_read_BOOKE_TCR() & BOOKE_TCR_DIE) )
195    msr_value = 0;
[3fa48ee]196
[9c325fb2]197  if (msr_value & MSR_EE) return 1;
[3fa48ee]198
[9c325fb2]199  return 0;
[acc25ee]200}
201
202/*
203 *  Clock_exit
204 *
205 *  This routine allows the clock driver to exit by masking the interrupt and
206 *  disabling the clock's counter.
207 */
208void Clock_exit( void )
209{
[0dd1d44]210  (void) BSP_disconnect_clock_handler ();
[acc25ee]211}
[359e537]212
[acc25ee]213/*
214 *  Clock_initialize
215 *
216 *  This routine initializes the clock driver.
217 */
218rtems_device_driver Clock_initialize(
219  rtems_device_major_number major,
220  rtems_device_minor_number minor,
221  void *pargp
222)
223{
[4e8de7e]224  rtems_interrupt_level l,tcr;
[3fa48ee]225
[95273a6]226  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
[d11b711]227            rtems_configuration_get_milliseconds_per_tick();
228
[359e537]229  /* set the decrementer now, prior to installing the handler
[c984fb3]230   * so no interrupts will happen in a while.
231   */
232  PPC_Set_decrementer( (unsigned)-1 );
233
[3fa48ee]234  /* On a bookE CPU the decrementer works differently. It doesn't
235   * count past zero but we can enable auto-reload :-)
236   */
237  if ( ppc_cpu_is_bookE() ) {
238
239    rtems_interrupt_disable(l);
240
[4e8de7e]241      tcr  = _read_BOOKE_TCR();
242      tcr |= BOOKE_TCR_ARE;
243      tcr &= ~BOOKE_TCR_DIE;
244      _write_BOOKE_TCR(tcr);
[3fa48ee]245
246    rtems_interrupt_enable(l);
247  }
[f7588eba]248
[75acd9e]249  Clock_TC.tc_get_timecount = Clock_Get_timecount;
250  Clock_TC.tc_counter_mask = 0xffffffff;
[aff220d]251  Clock_TC.tc_frequency = (UINT64_C(1000) * BSP_bus_frequency) / BSP_time_base_divisor;
[75acd9e]252  Clock_TC.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
253  rtems_timecounter_install(&Clock_TC);
254
[4e8de7e]255  /*
256   * If a decrementer exception was pending, it is cleared by
[c984fb3]257   * executing the default (nop) handler at this point;
258   * The next exception will then be taken by our clock handler.
259   * Clock handler installation initializes the decrementer to
260   * the correct value.
261   */
[56758965]262  clock_handler = clockHandler;
[acc25ee]263  if (!BSP_connect_clock_handler ()) {
264    printk("Unable to initialize system clock\n");
265    rtems_fatal_error_occurred(1);
266  }
267
268  return RTEMS_SUCCESSFUL;
269} /* Clock_initialize */
Note: See TracBrowser for help on using the repository browser.