+ memcpy(data, zeropad, padding);
+
+ return (total_len);
+}
+
+static int32_t
+xran_prepare_sectionext_6(struct rte_mbuf *mbuf,
+ struct xran_sectionext6_info *params, int32_t last_flag)
+{
+ union xran_cp_radioapp_section_ext6 *ext6;
+ int32_t parm_size;
+
+ parm_size = sizeof(union xran_cp_radioapp_section_ext6);
+ ext6 = (union xran_cp_radioapp_section_ext6 *)rte_pktmbuf_append(mbuf, parm_size);
+ if(ext6 == NULL) {
+ print_err("Fail to allocate the space for section extension 6");
+ return(XRAN_STATUS_RESOURCE);
+ }
+
+ ext6->data_field.data_field1 = 0x0LL;
+ ext6->all_bits.extType = XRAN_CP_SECTIONEXTCMD_6;
+ ext6->all_bits.ef = last_flag;
+ ext6->all_bits.rbgSize = params->rbgSize;
+ ext6->all_bits.rbgMask = params->rbgMask;
+ ext6->all_bits.symbolMask = params->symbolMask;
+ ext6->all_bits.extLen = parm_size / XRAN_SECTIONEXT_ALIGN;
+ //ext6->reserved0 = 0;
+ //ext6->reserved1 = 0;
+
+ *(uint64_t *)ext6 = rte_cpu_to_be_64(*(uint64_t*)ext6);
+
+ return (parm_size);
+}
+
+static int32_t
+xran_prepare_sectionext_10(struct rte_mbuf *mbuf,
+ struct xran_sectionext10_info *params, int32_t last_flag)
+{
+ union xran_cp_radioapp_section_ext10 *ext10;
+ int32_t parm_size;
+ int32_t total_len;
+ int32_t padding;
+ int32_t i;
+ uint16_t *id_ptr;
+
+
+#if (XRAN_STRICT_PARM_CHECK)
+ if(params->beamGrpType != XRAN_BEAMGT_COMMON
+ && params->beamGrpType != XRAN_BEAMGT_MATRIXIND
+ && params->beamGrpType != XRAN_BEAMGT_VECTORLIST) {
+ print_err("Invalid beam group Type - %d\n", params->beamGrpType);
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+#endif
+ /* should be checked since it will be used for the index of array */
+ if(params->numPortc > XRAN_MAX_NUMPORTC_EXT10) {
+ print_err("Invalid Number of eAxC in extension 10 - %d\n", params->numPortc);
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ parm_size = sizeof(union xran_cp_radioapp_section_ext10);
+ ext10 = (union xran_cp_radioapp_section_ext10 *)rte_pktmbuf_append(mbuf, parm_size);
+ if(ext10 == NULL) {
+ print_err("Fail to allocate the space for section extension 10");
+ return(XRAN_STATUS_RESOURCE);
+ }
+
+ ext10->all_bits.extType = XRAN_CP_SECTIONEXTCMD_10;
+ ext10->all_bits.ef = last_flag;
+ ext10->all_bits.numPortc = params->numPortc;
+ ext10->all_bits.beamGroupType = params->beamGrpType;
+ ext10->all_bits.reserved = 0;
+
+ total_len = parm_size;
+
+ if(params->beamGrpType == XRAN_BEAMGT_VECTORLIST) {
+ /* Calculate required size, it needs to be reduced by one byte
+ * since beam ID starts from reserved field(fourth octet). */
+ parm_size = params->numPortc * 2 - 1;
+
+ /* for alignment */
+ padding = (parm_size + total_len) % XRAN_SECTIONEXT_ALIGN;
+ if(padding) {
+ padding = XRAN_SECTIONEXT_ALIGN - padding;
+ parm_size += padding;
+ }
+
+ id_ptr = (uint16_t *)rte_pktmbuf_append(mbuf, parm_size);
+ if(id_ptr == NULL) {
+ print_err("Fail to allocate the space for beam IDs in section extension 10");
+ return(XRAN_STATUS_RESOURCE);
+ }
+
+ /* Need to advance pointer by one-byte since beam IDs start from fourth octet */
+ id_ptr = (uint16_t *)(((uint8_t *)id_ptr) - 1);
+
+ /* this might not be optimal since the alignment is broken */
+ for(i = 0; i < params->numPortc; i++)
+ id_ptr[i] = rte_cpu_to_be_16(params->beamID[i]);
+
+ /* zero padding */
+ if(padding)
+ memcpy((uint8_t *)&id_ptr[params->numPortc], zeropad, padding);
+ }
+
+ total_len += parm_size;
+ ext10->all_bits.extLen = total_len / XRAN_SECTIONEXT_ALIGN;
+
+ ext10->data_field = 0;
+ ext10->data_field = (XRAN_CP_SECTIONEXTCMD_10 << xran_cp_radioapp_sec_ext10_ExtType)
+ | (last_flag << xran_cp_radioapp_sec_ext10_EF)
+ | ((total_len / XRAN_SECTIONEXT_ALIGN) << xran_cp_radioapp_sec_ext10_ExtLen)
+ | (params->numPortc << xran_cp_radioapp_sec_ext10_NumPortc)
+ | (params->beamGrpType << xran_cp_radioapp_sec_ext10_BeamGroupType);
+
+
+ return (total_len);
+}
+
+/**
+ * @brief Estimates how many BFW sets can be fit to given MTU size
+ *
+ * @ingroup xran_cp_pkt
+ *
+ * @param numBFW the number of BFW I/Qs
+ * @param iqWidth the bitwidth of BFW
+ * @param compMeth Compression method for BFW
+ * @param mtu MTU size
+ *
+ * @return
+ * the number of maximum set of BFWs on success
+ * XRAN_STATUS_INVALID_PARAM, if compression method is not supported.
+ */
+int32_t
+xran_cp_estimate_max_set_bfws(uint8_t numBFWs, uint8_t iqWidth, uint8_t compMeth, uint16_t mtu)
+{
+ int32_t avail_len;
+ int32_t bfw_bitsize;
+ int32_t bundle_size;
+
+ /* Exclude headers can be present */
+ avail_len = mtu - ( RTE_PKTMBUF_HEADROOM \
+ + sizeof(struct xran_ecpri_hdr) \
+ + sizeof(struct xran_cp_radioapp_common_header) \
+ + sizeof(struct xran_cp_radioapp_section1) \
+ + sizeof(union xran_cp_radioapp_section_ext6) \
+ + sizeof(union xran_cp_radioapp_section_ext10) );
+
+ /* Calculate the size of BFWs I/Q in bytes */
+ bfw_bitsize = numBFWs * iqWidth * 2;
+ bundle_size = bfw_bitsize>>3;
+ if(bfw_bitsize%8) bundle_size++;
+
+ bundle_size += 2; /* two bytes for Beam ID */
+ switch(compMeth) {
+ case XRAN_BFWCOMPMETHOD_NONE:
+ break;
+
+ case XRAN_BFWCOMPMETHOD_BLKFLOAT:
+ bundle_size += 1; /* for bfwCompParam */
+ break;
+
+ default:
+ print_err("Compression method %d is not supported!", compMeth);
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ return (avail_len / bundle_size);
+}
+
+inline static uint32_t
+xran_cp_get_hdroffset_section1(uint32_t exthdr_size)
+{
+ uint32_t hdr_len;
+
+ hdr_len = ( RTE_PKTMBUF_HEADROOM \
+ + sizeof(struct xran_ecpri_hdr) \
+ + sizeof(struct xran_cp_radioapp_common_header) \
+ + sizeof(struct xran_cp_radioapp_section1) \
+ + exthdr_size );
+ return (hdr_len);
+}
+
+/**
+ * @brief Prepare Beam Forming Weights(BFWs) for Section Extension 11
+ * Copy sets of BFWs to buffer after compression if required.
+ *
+ * @ingroup xran_cp_pkt
+ *
+ * @param numSetBFW the number of set of BFWs
+ * @param numBFW the number of BFWs in a set
+ * @param iqWidth the bitwidth of BFW
+ * @param compMeth Compression method for BFW
+ * @param bfwIQ the array of BFW I/Q source
+ * @param dst the pointer of destination buffer (external buffer)
+ * @param dst_maxlen the maximum length of destination buffer
+ * need to exclude headroom from MTU
+ * @param bfwInfo Extension 11 PRB bundle information array.
+ * BFW size, offset and pointer will be set.
+ *
+ * @return
+ * XRAN_STATUS_SUCCESS on success
+ * XRAN_STATUS_RESOURCE, if destination memory is not enough to store all BFWs
+ */
+int32_t xran_cp_prepare_ext11_bfws(uint8_t numSetBFW, uint8_t numBFW,
+ uint8_t iqWidth, uint8_t compMeth,
+ uint8_t *dst, int16_t dst_maxlen,
+ struct xran_ext11_bfw_info bfwInfo[])
+{
+ int32_t i;
+ int32_t iq_bitsize, iq_size;
+ int32_t parm_size;
+ int32_t total_len;
+ uint32_t hdr_offset;
+ uint8_t *ptr;
+
+ struct xranlib_compress_request bfpComp_req;
+ struct xranlib_compress_response bfpComp_rsp;
+
+ if(dst == NULL) {
+ print_err("Invalid destination pointer!");
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ /* Calculate the size of BFWs I/Q in bytes */
+ iq_bitsize = numBFW * iqWidth * 2;
+ iq_size = iq_bitsize>>3;
+ if(iq_bitsize%8)
+ iq_size++;
+
+ /* Check maximum size */
+ parm_size = ((compMeth == XRAN_BFWCOMPMETHOD_NONE)?0:1) + 2; /* bfwCompParam + beamID(2) */
+ total_len = numSetBFW * (parm_size + iq_size);
+
+ if(total_len >= dst_maxlen) {
+ print_err("Exceed maximum length to fit the set of BFWs - (%d/%d)",
+ total_len, dst_maxlen);
+ return (XRAN_STATUS_RESOURCE);
+ }
+
+ hdr_offset = xran_cp_get_hdroffset_section1(sizeof(union xran_cp_radioapp_section_ext11));
+
+ /* Copy BFWs to destination buffer */
+ ptr = dst + hdr_offset + 2;
+ switch(compMeth) {
+ /* No compression */
+ case XRAN_BFWCOMPMETHOD_NONE:
+ for(i = 0; i < numSetBFW; i++) {
+ *((uint16_t *)ptr) = rte_cpu_to_be_16((bfwInfo[i].beamId & 0x7fff));
+ memcpy((ptr + 2), bfwInfo[i].pBFWs, iq_size);
+ ptr += iq_size + 2; /* beam ID + IQ size */
+ }
+ break;
+
+ /* currently only supports BFP compression */
+ case XRAN_BFWCOMPMETHOD_BLKFLOAT:
+ memset(&bfpComp_req, 0, sizeof(struct xranlib_compress_request));
+ memset(&bfpComp_rsp, 0, sizeof(struct xranlib_compress_response));
+
+ for(i = 0; i < numSetBFW; i++) {
+ bfpComp_req.numRBs = 1;
+ bfpComp_req.numDataElements = numBFW*2;
+ bfpComp_req.len = numBFW*2*2;
+ bfpComp_req.compMethod = compMeth;
+ bfpComp_req.iqWidth = iqWidth;
+ bfpComp_req.data_in = (int16_t *)bfwInfo[i].pBFWs;
+ bfpComp_rsp.data_out = (int8_t*)(ptr + 2); /* exponent will be stored at first byte */
+
+ if(xranlib_compress_bfw(&bfpComp_req, &bfpComp_rsp) == 0) {
+ print_dbg("comp_len %d iq_size %d\n", bfpComp_rsp.len, iq_size);
+ } else {
+ print_err("compression failed\n");
+ return (XRAN_STATUS_FAIL);
+ }
+ /* move exponent, it is stored at first byte of output */
+ *ptr = *(ptr + 2);
+
+ /* beamId */
+ *((uint16_t *)(ptr+1)) = rte_cpu_to_be_16((bfwInfo[i].beamId & 0x7fff));
+ ptr += iq_size + 3;
+ }
+ break;
+
+ default:
+ print_err("Compression method %d is not supported!", compMeth);
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ /* Update the length of extension with padding */
+ parm_size = (total_len + sizeof(union xran_cp_radioapp_section_ext11))
+ % XRAN_SECTIONEXT_ALIGN;
+ if(parm_size) {
+ /* Add padding */
+ parm_size = XRAN_SECTIONEXT_ALIGN - parm_size;
+ memcpy(ptr, zeropad, parm_size);
+ total_len += parm_size;
+ }
+
+ return (total_len);
+}
+
+
+static void free_ext_buf(void *addr, void *opaque)
+{
+ /* free is not required for external buffers */
+}
+
+/*
+ * extbuf_start : the pointer of the external buffer,
+ * It can be the start address of whole external buffer.
+ * extbuf_len : total length of the external buffer (available space to access)
+ * To use the length of the data, offset2data should be zero.
+ * */
+int32_t xran_cp_attach_ext_buf(struct rte_mbuf *mbuf,
+ uint8_t *extbuf_start, uint16_t extbuf_len,
+ struct rte_mbuf_ext_shared_info *shinfo)
+{
+ rte_iova_t extbuf_iova;
+
+
+ if(unlikely(mbuf == NULL)) {
+ print_err("Invalid mbuf to attach!\n");
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ /* Update shared information */
+ shinfo->free_cb = free_ext_buf;
+ rte_mbuf_ext_refcnt_update(shinfo, 1);
+
+ extbuf_iova = rte_malloc_virt2iova(extbuf_start);
+ if(unlikely(extbuf_iova == RTE_BAD_IOVA)) {
+ print_err("Failed rte_mem_virt2iova RTE_BAD_IOVA \n");
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+
+ rte_pktmbuf_attach_extbuf(mbuf, extbuf_start, extbuf_iova, extbuf_len, shinfo);
+
+ rte_pktmbuf_reset_headroom(mbuf);
+
+ return (XRAN_STATUS_SUCCESS);
+}
+
+
+static int32_t
+xran_prepare_sectionext_11(struct rte_mbuf *mbuf,
+ struct xran_sectionext11_info *params, int32_t last_flag)
+{
+ union xran_cp_radioapp_section_ext11 *ext11;
+ int32_t total_len;
+
+
+#if (XRAN_STRICT_PARM_CHECK)
+ if(unlikely((params->numSetBFWs == 0)
+ || (params->numSetBFWs > XRAN_MAX_SET_BFWS))) {
+ print_err("Invalid number of the set of PRB bundle [%d]", params->numSetBFWs);
+ return (XRAN_STATUS_INVALID_PARAM);
+ }
+#endif
+
+ /* BFWs are already present in the external buffer, just update the length */
+ total_len = sizeof(union xran_cp_radioapp_section_ext11) + params->totalBfwIQLen;
+
+ ext11 = (union xran_cp_radioapp_section_ext11 *)rte_pktmbuf_append(mbuf, total_len);
+ if(ext11 == NULL) {
+ print_err("Fail to allocate the space for section extension 11 [%d]", total_len);
+ return (XRAN_STATUS_RESOURCE);
+ }
+
+ /*ext11->all_bits.extType = XRAN_CP_SECTIONEXTCMD_11;
+ ext11->all_bits.ef = last_flag;
+ ext11->all_bits.reserved = 0;
+ ext11->all_bits.RAD = params->RAD;
+ ext11->all_bits.disableBFWs = params->disableBFWs;
+ ext11->all_bits.numBundPrb = params->numBundPrb;
+ ext11->all_bits.bfwCompMeth = params->bfwCompMeth;
+ ext11->all_bits.bfwIqWidth = XRAN_CONVERT_BFWIQWIDTH(params->bfwIqWidth);
+
+ ext11->all_bits.extLen = total_len / XRAN_SECTIONEXT_ALIGN;*/
+
+ ext11->data_field.data_field1 = (last_flag << xran_cp_radioapp_sec_ext11_bitfield_Ef)
+ | (XRAN_CP_SECTIONEXTCMD_11 << xran_cp_radioapp_sec_ext11_bitfield_ExtType)
+ | ((total_len / XRAN_SECTIONEXT_ALIGN) << xran_cp_radioapp_sec_ext11_bitfield_ExtLen)
+ | (params->disableBFWs << xran_cp_radioapp_sec_ext11_bitfield_DisBFWs)
+ | (params->RAD << xran_cp_radioapp_sec_ext11_bitfield_RAD);
+ ext11->data_field.data_field2 = ((XRAN_CONVERT_BFWIQWIDTH(params->bfwIqWidth)) << xran_cp_radioapp_sec_ext11_bitfield_BFWIQWidth)
+ | (params->bfwCompMeth << xran_cp_radioapp_sec_ext11_bitfield_BFWCompMeth)
+ | params->numBundPrb;
+
+ *(uint32_t *)ext11 = rte_cpu_to_be_32(*(uint32_t*)ext11);