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