Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSTestSuitesValidation
0007  *
0008  * @brief This source file contains the definition of SetGetTimecountHandler(),
0009  *   GetTimecountCounter(), and SetTimecountCounter().
0010  */
0011 
0012 /*
0013  * Copyright (C) 2021 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include "tx-support.h"
0042 
0043 #include <rtems/sysinit.h>
0044 #include <rtems/timecounter.h>
0045 #include <rtems/score/atomic.h>
0046 #include <rtems/score/percpu.h>
0047 #include <rtems/score/smpimpl.h>
0048 #include <rtems/score/threaddispatch.h>
0049 
0050 typedef struct {
0051   struct timecounter base;
0052   GetTimecountHandler handler;
0053   Atomic_Ulong counter;
0054 } TimecounterControl;
0055 
0056 static TimecounterControl TimecounterInstance;
0057 
0058 GetTimecountHandler SetGetTimecountHandler( GetTimecountHandler handler )
0059 {
0060   GetTimecountHandler previous;
0061 
0062   previous = TimecounterInstance.handler;
0063   TimecounterInstance.handler = handler;
0064   return previous;
0065 }
0066 
0067 uint32_t GetTimecountCounter( void )
0068 {
0069   return (uint32_t) _Atomic_Load_ulong(
0070     &TimecounterInstance.counter,
0071     ATOMIC_ORDER_RELAXED
0072   );
0073 }
0074 
0075 uint32_t SetTimecountCounter( uint32_t counter )
0076 {
0077   return (uint32_t) _Atomic_Exchange_ulong(
0078     &TimecounterInstance.counter,
0079     counter,
0080     ATOMIC_ORDER_RELAXED
0081   );
0082 }
0083 
0084 static uint32_t GetTimecountSoftware( void )
0085 {
0086   return (uint32_t) _Atomic_Fetch_add_ulong(
0087     &TimecounterInstance.counter,
0088     1,
0089     ATOMIC_ORDER_RELAXED
0090   );
0091 }
0092 
0093 static uint32_t GetTimecountWrapper( struct timecounter *tc )
0094 {
0095   TimecounterControl *self;
0096 
0097   self = (TimecounterControl *) tc;
0098   return ( *self->handler )();
0099 }
0100 
0101 static void InstallTimecounter( void )
0102 {
0103   TimecounterControl *self;
0104 
0105   self = &TimecounterInstance;
0106   self->handler = GetTimecountSoftware;
0107   self->base.tc_get_timecount = GetTimecountWrapper;
0108   self->base.tc_counter_mask = 0xffffffff;
0109   self->base.tc_frequency = SOFTWARE_TIMECOUNTER_FREQUENCY;
0110   self->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 1;
0111   rtems_timecounter_install( &self->base );
0112 }
0113 
0114 RTEMS_SYSINIT_ITEM(
0115   InstallTimecounter,
0116   RTEMS_SYSINIT_DEVICE_DRIVERS,
0117   RTEMS_SYSINIT_ORDER_LAST
0118 );
0119 
0120 static void DoTimecounterTick( void *arg )
0121 {
0122   (void) arg;
0123   _Timecounter_Tick();
0124 }
0125 
0126 void TimecounterTick( void )
0127 {
0128   unsigned long    counter_ticks_per_clock_tick;
0129   Per_CPU_Control *cpu_self;
0130   bool             success;
0131 
0132   counter_ticks_per_clock_tick =
0133     SOFTWARE_TIMECOUNTER_FREQUENCY / rtems_clock_get_ticks_per_second();
0134   cpu_self = _Thread_Dispatch_disable();
0135 
0136   do {
0137     unsigned long old_counter;
0138     unsigned long new_counter;
0139 
0140     old_counter = _Atomic_Load_ulong(
0141       &TimecounterInstance.counter,
0142       ATOMIC_ORDER_RELAXED
0143     );
0144     new_counter = old_counter + counter_ticks_per_clock_tick -
0145       ( old_counter % counter_ticks_per_clock_tick );
0146     success = _Atomic_Compare_exchange_ulong(
0147       &TimecounterInstance.counter,
0148       &old_counter,
0149       new_counter,
0150       ATOMIC_ORDER_RELAXED,
0151       ATOMIC_ORDER_RELAXED
0152     );
0153   } while ( !success );
0154 
0155   DoTimecounterTick( NULL );
0156 #if defined( RTEMS_SMP )
0157   _SMP_Othercast_action( DoTimecounterTick, NULL );
0158 #endif
0159   _Thread_Dispatch_enable( cpu_self );
0160 }