2390b7e3af3e728c2a5bede5c89ccb2fa198f64a
[o-du/phy.git] / fhi_lib / lib / src / xran_timer.c
1 /******************************************************************************\r
2 *\r
3 *   Copyright (c) 2019 Intel.\r
4 *\r
5 *   Licensed under the Apache License, Version 2.0 (the "License");\r
6 *   you may not use this file except in compliance with the License.\r
7 *   You may obtain a copy of the License at\r
8 *\r
9 *       http://www.apache.org/licenses/LICENSE-2.0\r
10 *\r
11 *   Unless required by applicable law or agreed to in writing, software\r
12 *   distributed under the License is distributed on an "AS IS" BASIS,\r
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14 *   See the License for the specific language governing permissions and\r
15 *   limitations under the License.\r
16 *\r
17 *******************************************************************************/\r
18 \r
19 /**\r
20  * @brief This file provides implementation to Timing for XRAN.\r
21  *\r
22  * @file xran_timer.c\r
23  * @ingroup group_lte_source_xran\r
24  * @author Intel Corporation\r
25  *\r
26  **/\r
27 \r
28 #include <time.h>\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <stdint.h>\r
32 \r
33 #include "xran_timer.h"\r
34 #include "xran_printf.h"\r
35 #include "xran_mlog_lnx.h"\r
36 #include "xran_lib_mlog_tasks_id.h"\r
37 #include "ethdi.h"\r
38 #include "xran_fh_o_du.h"\r
39 #include "xran_common.h"\r
40 \r
41 #define NSEC_PER_SEC  1000000000L\r
42 #define NSEC_PER_USEC 1000L\r
43 #define THRESHOLD        35  /**< the avg cost of clock_gettime() in ns */\r
44 #define TIMECOMPENSATION 2   /**< time compensation in us, avg latency of clock_nanosleep */\r
45 \r
46 #define SEC_MOD_STOP (60)\r
47 \r
48 static struct timespec started_time;\r
49 static struct timespec last_time;\r
50 static struct timespec cur_time;\r
51 \r
52 static uint64_t  curr_tick;\r
53 static uint64_t  last_tick;\r
54 \r
55 static struct timespec* p_cur_time = &cur_time;\r
56 static struct timespec* p_last_time = &last_time;\r
57 \r
58 \r
59 static struct timespec* p_temp_time;\r
60 \r
61 static unsigned long current_second = 0;\r
62 static unsigned long started_second = 0;\r
63 static uint8_t numerlogy = 0;\r
64 extern uint32_t xran_lib_ota_sym;\r
65 extern uint32_t xran_lib_ota_tti;\r
66 extern uint32_t xran_lib_ota_sym_idx;\r
67 \r
68 static int debugStop = 0;\r
69 static int debugStopCount = 0;\r
70 \r
71 static long fine_tuning[5][2] =\r
72 {\r
73     {71428L, 71429L},  /* mu = 0 */\r
74     {35714L, 35715L},  /* mu = 1 */\r
75     {0, 0},            /* mu = 2 not supported */\r
76     {8928L, 8929L},    /* mu = 3 */\r
77     {0,0  }            /* mu = 4 not supported */\r
78 };\r
79 \r
80 static uint8_t slots_per_subframe[4] =\r
81 {\r
82     1,  /* mu = 0 */\r
83     2,  /* mu = 1 */\r
84     4,  /* mu = 2 */\r
85     8,  /* mu = 3 */\r
86 };\r
87 \r
88 uint64_t timing_get_current_second(void)\r
89 {\r
90     return current_second;\r
91 }\r
92 \r
93 int timing_set_numerology(uint8_t value)\r
94 {\r
95     numerlogy = value;\r
96     return numerlogy;\r
97 }\r
98 \r
99 int timing_set_debug_stop(int value, int count)\r
100 {\r
101     debugStop = value;\r
102     debugStopCount = count;\r
103 \r
104     if(debugStop){\r
105         clock_gettime(CLOCK_REALTIME, &started_time);\r
106         started_second =started_time.tv_sec;\r
107     }\r
108     return debugStop;\r
109 }\r
110 \r
111 int timing_get_debug_stop(void)\r
112 {\r
113     return debugStop;\r
114 }\r
115 \r
116 void timing_adjust_gps_second(struct timespec* p_time)\r
117 {\r
118     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();\r
119 \r
120     long nsec = p_time->tv_nsec + p_xran_dev_ctx->offset_nsec;\r
121     p_time->tv_sec += p_xran_dev_ctx->offset_sec;\r
122     if (nsec >= 1e9)\r
123     {\r
124         nsec -=1e9;\r
125         p_time->tv_sec += 1;\r
126     }\r
127     p_time->tv_nsec = nsec;\r
128 \r
129     return;\r
130 }\r
131 uint64_t xran_tick(void)\r
132 {\r
133     uint32_t hi, lo;\r
134     __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));\r
135     return ( (uint64_t)lo)|( ((uint64_t)hi)<<32 );\r
136 }\r
137 \r
138 unsigned long get_ticks_diff(unsigned long curr_tick, unsigned long last_tick)\r
139 {\r
140     if (curr_tick >= last_tick)\r
141         return (unsigned long)(curr_tick - last_tick);\r
142     else\r
143         return (unsigned long)(0xFFFFFFFFFFFFFFFF - last_tick + curr_tick);\r
144 }\r
145 \r
146 long poll_next_tick(long interval_ns, unsigned long *used_tick)\r
147 {\r
148     struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();\r
149     long target_time;\r
150     long delta;\r
151     static int counter = 0;\r
152     static long sym_acc = 0;\r
153     static long sym_cnt = 0;\r
154 \r
155     if(counter == 0) {\r
156        clock_gettime(CLOCK_REALTIME, p_last_time);\r
157        last_tick = MLogTick();\r
158        if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))\r
159            timing_adjust_gps_second(p_last_time);\r
160        current_second = p_last_time->tv_sec;\r
161        counter = 1;\r
162     }\r
163 \r
164     target_time = (p_last_time->tv_sec * NSEC_PER_SEC + p_last_time->tv_nsec + interval_ns);\r
165 \r
166     while(1) {\r
167         clock_gettime(CLOCK_REALTIME, p_cur_time);\r
168         curr_tick = MLogTick();\r
169         if(unlikely(p_xran_dev_ctx->offset_sec || p_xran_dev_ctx->offset_nsec))\r
170             timing_adjust_gps_second(p_cur_time);\r
171         delta = (p_cur_time->tv_sec * NSEC_PER_SEC + p_cur_time->tv_nsec) - target_time;\r
172         if(delta > 0 || (delta < 0 && abs(delta) < THRESHOLD)) {\r
173             if (debugStop &&(debugStopCount > 0) && (tx_counter >= debugStopCount)){\r
174                 uint64_t t1;\r
175                 printf("STOP:[%ld.%09ld], debugStopCount %d, tx_counter %ld\n", p_cur_time->tv_sec, p_cur_time->tv_nsec, debugStopCount, tx_counter);\r
176                 t1 = MLogTick();\r
177                 rte_pause();\r
178                 MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());\r
179                 xran_if_current_state = XRAN_STOPPED;\r
180             }\r
181             if(current_second != p_cur_time->tv_sec){\r
182                 current_second = p_cur_time->tv_sec;\r
183                 xran_updateSfnSecStart();\r
184                 xran_lib_ota_sym_idx = 0;\r
185                 xran_lib_ota_tti = 0;\r
186                 xran_lib_ota_sym = 0;\r
187                 sym_cnt = 0;\r
188                 sym_acc = 0;\r
189                 print_dbg("ToS:C Sync timestamp: [%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);\r
190                 if(debugStop){\r
191                     if(p_cur_time->tv_sec > started_second && ((p_cur_time->tv_sec % SEC_MOD_STOP) == 0)){\r
192                         uint64_t t1;\r
193                         printf("STOP:[%ld.%09ld]\n", p_cur_time->tv_sec, p_cur_time->tv_nsec);\r
194                         t1 = MLogTick();\r
195                         rte_pause();\r
196                         MLogTask(PID_TIME_SYSTIME_STOP, t1, MLogTick());\r
197                         xran_if_current_state = XRAN_STOPPED;\r
198                     }\r
199                 }\r
200                 p_cur_time->tv_nsec = 0; // adjust to 1pps\r
201             } else {\r
202                 xran_lib_ota_sym_idx = XranIncrementSymIdx(xran_lib_ota_sym_idx, XRAN_NUM_OF_SYMBOL_PER_SLOT*slots_per_subframe[numerlogy]);\r
203                 /* adjust to sym boundary */\r
204                 if(sym_cnt & 1)\r
205                     sym_acc +=  fine_tuning[numerlogy][0];\r
206                 else\r
207                     sym_acc +=  fine_tuning[numerlogy][1];\r
208                 /* fine tune to second boundary */\r
209                 if(sym_cnt % 13 == 0)\r
210                     sym_acc += 1;\r
211 \r
212                 p_cur_time->tv_nsec = sym_acc;\r
213                 sym_cnt++;\r
214             }\r
215 \r
216 #ifdef USE_PTP_TIME\r
217             if(debugStop && delta < interval_ns*10)\r
218                 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));\r
219 #else\r
220             MLogTask(PID_TIME_SYSTIME_POLL, last_tick, curr_tick);\r
221             last_tick = curr_tick;\r
222 #endif\r
223 \r
224 \r
225             p_temp_time = p_last_time;\r
226             p_last_time = p_cur_time;\r
227             p_cur_time  = p_temp_time;\r
228             break;\r
229         } else {\r
230             if( likely(xran_if_current_state == XRAN_RUNNING)){\r
231                 uint64_t t1, t2;\r
232                 t1 = xran_tick();\r
233 \r
234                 ring_processing_func();\r
235                 process_dpdk_io();\r
236 \r
237                 t2 = xran_tick();\r
238                 *used_tick += get_ticks_diff(t2, t1);\r
239             }\r
240         }\r
241   }\r
242 \r
243   return delta;\r
244 }\r
245 \r
246 long sleep_next_tick(long interval)\r
247 {\r
248    struct timespec start_time;\r
249    struct timespec cur_time;\r
250    //struct timespec target_time_convert;\r
251    struct timespec sleep_target_time_convert;\r
252    long target_time;\r
253    long sleep_target_time;\r
254    long delta;\r
255 \r
256    clock_gettime(CLOCK_REALTIME, &start_time);\r
257    target_time = (start_time.tv_sec * NSEC_PER_SEC + start_time.tv_nsec + interval * NSEC_PER_USEC) / (interval * NSEC_PER_USEC) * interval;\r
258    //printf("target: %ld, current: %ld, %ld\n", target_time, start_time.tv_sec, start_time.tv_nsec);\r
259    sleep_target_time = target_time - TIMECOMPENSATION;\r
260    sleep_target_time_convert.tv_sec = sleep_target_time * NSEC_PER_USEC / NSEC_PER_SEC;\r
261    sleep_target_time_convert.tv_nsec = (sleep_target_time * NSEC_PER_USEC) % NSEC_PER_SEC;\r
262 \r
263    //target_time_convert.tv_sec = target_time * NSEC_PER_USEC / NSEC_PER_SEC;\r
264    //target_time_convert.tv_nsec = (target_time * NSEC_PER_USEC) % NSEC_PER_SEC;\r
265 \r
266    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &sleep_target_time_convert, NULL);\r
267 \r
268    clock_gettime(CLOCK_REALTIME, &cur_time);\r
269 \r
270    delta = (cur_time.tv_sec * NSEC_PER_SEC + cur_time.tv_nsec) - target_time * NSEC_PER_USEC;\r
271 \r
272    return delta;\r
273 }\r
274 \r
275 \r
276 \r