1 /******************************************************************************
3 * Copyright (c) 2020 Intel.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 *******************************************************************************/
20 * @brief This file provides the implementation of User Plane Messages APIs.
23 * @ingroup group_lte_source_xran
24 * @author Intel Corporation
28 #include <immintrin.h>
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"
41 * @brief Builds eCPRI header in xRAN packet
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
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,
53 struct xran_ecpri_hdr *ecpri_hdr = (struct xran_ecpri_hdr *)
54 rte_pktmbuf_append(mbuf, sizeof(struct xran_ecpri_hdr));
56 uint16_t iq_samples_bytes_in_mbuf = rte_pktmbuf_tailroom(mbuf) -
57 sizeof(struct radio_app_common_hdr) - sizeof(struct data_section_hdr);
59 iq_samples_bytes_in_mbuf -= (iq_samples_bytes_in_mbuf % alignment);
61 if (NULL == ecpri_hdr)
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;
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 */
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;
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;
95 * @brief Builds eCPRI header in xRAN packet
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
106 static inline int xran_build_ecpri_hdr_ex(struct rte_mbuf *mbuf,
107 uint8_t ecpri_mesg_type,
113 enum xran_comp_hdr_type staticEn)
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));
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)
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);
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);
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;
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;
147 * @brief Builds application layer of xRAN packet
149 * @param mbuf Initialized rte_mbuf packet
150 * @param app_hdr_input Radio App common header structure to be set in mbuf
152 * @return int 0 on success, non zero on failure
154 static inline int build_application_layer(
155 struct rte_mbuf *mbuf,
156 const struct radio_app_common_hdr *app_hdr_input)
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));
165 memcpy(app_hdr, app_hdr_input, sizeof(struct radio_app_common_hdr));
171 * @brief Builds section header in xRAN packet
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
178 static inline int build_section_hdr(
179 struct rte_mbuf *mbuf,
180 const struct data_section_hdr *sec_hdr,
183 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
184 struct data_section_hdr *section_hdr = (struct data_section_hdr *)(pChar + offset);
186 if (NULL == section_hdr)
189 memcpy(section_hdr, &sec_hdr->fields.all_bits, sizeof(struct data_section_hdr));
196 * @brief Function for appending IQ samples data to the mbuf.
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.
204 static inline uint16_t append_iq_samples_ex(
205 struct rte_mbuf *mbuf,
207 const void *iq_data_start,
208 const uint32_t iq_data_num_bytes,
209 enum xran_input_byte_order iq_buf_byte_order,
212 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
215 iq_sam_buf = (pChar + iq_sam_offset);
216 if (iq_sam_buf == NULL){
217 print_err("iq_sam_buf == NULL\n");
220 if(iq_buf_byte_order == XRAN_CPU_LE_BYTE_ORDER){
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]);
230 else if(iq_buf_byte_order == XRAN_NE_BE_BYTE_ORDER){
232 memcpy(iq_sam_buf, (uint8_t *)iq_data_start, iq_data_num_bytes);
236 return iq_data_num_bytes;
240 * @brief Function for appending IQ samples data to the mbuf.
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.
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)
255 uint16_t iq_bytes_to_send = 0;
256 uint16_t free_space_in_pkt = rte_pktmbuf_tailroom(mbuf);
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;
261 iq_bytes_to_send = free_space_in_pkt;
263 /* don't cut off an iq in half */
264 iq_bytes_to_send -= iq_bytes_to_send % alignment;
266 void *iq_sam_buf = (void *)rte_pktmbuf_append(mbuf, iq_bytes_to_send);
268 memcpy(iq_sam_buf, (uint8_t *)iq_data_start + iq_data_offset,
271 return iq_bytes_to_send;
276 * @brief Builds compression header in xRAN packet
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
284 static inline int build_compression_hdr(
285 struct rte_mbuf *mbuf,
286 const struct data_section_compression_hdr *compr_hdr,
289 char *pChar = rte_pktmbuf_mtod(mbuf, char*);
290 struct data_section_compression_hdr *compression_hdr =
291 (struct data_section_compression_hdr *)(pChar + offset);
293 if (NULL == compression_hdr)
296 memcpy(compression_hdr, compr_hdr, sizeof(*compression_hdr));
303 * @brief Appends compression parameter in xRAN packet
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
309 static int append_comp_param(struct rte_mbuf *mbuf, union compression_params *ud_comp_param)
311 union compression_params *compr_param =
312 (union compression_params *)rte_pktmbuf_append(mbuf, sizeof(union compression_params));
314 if (NULL == compr_param)
317 memcpy(compr_param, ud_comp_param, sizeof(union compression_params));
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
331 int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
332 void **iq_data_start,
336 uint8_t *subframe_id,
339 union ecpri_seq_id *seq_id,
341 uint16_t *start_prbu,
346 enum xran_comp_hdr_type staticComp,
351 uint32_t mlogVar[10];
352 uint32_t mlogVarCnt = 0;
354 struct xran_eaxc_info result;
358 if (NULL == iq_data_start)
361 /* Process eCPRI header. */
362 const struct xran_ecpri_hdr *ecpri_hdr = rte_pktmbuf_mtod(mbuf, void *);
363 if (ecpri_hdr == NULL)
367 *seq_id = ecpri_hdr->ecpri_seq_id;
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);
373 *CC_ID = result.ccId;
374 *Ant_ID = result.ruPortId;
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 */
383 radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);
386 *frame_id = radio_hdr->frame_id;
389 *subframe_id = radio_hdr->sf_slot_sym.subframe_id;
392 *slot_id = xran_slotid_convert(radio_hdr->sf_slot_sym.slot_id, 1);
395 *symb_id = radio_hdr->sf_slot_sym.symb_id;
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 */
404 data_hdr->fields.all_bits = rte_be_to_cpu_32(data_hdr->fields.all_bits);
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;
413 const struct data_section_compression_hdr *data_compr_hdr;
414 if (staticComp != XRAN_COMP_HDR_TYPE_STATIC)
417 (void *) rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
419 if (data_compr_hdr == NULL)
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));
427 *iq_data_start = (void *)compr_param; /*rte_pktmbuf_adj(mbuf, sizeof(*compr_param))*/;
431 *iq_data_start = rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
436 *iq_data_start = rte_pktmbuf_adj(mbuf, sizeof(*data_hdr));
439 if (*iq_data_start == NULL)
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());
455 return rte_pktmbuf_pkt_len(mbuf);
459 * @brief Function for starting preparion of IQ samples portions
460 * to be sent in xRAN packet
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.
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,
481 enum xran_comp_hdr_type staticEn,
483 uint16_t num_sections,
484 uint16_t section_id_start,
487 uint32_t offset=0 , ret_val=0;
488 uint16_t idx , iq_len=0;
490 uint16_t iq_n_section_size; //All data_section + compression hdrs + iq
492 iq_n_section_size = iq_data_num_bytes + num_sections*sizeof(struct data_section_hdr);
494 if ((params[0].compr_hdr_param.ud_comp_hdr.ud_comp_meth != XRAN_COMPMETHOD_NONE)&&(staticEn == XRAN_COMP_HDR_TYPE_DYNAMIC))
496 iq_n_section_size += num_sections*sizeof(struct data_section_compression_hdr);
499 if(xran_build_ecpri_hdr_ex(mbuf,
501 (int)iq_n_section_size,
505 params[0].compr_hdr_param.ud_comp_hdr.ud_comp_meth,
507 print_err("xran_build_ecpri_hdr_ex return 0\n");
511 if (build_application_layer(mbuf, &(params[0].app_params)) != 0){
512 print_err("build_application_layer return != 0\n");
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++)
521 if (build_section_hdr(mbuf, &(params[idx].sec_hdr),offset) != 0){
522 print_err("build_section_hdr return != 0\n");
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)
530 offset += sizeof(struct data_section_compression_hdr);
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));
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));
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;