Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSDriverClockImpl
0007  *
0008  * @brief This header file contains the shared Clock Driver implementation.
0009  *
0010  * This header file shall only be included by a particular Clock Driver
0011  * implementation source file.
0012  */
0013 
0014 /*
0015  *  COPYRIGHT (c) 1989-2014.
0016  *  On-Line Applications Research Corporation (OAR).
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #include <stdlib.h>
0041 
0042 #include <bsp.h>
0043 #include <rtems/clockdrv.h>
0044 #include <rtems/score/percpu.h>
0045 #include <rtems/score/processormaskimpl.h>
0046 #include <rtems/score/smpimpl.h>
0047 #include <rtems/score/timecounter.h>
0048 #include <rtems/score/thread.h>
0049 #include <rtems/score/watchdogimpl.h>
0050 
0051 /**
0052  * @defgroup RTEMSDriverClockImpl Clock Driver Implementation
0053  *
0054  * @ingroup RTEMSDriverClock
0055  *
0056  * @brief This group contains the Clock Driver implementation.
0057  */
0058 
0059 #ifdef Clock_driver_nanoseconds_since_last_tick
0060 #error "Update driver to use the timecounter instead of nanoseconds extension"
0061 #endif
0062 
0063 #if CLOCK_DRIVER_USE_FAST_IDLE && CLOCK_DRIVER_ISRS_PER_TICK
0064 #error "Fast Idle PLUS n ISRs per tick is not supported"
0065 #endif
0066 
0067 #if defined(BSP_FEATURE_IRQ_EXTENSION) || \
0068     (CPU_SIMPLE_VECTORED_INTERRUPTS != TRUE)
0069 typedef void * Clock_isr_argument;
0070 #else
0071 typedef rtems_vector_number Clock_isr_argument;
0072 #endif
0073 
0074 /**
0075  * @brief Do nothing by default.
0076  */
0077 #ifndef Clock_driver_support_install_isr
0078   #define Clock_driver_support_install_isr(isr)
0079 #endif
0080 
0081 /**
0082  * @brief This method is rarely used so default it.
0083  */
0084 #ifndef Clock_driver_support_find_timer
0085   #define Clock_driver_support_find_timer()
0086 #endif
0087 
0088 /**
0089  * @brief Do nothing by default.
0090  */
0091 #ifndef Clock_driver_support_at_tick
0092   #define Clock_driver_support_at_tick( arg ) do { (void) arg; } while (0)
0093 #endif
0094 
0095 /**
0096  * @brief Do nothing by default.
0097  */
0098 #ifndef Clock_driver_support_set_interrupt_affinity
0099   #define Clock_driver_support_set_interrupt_affinity(online_processors)
0100 #endif
0101 
0102 /*
0103  * A specialized clock driver may use for example rtems_timecounter_tick_simple()
0104  * instead of the default.
0105  */
0106 #ifndef Clock_driver_timecounter_tick
0107 static void Clock_driver_timecounter_tick( Clock_isr_argument arg )
0108 {
0109   (void) arg;
0110 #if defined(CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER)
0111   rtems_clock_tick();
0112 #elif defined(RTEMS_SMP) && defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
0113   uint32_t cpu_max;
0114   uint32_t cpu_index;
0115 
0116   cpu_max = _SMP_Get_processor_maximum();
0117 
0118   for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
0119     Per_CPU_Control *cpu;
0120 
0121     cpu = _Per_CPU_Get_by_index( cpu_index );
0122 
0123     if ( _Per_CPU_Is_boot_processor( cpu ) ) {
0124       rtems_timecounter_tick();
0125     } else if ( _Processor_mask_Is_set( _SMP_Get_online_processors(), cpu_index ) ) {
0126       _Watchdog_Tick( cpu );
0127     }
0128   }
0129 #else
0130   rtems_timecounter_tick();
0131 #endif
0132 }
0133 #endif
0134 
0135 /**
0136  * @brief ISRs until next clock tick
0137  */
0138 #if CLOCK_DRIVER_ISRS_PER_TICK
0139   volatile uint32_t  Clock_driver_isrs;
0140 #endif
0141 
0142 /**
0143  * @brief Clock ticks since initialization
0144  */
0145 volatile uint32_t    Clock_driver_ticks;
0146 
0147 #ifdef Clock_driver_support_shutdown_hardware
0148 #error "Clock_driver_support_shutdown_hardware() is no longer supported"
0149 #endif
0150 
0151 #if CLOCK_DRIVER_USE_FAST_IDLE
0152 static bool _Clock_Has_watchdogs(const Per_CPU_Control *cpu)
0153 {
0154   size_t i;
0155 
0156   for (i = 0; i < RTEMS_ARRAY_SIZE(cpu->Watchdog.Header); ++i) {
0157     if (_Watchdog_Header_first(&cpu->Watchdog.Header[i]) != NULL) {
0158       return true;
0159     }
0160   }
0161 
0162   return false;
0163 }
0164 #endif
0165 
0166 /**
0167  *  @brief Clock_isr
0168  *
0169  *  This is the clock tick interrupt handler.
0170  *
0171  *  @param arg is the clock interrupt handler argument.
0172  */
0173 void Clock_isr( Clock_isr_argument arg );
0174 void Clock_isr( Clock_isr_argument arg )
0175 {
0176   /*
0177    *  Accurate count of ISRs
0178    */
0179   Clock_driver_ticks += 1;
0180 
0181   #if CLOCK_DRIVER_USE_FAST_IDLE
0182     {
0183       Clock_driver_timecounter_tick( arg );
0184 
0185       if (_SMP_Get_processor_maximum() == 1) {
0186         struct timecounter *tc;
0187         uint64_t            us_per_tick;
0188         uint32_t            interval;
0189         Per_CPU_Control    *cpu_self;
0190 
0191         cpu_self = _Per_CPU_Get();
0192         tc = _Timecounter;
0193         us_per_tick = rtems_configuration_get_microseconds_per_tick();
0194         interval = (uint32_t) ((tc->tc_frequency * us_per_tick) / 1000000);
0195 
0196         while (
0197           cpu_self->thread_dispatch_disable_level == cpu_self->isr_nest_level
0198             && cpu_self->heir == cpu_self->executing
0199             && cpu_self->executing->is_idle
0200             && _Clock_Has_watchdogs(cpu_self)
0201         ) {
0202           ISR_lock_Context lock_context;
0203 
0204           _Timecounter_Acquire(&lock_context);
0205           _Timecounter_Tick_simple(
0206             interval,
0207             (*tc->tc_get_timecount)(tc),
0208             &lock_context
0209           );
0210         }
0211       }
0212 
0213       Clock_driver_support_at_tick( arg );
0214     }
0215   #else
0216     /*
0217      *  Do the hardware specific per-tick action.
0218      *
0219      *  The counter/timer may or may not be set to automatically reload.
0220      */
0221     Clock_driver_support_at_tick( arg );
0222 
0223     #if CLOCK_DRIVER_ISRS_PER_TICK
0224       /*
0225        *  The driver is multiple ISRs per clock tick.
0226        */
0227       if ( !Clock_driver_isrs ) {
0228         Clock_driver_timecounter_tick( arg );
0229 
0230         Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK_VALUE;
0231       }
0232       Clock_driver_isrs--;
0233     #else
0234       /*
0235        *  The driver is one ISR per clock tick.
0236        */
0237       Clock_driver_timecounter_tick( arg );
0238     #endif
0239   #endif
0240 }
0241 
0242 void _Clock_Initialize( void )
0243 {
0244   Clock_driver_ticks = 0;
0245 
0246   /*
0247    *  Find timer -- some BSPs search buses for hardware timer
0248    */
0249   Clock_driver_support_find_timer();
0250 
0251   /*
0252    *  Install vector
0253    */
0254   Clock_driver_support_install_isr( Clock_isr );
0255 
0256   #ifdef RTEMS_SMP
0257     Clock_driver_support_set_interrupt_affinity(
0258       _SMP_Get_online_processors()
0259     );
0260   #endif
0261 
0262   /*
0263    *  Now initialize the hardware that is the source of the tick ISR.
0264    */
0265   Clock_driver_support_initialize_hardware();
0266 
0267   /*
0268    *  If we are counting ISRs per tick, then initialize the counter.
0269    */
0270   #if CLOCK_DRIVER_ISRS_PER_TICK
0271     Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK_VALUE;
0272   #endif
0273 }