d748e2cda66a1f9896c06d8474cb10031844c504
[o-du/phy.git] / fhi_lib / lib / src / xran_up_api.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 the implementation of User Plane Messages APIs.\r
21  *\r
22  * @file xran_up_api.c\r
23  * @ingroup group_lte_source_xran\r
24  * @author Intel Corporation\r
25  *\r
26  **/\r
27 #include <inttypes.h>\r
28 \r
29 #include <rte_memcpy.h>\r
30 #include <rte_mbuf.h>\r
31 \r
32 #include "xran_fh_o_du.h"\r
33 #include "xran_transport.h"\r
34 #include "xran_up_api.h"\r
35 #include "xran_printf.h"\r
36 #include "xran_mlog_lnx.h"\r
37 \r
38 extern uint32_t xran_lib_ota_tti;\r
39 \r
40 /**\r
41  * @brief Builds eCPRI header in xRAN packet\r
42  *\r
43  * @param mbuf Initialized rte_mbuf packet\r
44  * @param iq_data_num_bytes Number of bytes in IQ data buffer\r
45  * @param iq_data_offset Number of elements already sent\r
46  * @return int int 0 on success, non zero on failure\r
47  */\r
48 static int build_ecpri_hdr(struct rte_mbuf *mbuf,\r
49     const uint32_t iq_data_num_bytes,\r
50     const uint32_t iq_data_offset,\r
51     uint8_t alignment)\r
52 {\r
53     struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)\r
54         rte_pktmbuf_append(mbuf, sizeof(struct xran_ecpri_hdr));\r
55 \r
56     uint16_t iq_samples_bytes_in_mbuf = rte_pktmbuf_tailroom(mbuf) -\r
57         sizeof(struct radio_app_common_hdr) - sizeof(struct data_section_hdr);\r
58 \r
59     iq_samples_bytes_in_mbuf -= (iq_samples_bytes_in_mbuf % alignment);\r
60 \r
61     if (NULL == ecpri_hdr)\r
62         return 1;\r
63 \r
64     ecpri_hdr->cmnhdr.ecpri_ver = XRAN_ECPRI_VER;\r
65     ecpri_hdr->cmnhdr.ecpri_resv = 0;\r
66     ecpri_hdr->cmnhdr.ecpri_concat = 0;\r
67     ecpri_hdr->cmnhdr.ecpri_mesg_type = ECPRI_IQ_DATA;\r
68 \r
69     if (iq_data_offset + iq_samples_bytes_in_mbuf > iq_data_num_bytes) {\r
70         ecpri_hdr->cmnhdr.ecpri_payl_size =\r
71             rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +\r
72                 sizeof(struct data_section_hdr) +\r
73                 (iq_data_num_bytes - iq_data_offset) +\r
74                 xran_get_ecpri_hdr_size());\r
75         ecpri_hdr->ecpri_seq_id.e_bit = 1;  /* last segment */\r
76     } else {\r
77         ecpri_hdr->cmnhdr.ecpri_payl_size =\r
78             rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +\r
79                 sizeof(struct data_section_hdr) +\r
80                 iq_samples_bytes_in_mbuf +\r
81                 xran_get_ecpri_hdr_size());\r
82         ecpri_hdr->ecpri_seq_id.e_bit = 0;\r
83     }\r
84 \r
85 //    ecpri_hdr->ecpri_xtc_id = 0;    /* currently not used */\r
86     ecpri_hdr->ecpri_seq_id.seq_id = 0;\r
87     ecpri_hdr->ecpri_seq_id.sub_seq_id = iq_data_offset /\r
88         iq_samples_bytes_in_mbuf;\r
89 \r
90     return 0;\r
91 }\r
92 \r
93 /**\r
94  * @brief Builds eCPRI header in xRAN packet\r
95  *\r
96  * @param mbuf Initialized rte_mbuf packet\r
97  * @param ecpri_mesg_type eCPRI message type\r
98  * @param payl_size the size in bytes of the payload part of eCPRI message\r
99  * @param CC_ID Component Carrier ID for ecpriRtcid/ecpriPcid\r
100  * @param Ant_ID Antenna ID for ecpriRtcid/ecpriPcid\r
101  * @param seq_id Message identifier for eCPRI message\r
102  * @param comp_meth Compression method\r
103  * @return int int 0 on success, non zero on failure\r
104  */\r
105 static int xran_build_ecpri_hdr_ex(struct rte_mbuf *mbuf,\r
106                               uint8_t ecpri_mesg_type,\r
107                               int payl_size,\r
108                               uint8_t CC_ID,\r
109                               uint8_t Ant_ID,\r
110                               uint8_t seq_id,\r
111                               uint8_t comp_meth)\r
112 {\r
113     char *pChar = rte_pktmbuf_mtod(mbuf, char*);\r
114     struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)(pChar + sizeof(struct ether_hdr));\r
115     uint16_t    ecpri_payl_size = payl_size\r
116                                 + sizeof(struct data_section_hdr)\r
117                                 + sizeof(struct radio_app_common_hdr)\r
118                                 + xran_get_ecpri_hdr_size();\r
119 \r
120     if (comp_meth != XRAN_COMPMETHOD_NONE)\r
121         ecpri_payl_size += sizeof(struct data_section_compression_hdr);\r
122 \r
123     if (NULL == ecpri_hdr)\r
124         return 1;\r
125 \r
126     ecpri_hdr->cmnhdr.ecpri_ver       = XRAN_ECPRI_VER;\r
127     ecpri_hdr->cmnhdr.ecpri_resv      = 0;     // should be zero\r
128     ecpri_hdr->cmnhdr.ecpri_concat    = 0;\r
129     ecpri_hdr->cmnhdr.ecpri_mesg_type = ecpri_mesg_type;\r
130     ecpri_hdr->cmnhdr.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payl_size);\r
131 \r
132     /* one to one lls-CU to RU only and band sector is the same */\r
133     ecpri_hdr->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);\r
134 \r
135     ecpri_hdr->ecpri_seq_id.seq_id = seq_id;\r
136 \r
137     /* no transport layer fragmentation supported */\r
138     ecpri_hdr->ecpri_seq_id.sub_seq_id  = 0;\r
139     ecpri_hdr->ecpri_seq_id.e_bit       = 1;\r
140 \r
141     return 0;\r
142 }\r
143 \r
144 \r
145 /**\r
146  * @brief Builds application layer of xRAN packet\r
147  *\r
148  * @param mbuf Initialized rte_mbuf packet\r
149  * @param app_hdr_input Radio App common header structure to be set in mbuf\r
150  *                      packet.\r
151  * @return int 0 on success, non zero on failure\r
152  */\r
153 static int build_application_layer(\r
154     struct rte_mbuf *mbuf,\r
155     const struct radio_app_common_hdr *app_hdr_input)\r
156 {\r
157     char *pChar = rte_pktmbuf_mtod(mbuf, char*);\r
158     struct radio_app_common_hdr *app_hdr = (struct radio_app_common_hdr *)(pChar + sizeof(struct ether_hdr)\r
159         + sizeof (struct xran_ecpri_hdr));\r
160 \r
161     if (NULL == app_hdr)\r
162         return 1;\r
163 \r
164     rte_memcpy(app_hdr, app_hdr_input, sizeof(struct radio_app_common_hdr));\r
165 \r
166     return 0;\r
167 }\r
168 \r
169 /**\r
170  * @brief Builds section header in xRAN packet\r
171  *\r
172  * @param mbuf Initialized rte_mbuf packet\r
173  * @param sec_hdr Section header structure to be set in mbuf packet\r
174  * @return int 0 on success, non zero on failure\r
175  */\r
176 static int build_section_hdr(\r
177     struct rte_mbuf *mbuf,\r
178     const struct data_section_hdr *sec_hdr)\r
179 {\r
180     char *pChar = rte_pktmbuf_mtod(mbuf, char*);\r
181     struct data_section_hdr *section_hdr = (struct data_section_hdr *)\r
182         (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr));\r
183 \r
184     if (NULL == section_hdr)\r
185         return 1;\r
186 \r
187     rte_memcpy(section_hdr, sec_hdr, sizeof(struct data_section_hdr));\r
188 \r
189     return 0;\r
190 }\r
191 /**\r
192  * @brief Function for appending IQ samples data to the mbuf.\r
193  *\r
194  * @param mbuf Initialized rte_mbuf packet.\r
195  * @param iq_data_start Address of the first element in IQ data array.\r
196  * @param iq_data_num_bytes Size of the IQ data array.\r
197  * @param iq_data_offset IQ data btyes already sent.\r
198  * @return uint16_t Bytes that have been appended to the packet.\r
199  */\r
200 static uint16_t append_iq_samples_ex(\r
201     struct rte_mbuf *mbuf,\r
202     const void *iq_data_start,\r
203     const uint32_t iq_data_num_bytes,\r
204     enum xran_input_byte_order iq_buf_byte_order,\r
205     uint32_t do_copy)\r
206 {\r
207     char *pChar = rte_pktmbuf_mtod(mbuf, char*);\r
208     void *iq_sam_buf  = (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr)\r
209                         + sizeof(struct radio_app_common_hdr)\r
210                         + sizeof(struct data_section_hdr));\r
211 \r
212     if (iq_sam_buf == NULL){\r
213         print_err("iq_sam_buf == NULL\n");\r
214         return 0;\r
215     }\r
216     if(iq_buf_byte_order == XRAN_CPU_LE_BYTE_ORDER){\r
217         int idx = 0;\r
218         uint16_t *psrc = (uint16_t *)iq_data_start;\r
219         uint16_t *pdst = (uint16_t *)iq_sam_buf;\r
220         /* CPU byte order (le) of IQ to network byte order (be) */\r
221         for (idx = 0; idx < iq_data_num_bytes/sizeof(int16_t); idx++){\r
222             pdst[idx]  =  (psrc[idx]>>8) | (psrc[idx]<<8); //rte_cpu_to_be_16(psrc[idx]);\r
223         }\r
224     }\r
225 \r
226 #if 0\r
227     /* do not expect to do copy anymore */\r
228     else if(iq_buf_byte_order == XRAN_NE_BE_BYTE_ORDER){\r
229         if(do_copy) {\r
230            rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start,  iq_data_num_bytes);\r
231         }\r
232     }\r
233 #endif\r
234 \r
235     return iq_data_num_bytes;\r
236 }\r
237 \r
238 /**\r
239  * @brief Function for appending IQ samples data to the mbuf.\r
240  *\r
241  * @param mbuf Initialized rte_mbuf packet.\r
242  * @param iq_data_start Address of the first element in IQ data array.\r
243  * @param iq_data_num_bytes Size of the IQ data array.\r
244  * @param iq_data_offset IQ data btyes already sent.\r
245  * @return uint16_t Bytes that have been appended to the packet.\r
246  */\r
247 static uint16_t append_iq_samples(\r
248     struct rte_mbuf *mbuf,\r
249     const void *iq_data_start,\r
250     const uint32_t iq_data_num_bytes,\r
251     const uint32_t iq_data_offset,\r
252     const uint8_t alignment)\r
253 {\r
254     uint16_t iq_bytes_to_send = 0;\r
255     uint16_t free_space_in_pkt = rte_pktmbuf_tailroom(mbuf);\r
256 \r
257     if (free_space_in_pkt > iq_data_num_bytes - iq_data_offset)\r
258         iq_bytes_to_send = iq_data_num_bytes - iq_data_offset;\r
259     else\r
260         iq_bytes_to_send = free_space_in_pkt;\r
261 \r
262     /* don't cut off an iq in half */\r
263     iq_bytes_to_send -= iq_bytes_to_send % alignment;\r
264 \r
265     void *iq_sam_buf = (void *)rte_pktmbuf_append(mbuf, iq_bytes_to_send);\r
266 \r
267     rte_memcpy(iq_sam_buf, (uint8_t *)iq_data_start + iq_data_offset,\r
268             iq_bytes_to_send);\r
269 \r
270     return iq_bytes_to_send;\r
271 }\r
272 \r
273 /**\r
274  * @brief Builds compression header in xRAN packet\r
275  *\r
276  * @param mbuf Initialized rte_mbuf packet\r
277  * @param compression_hdr Section compression header structure\r
278  *                to be set in mbuf packet\r
279  * @return int 0 on success, non zero on failure\r
280  */\r
281 static int build_compression_hdr(\r
282     struct rte_mbuf *mbuf,\r
283     const struct data_section_compression_hdr *compr_hdr)\r
284 {\r
285     char *pChar = rte_pktmbuf_mtod(mbuf, char*);\r
286     struct data_section_compression_hdr *compression_hdr = (struct data_section_compression_hdr *)\r
287         (pChar + sizeof(struct ether_hdr) + sizeof (struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)\r
288         + sizeof(struct data_section_hdr));\r
289 \r
290     if (NULL == compression_hdr)\r
291         return 1;\r
292 \r
293     rte_memcpy(compression_hdr, compr_hdr, sizeof(*compression_hdr));\r
294 \r
295     return 0;\r
296 }\r
297 \r
298 /**\r
299  * @brief Appends compression parameter in xRAN packet\r
300  *\r
301  * @param mbuf Initialized rte_mbuf packet\r
302  * @param ud_comp_paramr Compression param to be set in mbuf packet\r
303  * @return int 0 on success, non zero on failure\r
304  */\r
305 static int append_comp_param(struct rte_mbuf *mbuf, union compression_params *ud_comp_param)\r
306 {\r
307     union compression_params *compr_param =\r
308         (union compression_params *)rte_pktmbuf_append(mbuf, sizeof(union compression_params));\r
309 \r
310     if (NULL == compr_param)\r
311         return 1;\r
312 \r
313     rte_memcpy(compr_param, ud_comp_param, sizeof(union compression_params));\r
314 \r
315     return 0;\r
316 }\r
317 \r
318 /**\r
319  * @brief Function for extracting all IQ samples from xRAN packet\r
320  *        holding a single data section\r
321  * @param iq_data_start Address of the first element in IQ data array.\r
322  * @param symb_id Symbol ID to be extracted from ecpri header\r
323  * @param seq_id  Sequence ID to be extracted from radio header\r
324  * @return int Size of remaining mbuf filled with IQ samples\r
325                zero on failure\r
326  */\r
327 int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,\r
328     void **iq_data_start,\r
329     uint8_t *CC_ID,\r
330     uint8_t *Ant_ID,\r
331     uint8_t *frame_id,\r
332     uint8_t *subframe_id,\r
333     uint8_t *slot_id,\r
334     uint8_t *symb_id,\r
335     struct ecpri_seq_id *seq_id,\r
336     uint16_t *num_prbu,\r
337     uint16_t *start_prbu,\r
338     uint16_t *sym_inc,\r
339     uint16_t *rb,\r
340     uint16_t *sect_id,\r
341     int8_t   expect_comp,\r
342     uint8_t *compMeth,\r
343     uint8_t *iqWidth)\r
344 {\r
345 #if XRAN_MLOG_VAR\r
346     uint32_t mlogVar[10];\r
347     uint32_t mlogVarCnt = 0;\r
348 #endif\r
349     struct xran_eaxc_info result;\r
350 \r
351     if (NULL == mbuf)\r
352         return 0;\r
353     if (NULL == iq_data_start)\r
354         return 0;\r
355 \r
356     /* Process eCPRI header. */\r
357     const struct xran_ecpri_hdr *ecpri_hdr = rte_pktmbuf_mtod(mbuf, void *);\r
358     if (ecpri_hdr == NULL)\r
359         return 0;\r
360 \r
361     if (seq_id)\r
362         *seq_id = ecpri_hdr->ecpri_seq_id;\r
363 \r
364     xran_decompose_cid((uint16_t)ecpri_hdr->ecpri_xtc_id, &result);\r
365 \r
366     *CC_ID  = result.ccId;\r
367     *Ant_ID = result.ruPortId;\r
368 \r
369     /* Process radio header. */\r
370     struct radio_app_common_hdr *radio_hdr =\r
371         (void *)rte_pktmbuf_adj(mbuf, sizeof(*ecpri_hdr));\r
372     if (radio_hdr == NULL)\r
373         return 0;       /* packet too short */\r
374 \r
375     radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);\r
376 \r
377     if (frame_id)\r
378         *frame_id    = radio_hdr->frame_id;\r
379 \r
380     if (subframe_id)\r
381         *subframe_id = radio_hdr->sf_slot_sym.subframe_id;\r
382 \r
383     if (slot_id)\r
384         *slot_id     = radio_hdr->sf_slot_sym.slot_id;\r
385 \r
386     if (symb_id)\r
387         *symb_id = radio_hdr->sf_slot_sym.symb_id;\r
388 \r
389     /* Process data section hdr */\r
390     struct data_section_hdr *data_hdr =\r
391         (void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr));\r
392     if (data_hdr == NULL)\r
393         return 0;       /* packet too short */\r
394 \r
395     /* cpu byte order */\r
396     data_hdr->fields.all_bits  = rte_be_to_cpu_32(data_hdr->fields.all_bits);\r
397 \r
398     *num_prbu   = data_hdr->fields.num_prbu;\r
399     *start_prbu = data_hdr->fields.start_prbu;\r
400     *sym_inc    = data_hdr->fields.sym_inc;\r
401     *rb         = data_hdr->fields.rb;\r
402     *sect_id    = data_hdr->fields.sect_id;\r
403 \r
404     if(expect_comp) {\r
405         const struct data_section_compression_hdr *data_compr_hdr =\r
406             (void *) rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));\r
407 \r
408         if (data_compr_hdr == NULL)\r
409             return 0;\r
410 \r
411         *compMeth = data_compr_hdr->ud_comp_hdr.ud_comp_meth;\r
412         *iqWidth =  data_compr_hdr->ud_comp_hdr.ud_iq_width;\r
413 \r
414         const uint8_t *compr_param =\r
415             (void *)rte_pktmbuf_adj(mbuf, sizeof(*data_compr_hdr));\r
416 \r
417             *iq_data_start = (void *)compr_param; /*rte_pktmbuf_adj(mbuf, sizeof(*compr_param))*/;\r
418     } else {\r
419         *iq_data_start = rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));\r
420     }\r
421 \r
422     if (*iq_data_start == NULL)\r
423         return 0;\r
424 \r
425 #if XRAN_MLOG_VAR\r
426     mlogVar[mlogVarCnt++] = 0xBBBBBBBB;\r
427     mlogVar[mlogVarCnt++] = xran_lib_ota_tti;\r
428     mlogVar[mlogVarCnt++] = radio_hdr->frame_id;\r
429     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.subframe_id;\r
430     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.slot_id;\r
431     mlogVar[mlogVarCnt++] = radio_hdr->sf_slot_sym.symb_id;\r
432     mlogVar[mlogVarCnt++] = data_hdr->fields.sect_id;\r
433     mlogVar[mlogVarCnt++] = data_hdr->fields.start_prbu;\r
434     mlogVar[mlogVarCnt++] = data_hdr->fields.num_prbu;\r
435     mlogVar[mlogVarCnt++] = rte_pktmbuf_pkt_len(mbuf);\r
436     MLogAddVariables(mlogVarCnt, mlogVar, MLogTick());\r
437 #endif\r
438 \r
439     return rte_pktmbuf_pkt_len(mbuf);\r
440 }\r
441 \r
442 /**\r
443  * @brief Function for starting preparion of IQ samples portions\r
444  *        to be sent in xRAN packet\r
445  *\r
446  * @param mbuf Initialized rte_mbuf packet.\r
447  * @param iq_data_start Address of the first element in IQ data array.\r
448  * @param iq_data_num_bytes Size of the IQ data array.\r
449  * @param iq_data_offset IQ data bytes already sent.\r
450  * @param alignment Size of IQ data alignment.\r
451  * @param pkt_gen_params Struct with parameters used for building packet\r
452  * @return int Number of bytes that have been appended\r
453                to the packet within all appended sections.\r
454  */\r
455 int32_t xran_prepare_iq_symbol_portion(\r
456                         struct rte_mbuf *mbuf,\r
457                         const void *iq_data_start,\r
458                         const enum xran_input_byte_order iq_buf_byte_order,\r
459                         const uint32_t iq_data_num_bytes,\r
460                         struct xran_up_pkt_gen_params *params,\r
461                         uint8_t CC_ID,\r
462                         uint8_t Ant_ID,\r
463                         uint8_t seq_id,\r
464                         uint32_t do_copy)\r
465 {\r
466     if(xran_build_ecpri_hdr_ex(mbuf,\r
467                            ECPRI_IQ_DATA,\r
468                            iq_data_num_bytes,\r
469                            CC_ID,\r
470                            Ant_ID,\r
471                            seq_id,\r
472                            params->compr_hdr_param.ud_comp_hdr.ud_comp_meth)){\r
473         print_err("xran_build_ecpri_hdr_ex return 0\n");\r
474         return 0;\r
475     }\r
476 \r
477     if (build_application_layer(mbuf, &(params->app_params)) != 0){\r
478         print_err("build_application_layer return != 0\n");\r
479         return 0;\r
480     }\r
481 \r
482     if (build_section_hdr(mbuf, &(params->sec_hdr)) != 0){\r
483         print_err("build_section_hdr return != 0\n");\r
484         return 0;\r
485     }\r
486 \r
487 \r
488     if(params->compr_hdr_param.ud_comp_hdr.ud_comp_meth != XRAN_COMPMETHOD_NONE) {\r
489         if (build_compression_hdr(mbuf, &(params->compr_hdr_param)) !=0)\r
490             return 0;\r
491 \r
492          /* payload expected to start with udCompParam */\r
493 \r
494         /*if(append_comp_param(mbuf, &(params->compr_param)) !=0)\r
495             return 0;*/\r
496     }\r
497 \r
498 \r
499     return append_iq_samples_ex(mbuf, iq_data_start, iq_data_num_bytes, iq_buf_byte_order, do_copy);\r
500 }\r
501 \r