File indexing completed on 2025-05-11 08:23:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 #include <bsp.h>
0046 #include <bsp/irq-generic.h>
0047 #include <bspopts.h>
0048 #include <libcpu/cpuModel.h>
0049 #include <assert.h>
0050 #include <rtems/timecounter.h>
0051 #ifdef RTEMS_SMP
0052 #include <rtems/score/smpimpl.h>
0053 #endif
0054
0055 #define CLOCK_VECTOR 0
0056
0057 volatile uint32_t pc386_microseconds_per_isr;
0058 volatile uint32_t pc386_isrs_per_tick;
0059 uint32_t pc386_clock_click_count;
0060
0061
0062 void Clock_isr(void *param);
0063 static void Clock_isr_handler(void *param);
0064
0065
0066
0067
0068
0069
0070
0071
0072 static uint64_t pc586_tsc_frequency;
0073
0074 static struct timecounter pc386_tc;
0075
0076
0077 #define CLOCK_DRIVER_ISRS_PER_TICK 1
0078 #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE pc386_isrs_per_tick
0079
0080 extern volatile uint32_t Clock_driver_ticks;
0081
0082 #define READ_8254( _lsb, _msb ) \
0083 do { outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); \
0084 inport_byte(TIMER_CNTR0, _lsb); \
0085 inport_byte(TIMER_CNTR0, _msb); \
0086 } while (0)
0087
0088
0089 #ifdef RTEMS_SMP
0090 #define Clock_driver_support_at_tick(arg) \
0091 do { \
0092 Processor_mask targets; \
0093 _Processor_mask_Assign(&targets, _SMP_Get_online_processors()); \
0094 _Processor_mask_Clear(&targets, _SMP_Get_current_processor()); \
0095 _SMP_Multicast_action(&targets, rtems_timecounter_tick, NULL); \
0096 } while (0)
0097 #endif
0098
0099 static uint32_t pc386_get_timecount_tsc(struct timecounter *tc)
0100 {
0101 return (uint32_t)rdtsc();
0102 }
0103
0104 static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
0105 {
0106 uint32_t irqs;
0107 uint8_t lsb, msb;
0108 rtems_interrupt_lock_context lock_context;
0109
0110
0111
0112
0113
0114 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0115
0116 READ_8254(lsb, msb);
0117 irqs = Clock_driver_ticks;
0118
0119 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0120
0121 return (irqs + 1) * pc386_microseconds_per_isr - ((msb << 8) | lsb);
0122 }
0123
0124
0125
0126
0127
0128
0129 static void calibrate_tsc(void)
0130 {
0131 uint64_t begin_time;
0132 uint8_t lsb, msb;
0133 uint32_t max_timer_value;
0134 uint32_t last_tick, cur_tick;
0135 int32_t diff, remaining;
0136
0137
0138 outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC);
0139
0140 outport_byte(TIMER_CNTR0, 0);
0141 outport_byte(TIMER_CNTR0, 0);
0142
0143 max_timer_value = 0xffff;
0144
0145 remaining = TIMER_TICK;
0146
0147 begin_time = rdtsc();
0148 READ_8254(lsb, msb);
0149 last_tick = (msb << 8) | lsb;
0150 while(remaining > 0) {
0151 READ_8254(lsb, msb);
0152 cur_tick = (msb << 8) | lsb;
0153
0154 diff = last_tick - cur_tick;
0155 last_tick = cur_tick;
0156 if (diff < 0) {
0157 diff += max_timer_value;
0158 }
0159 remaining -= diff;
0160 }
0161
0162 pc586_tsc_frequency = rdtsc() - begin_time;
0163
0164 #if 0
0165 printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency ));
0166 #endif
0167 }
0168
0169 static void clockOn(void)
0170 {
0171
0172
0173
0174
0175
0176 if ( x86_has_tsc() ) {
0177 calibrate_tsc();
0178 }
0179
0180 rtems_interrupt_lock_context lock_context;
0181 pc386_isrs_per_tick = 1;
0182 pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
0183
0184 while (US_TO_TICK(pc386_microseconds_per_isr) > 65535) {
0185 pc386_isrs_per_tick *= 10;
0186 pc386_microseconds_per_isr /= 10;
0187 }
0188 pc386_clock_click_count = US_TO_TICK(pc386_microseconds_per_isr);
0189
0190 #if 0
0191 printk( "configured usecs per tick=%d \n",
0192 rtems_configuration_get_microseconds_per_tick() );
0193 printk( "Microseconds per ISR =%d\n", pc386_microseconds_per_isr );
0194 printk( "final ISRs per=%d\n", pc386_isrs_per_tick );
0195 printk( "final timer counts=%d\n", pc386_clock_click_count );
0196 #endif
0197
0198 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0199 outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
0200 outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 0 & 0xff);
0201 outport_byte(TIMER_CNTR0, pc386_clock_click_count >> 8 & 0xff);
0202 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0203
0204 bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER );
0205 }
0206
0207 bool Clock_isr_enabled = false;
0208 static void Clock_isr_handler(void *param)
0209 {
0210 if ( Clock_isr_enabled )
0211 Clock_isr( param );
0212 }
0213
0214 void Clock_driver_install_handler(void)
0215 {
0216 rtems_status_code status;
0217
0218 status = rtems_interrupt_handler_install(
0219 BSP_PERIODIC_TIMER,
0220 "ckinit",
0221 RTEMS_INTERRUPT_UNIQUE,
0222 Clock_isr_handler,
0223 NULL
0224 );
0225 assert(status == RTEMS_SUCCESSFUL);
0226 clockOn();
0227 }
0228
0229 #define Clock_driver_support_set_interrupt_affinity(online_processors) \
0230 do { \
0231 \
0232 (void) online_processors; \
0233 } while (0)
0234
0235 void Clock_driver_support_initialize_hardware(void)
0236 {
0237 bool use_tsc = false;
0238 bool use_8254 = false;
0239
0240 #if (CLOCK_DRIVER_USE_TSC == 1)
0241 use_tsc = true;
0242 #endif
0243
0244 #if (CLOCK_DRIVER_USE_8254 == 1)
0245 use_8254 = true;
0246 #endif
0247
0248 if ( !use_tsc && !use_8254 ) {
0249 if ( x86_has_tsc() ) use_tsc = true;
0250 else use_8254 = true;
0251 }
0252
0253 if ( use_8254 ) {
0254
0255 pc386_tc.tc_get_timecount = pc386_get_timecount_i8254;
0256 pc386_tc.tc_counter_mask = 0xffffffff;
0257 pc386_tc.tc_frequency = TIMER_TICK;
0258 } else {
0259
0260 pc386_tc.tc_get_timecount = pc386_get_timecount_tsc;
0261 pc386_tc.tc_counter_mask = 0xffffffff;
0262 pc386_tc.tc_frequency = pc586_tsc_frequency;
0263 }
0264
0265 pc386_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0266 rtems_timecounter_install(&pc386_tc);
0267 Clock_isr_enabled = true;
0268 }
0269
0270 #include "../../../shared/dev/clock/clockimpl.h"