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