* INTC Contribution to the O-RAN F Release for O-DU Low
[o-du/phy.git] / fhi_lib / lib / src / xran_timer.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2020 Intel.
4 *
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
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
17 *******************************************************************************/
18
19 /**
20  * @brief This file provides implementation to Timing for XRAN.
21  *
22  * @file xran_timer.c
23  * @ingroup group_lte_source_xran
24  * @author Intel Corporation
25  *
26  **/
27
28 #include <time.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
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"
37 #include "ethdi.h"
38 #include "xran_fh_o_du.h"
39 #include "xran_common.h"
40
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 */
45
46 #define SEC_MOD_STOP (60)
47
48 static struct timespec started_time;
49 static struct timespec last_time;
50 static struct timespec cur_time;
51
52 static uint64_t  curr_tick;
53 static uint64_t  last_tick;
54
55 static struct timespec* p_cur_time = &cur_time;
56 static struct timespec* p_last_time = &last_time;
57
58
59 static struct timespec* p_temp_time;
60
61 static struct timespec sleeptime = {.tv_nsec = 1E3 }; /* 1 us */
62
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[];
69
70 static int debugStop = 0;
71 static int debugStopCount = 0;
72
73 static long fine_tuning[5][2] =
74 {
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 */
80 };
81
82 static uint8_t slots_per_subframe[4] =
83 {
84     1,  /* mu = 0 */
85     2,  /* mu = 1 */
86     4,  /* mu = 2 */
87     8,  /* mu = 3 */
88 };
89
90 uint64_t timing_get_current_second(void)
91 {
92     return current_second;
93 }
94
95 uint32_t xran_max_ota_sym_idx(uint8_t numerlogy)
96 {
97     return (XRAN_NUM_OF_SYMBOL_PER_SLOT * slots_per_subframe[numerlogy] * MSEC_PER_SEC);
98 }
99
100 int timing_set_numerology(uint8_t value)
101 {
102     numerlogy = value;
103     return numerlogy;
104 }
105 uint8_t timing_get_numerology(void)
106 {
107     return numerlogy;
108 }
109
110 int timing_set_debug_stop(int value, int count)
111 {
112     debugStop = value;
113     debugStopCount = count;
114
115     if(debugStop){
116         clock_gettime(CLOCK_REALTIME, &started_time);
117         started_second =started_time.tv_sec;
118     }
119     return debugStop;
120 }
121
122 int timing_get_debug_stop(void)
123 {
124     return debugStop;
125 }
126
127 void timing_adjust_gps_second(struct timespec* p_time)
128 {
129     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
130
131     if (p_time->tv_nsec >= p_xran_dev_ctx->offset_nsec)
132     {
133         p_time->tv_nsec -= p_xran_dev_ctx->offset_nsec;
134         p_time->tv_sec -= p_xran_dev_ctx->offset_sec;
135     }
136     else
137     {
138         p_time->tv_nsec += 1e9 - p_xran_dev_ctx->offset_nsec;
139         p_time->tv_sec -= p_xran_dev_ctx->offset_sec + 1;
140     }
141
142     return;
143 }
144 uint64_t xran_tick(void)
145 {
146     uint32_t hi, lo;
147     __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
148     return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );
149 }
150
151 unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_tick)
152 {
153     if (curr_tick >= last_tick)
154         return (unsigned long)(curr_tick - last_tick);
155     else
156         return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);
157 }
158 extern uint16_t xran_getSfnSecStart(void);
159
160 long poll_next_tick(long interval_ns, unsigned long *used_tick)
161 {
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;
166
167     long target_time;
168     long delta, tm_threshold_high, tm_threshold_low;//Update tm threhsolds
169     static int counter = 0;
170     static long sym_acc = 0;
171     static long sym_cnt = 0;
172     int i;
173
174     if(counter == 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;
180        counter = 1;
181     }
182
183     target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);
184
185     while(1) {
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         tm_threshold_high = interval_ns * N_SYM_PER_SLOT * 2;//2 slots
192         tm_threshold_low = interval_ns * 2; //2 symbols
193         //add tm exception handling
194         if (unlikely(labs(delta) > tm_threshold_low)) {
195             print_dbg("poll_next_tick exceed 2 symbols threshold with delta:%ld(ns), used_tick:%ld(tick) \n", delta, used_tick);
196             pCnt->timer_missed_sym++;
197             if(unlikely(labs(delta) > tm_threshold_high)) {
198                 print_dbg("poll_next_tick exceed 2 slots threshold, stop xran! delta:%ld(ns), used_tick:%ld(tick) \n", delta, used_tick);
199                 //xran_if_current_state = XRAN_STOPPED;
200                 pCnt->timer_missed_slot++;
201             }
202         }
203         if(delta > 0 || (delta < 0 && labs(delta) < THRESHOLD)) {
204             if (debugStop &&(debugStopCount > 0) && (pCnt->tx_counter >= debugStopCount)){
205                 uint64_t t1;
206                 printf("STOP:[%ld.%09ld], debugStopCount %d, tx_counter %ld\n", p_cur_time->tv_sec, p_cur_time->tv_nsec, debugStopCount, pCnt->tx_counter);
207                 t1 = MLogTick();
208                 rte_pause();
209                 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
210                 xran_if_current_state = XRAN_STOPPED;
211             }
212             if(current_second != p_cur_time->tv_sec){
213                 current_second = p_cur_time->tv_sec;
214                 xran_updateSfnSecStart();
215                 for (i=0; i < XRAN_PORTS_NUM; i++)
216                 {
217                     xran_lib_ota_tti[i] = 0;
218                     xran_lib_ota_sym[i] = 0;
219                     xran_lib_ota_sym_idx[i] = 0;
220                 }
221                 sym_cnt = 0;
222                 sym_acc = 0;
223                 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);
224                 if(debugStop){
225                     if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){
226                         uint64_t t1;
227                         uint32_t tti = xran_lib_ota_tti[0];
228                         uint32_t slot_id     = XranGetSlotNum(tti, SLOTNUM_PER_SUBFRAME(interval_us));
229                         uint32_t subframe_id = XranGetSubFrameNum(tti,SLOTNUM_PER_SUBFRAME(interval_us),  SUBFRAMES_PER_SYSTEMFRAME);
230                         uint32_t frame_id    = XranGetFrameNum(tti,xran_getSfnSecStart(),SUBFRAMES_PER_SYSTEMFRAME, SLOTNUM_PER_SUBFRAME(interval_us));
231                         printf("STOP:[%ld.%09ld] (%d : %d : %d)\n", p_cur_time->tv_sec, p_cur_time->tv_nsec,frame_id, subframe_id, slot_id);
232                         t1 = MLogTick();
233                         rte_pause();
234                         MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());
235                         xran_if_current_state = XRAN_STOPPED;
236                     }
237                 }
238                 p_cur_time->tv_nsec = 0; // adjust to 1pps
239             } else {
240                 xran_lib_ota_sym_idx[0] = XranIncrementSymIdx(xran_lib_ota_sym_idx[0], XRAN_NUM_OF_SYMBOL_PER_SLOT*slots_per_subframe[numerlogy]);
241                 for (i=1; i < p_xran_dev_ctx->fh_init.xran_ports; i++)
242                 {
243                     struct xran_device_ctx * p_other_ctx = xran_dev_get_ctx_by_id(i);
244                     if(p_other_ctx)
245                     xran_lib_ota_sym_idx[i] = xran_lib_ota_sym_idx[0] >> (numerlogy - xran_get_conf_numerology(p_other_ctx));
246                 }
247                 /* adjust to sym boundary */
248                 if(sym_cnt & 1)
249                     sym_acc +=  fine_tuning[numerlogy][0];
250                 else
251                     sym_acc +=  fine_tuning[numerlogy][1];
252                 /* fine tune to second boundary */
253                 if(sym_cnt % 13 == 0)
254                     sym_acc += 1;
255
256                 p_cur_time->tv_nsec = sym_acc;
257                 sym_cnt++;
258             }
259
260 #ifdef USE_PTP_TIME
261             if(debugStop && delta < interval_ns*10)
262                 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));
263 #else
264             MLogXRANTask(PID_TIME_SYSTIME_POLL, last_tick, curr_tick);
265             last_tick = curr_tick;
266 #endif
267
268
269             p_temp_time = p_last_time;
270             p_last_time = p_cur_time;
271             p_cur_time  = p_temp_time;
272             break;
273         } else {
274             if(likely((xran_if_current_state == XRAN_RUNNING)||(xran_if_current_state == XRAN_OWDM))){
275                 uint64_t t1, t2;
276                 t1 = xran_tick();
277
278                 if(p_eth->time_wrk_cfg.f)
279                     p_eth->time_wrk_cfg.f(p_eth->time_wrk_cfg.arg);
280
281                 if(p_io_cfg->io_sleep)
282                     nanosleep(&sleeptime,NULL);
283
284                 t2 = xran_tick();
285                 *used_tick += get_ticks_diff(t2, t1);
286             }
287
288         }
289   }
290
291   return delta;
292 }
293
294 long sleep_next_tick(long interval)
295 {
296    struct timespec start_time;
297    struct timespec cur_time;
298    //struct timespec target_time_convert;
299    struct timespec sleep_target_time_convert;
300    long target_time;
301    long sleep_target_time;
302    long delta;
303
304    clock_gettime(CLOCK_REALTIME, &start_time);
305    target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;
306    //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);
307    sleep_target_time = target_time - TIMECOMPENSATION;
308    sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;
309    sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
310
311    //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;
312    //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;
313
314    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);
315
316    clock_gettime(CLOCK_REALTIME, &cur_time);
317
318    delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;
319
320    return delta;
321 }
322
323
324