1 /******************************************************************************
3 * Copyright (c) 2020 Intel.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 *******************************************************************************/
20 * @brief This file provides implementation to Timing for XRAN.
23 * @ingroup group_lte_source_xran
24 * @author Intel Corporation
32 #include <immintrin.h>
33 #include "xran_timer.h"
34 #include "xran_printf.h"
35 #include "xran_mlog_lnx.h"
36 #include "xran_lib_mlog_tasks_id.h"
38 #include "xran_fh_o_du.h"
39 #include "xran_common.h"
41 #define NSEC_PER_SEC 1000000000L
42 #define NSEC_PER_USEC 1000L
43 #define THRESHOLD 35 /**< the avg cost of clock_gettime() in ns */
44 #define TIMECOMPENSATION 2 /**< time compensation in us, avg latency of clock_nanosleep */
46 #define SEC_MOD_STOP (60)
48 static struct timespec started_time;
49 static struct timespec last_time;
50 static struct timespec cur_time;
52 static uint64_t curr_tick;
53 static uint64_t last_tick;
55 static struct timespec* p_cur_time = &cur_time;
56 static struct timespec* p_last_time = &last_time;
59 static struct timespec* p_temp_time;
61 static struct timespec sleeptime = {.tv_nsec = 1E3 }; /* 1 us */
63 volatile static unsigned long current_second = 0;
64 static unsigned long started_second = 0;
65 static uint8_t numerlogy = 0;
66 extern uint32_t xran_lib_ota_sym[];
67 extern uint32_t xran_lib_ota_tti[];
68 extern uint32_t xran_lib_ota_sym_idx[];
70 static int debugStop = 0;
71 static int debugStopCount = 0;
73 static long fine_tuning[5][2] =
75 {71428L, 71429L}, /* mu = 0 */
76 {35714L, 35715L}, /* mu = 1 */
77 {0, 0}, /* mu = 2 not supported */
78 {8928L, 8929L}, /* mu = 3 */
79 {0,0 } /* mu = 4 not supported */
82 static uint8_t slots_per_subframe[4] =
90 uint64_t timing_get_current_second(void)
92 return current_second;
95 uint32_t xran_max_ota_sym_idx(uint8_t numerlogy)
97 return (XRAN_NUM_OF_SYMBOL_PER_SLOT * slots_per_subframe[numerlogy] * MSEC_PER_SEC);
100 int timing_set_numerology(uint8_t value)
105 uint8_t timing_get_numerology(void)
110 int timing_set_debug_stop(int value, int count)
113 debugStopCount = count;
116 clock_gettime(CLOCK_REALTIME, &started_time);
117 started_second =started_time.tv_sec;
122 int timing_get_debug_stop(void)
127 void timing_adjust_gps_second(struct timespec* p_time)
129 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
131 if (p_time->tv_nsec >= p_xran_dev_ctx->offset_nsec)
133 p_time->tv_nsec -= p_xran_dev_ctx->offset_nsec;
134 p_time->tv_sec -= p_xran_dev_ctx->offset_sec;
138 p_time->tv_nsec += 1e9 - p_xran_dev_ctx->offset_nsec;
139 p_time->tv_sec -= p_xran_dev_ctx->offset_sec + 1;
144 uint64_t xran_tick(void)
147 __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
148 return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
151 unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_tick)
153 if (curr_tick >= last_tick)
154 return (unsigned long)(curr_tick - last_tick);
156 return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);
158 extern uint16_t xran_getSfnSecStart(void);
160 long poll_next_tick(long interval_ns, unsigned long *used_tick)
162 struct xran_ethdi_ctx *p_eth = xran_ethdi_get_ctx();
163 struct xran_io_cfg *p_io_cfg = &(p_eth->io_cfg);
164 struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
165 struct xran_common_counters* pCnt = &p_xran_dev_ctx->fh_counters;
169 static int counter = 0;
170 static long sym_acc = 0;
171 static long sym_cnt = 0;
175 clock_gettime(CLOCK_REALTIME, p_last_time);
176 last_tick = MLogTick();
177 if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
178 timing_adjust_gps_second(p_last_time);
179 current_second = p_last_time->tv_sec;
183 target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);
186 clock_gettime(CLOCK_REALTIME, p_cur_time);
187 curr_tick = MLogTick();
188 if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))
189 timing_adjust_gps_second(p_cur_time);
190 delta = (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec) - target_time;
191 if(delta > 0 || (delta < 0 && abs(delta) < THRESHOLD)) {
192 if (debugStop &&(debugStopCount > 0) && (pCnt->tx_counter >= debugStopCount)){
194 printf("STOP:[%ld.%09ld], debugStopCount %d, tx_counter %ld\n", p_cur_time->tv_sec, p_cur_time->tv_nsec, debugStopCount, pCnt->tx_counter);
197 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
198 xran_if_current_state = XRAN_STOPPED;
200 if(current_second != p_cur_time->tv_sec){
201 current_second = p_cur_time->tv_sec;
202 xran_updateSfnSecStart();
203 for (i=0; i < XRAN_PORTS_NUM; i++)
205 xran_lib_ota_tti[i] = 0;
206 xran_lib_ota_sym[i] = 0;
207 xran_lib_ota_sym_idx[i] = 0;
211 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
213 if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){
215 uint32_t tti = xran_lib_ota_tti[0];
216 uint32_t slot_id = XranGetSlotNum(tti, SLOTNUM_PER_SUBFRAME(interval_us));
217 uint32_t subframe_id = XranGetSubFrameNum(tti,SLOTNUM_PER_SUBFRAME(interval_us), SUBFRAMES_PER_SYSTEMFRAME);
218 uint32_t frame_id = XranGetFrameNum(tti,xran_getSfnSecStart(),SUBFRAMES_PER_SYSTEMFRAME, SLOTNUM_PER_SUBFRAME(interval_us));
219 printf("STOP:[%ld.%09ld] (%d : %d : %d)\n", p_cur_time->tv_sec, p_cur_time->tv_nsec,frame_id, subframe_id, slot_id);
222 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
223 xran_if_current_state = XRAN_STOPPED;
226 p_cur_time->tv_nsec = 0; // adjust to 1pps
228 xran_lib_ota_sym_idx[0] = XranIncrementSymIdx(xran_lib_ota_sym_idx[0], XRAN_NUM_OF_SYMBOL_PER_SLOT*slots_per_subframe[numerlogy]);
229 for (i=1; i < p_xran_dev_ctx->fh_init.xran_ports; i++)
231 struct xran_device_ctx * p_other_ctx = xran_dev_get_ctx_by_id(i);
232 xran_lib_ota_sym_idx[i] = xran_lib_ota_sym_idx[0] >> (numerlogy - xran_get_conf_numerology(p_other_ctx));
234 /* adjust to sym boundary */
236 sym_acc += fine_tuning[numerlogy][0];
238 sym_acc += fine_tuning[numerlogy][1];
239 /* fine tune to second boundary */
240 if(sym_cnt % 13 == 0)
243 p_cur_time->tv_nsec = sym_acc;
248 if(debugStop && delta < interval_ns*10)
249 MLogTask(PID_TIME_SYSTIME_POLL, (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec), (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec));
251 MLogTask(PID_TIME_SYSTIME_POLL, last_tick, curr_tick);
252 last_tick = curr_tick;
256 p_temp_time = p_last_time;
257 p_last_time = p_cur_time;
258 p_cur_time = p_temp_time;
261 if(likely((xran_if_current_state == XRAN_RUNNING)||(xran_if_current_state == XRAN_OWDM))){
265 if(p_eth->time_wrk_cfg.f)
266 p_eth->time_wrk_cfg.f(p_eth->time_wrk_cfg.arg);
268 if(p_io_cfg->io_sleep)
269 nanosleep(&sleeptime,NULL);
272 *used_tick += get_ticks_diff(t2, t1);
281 long sleep_next_tick(long interval)
283 struct timespec start_time;
284 struct timespec cur_time;
285 //struct timespec target_time_convert;
286 struct timespec sleep_target_time_convert;
288 long sleep_target_time;
291 clock_gettime(CLOCK_REALTIME, &start_time);
292 target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;
293 //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);
294 sleep_target_time = target_time - TIMECOMPENSATION;
295 sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;
296 sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
298 //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;
299 //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
301 clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);
303 clock_gettime(CLOCK_REALTIME, &cur_time);
305 delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;