#include <rte_malloc.h>
#include <rte_ring.h>
#include <rte_kvargs.h>
+#include <rte_cycles.h>
#include <rte_bbdev.h>
#include <rte_bbdev_pmd.h>
+#ifdef RTE_BBDEV_SDK_AVX2
#include <phy_turbo.h>
#include <phy_crc.h>
#include <phy_rate_match.h>
-#include <divide.h>
+#endif
-#define DRIVER_NAME turbo_sw
+#define DRIVER_NAME baseband_turbo_sw
/* Turbo SW PMD logging ID */
static int bbdev_turbo_sw_logtype;
rte_bbdev_log(DEBUG, RTE_STR(__LINE__) ":%s() " fmt, __func__, \
##__VA_ARGS__)
-/* Number of columns in sub-block interleaver (36.212, section 5.1.4.1.1) */
-#define C_SUBBLOCK (32)
-#define MAX_TB_SIZE (391656)
-#define MAX_CB_SIZE (6144)
-#define MAX_KW (18528)
+#define DEINT_INPUT_BUF_SIZE (((RTE_BBDEV_MAX_CB_SIZE >> 3) + 1) * 48)
+#define DEINT_OUTPUT_BUF_SIZE (DEINT_INPUT_BUF_SIZE * 6)
+#define ADAPTER_OUTPUT_BUF_SIZE ((RTE_BBDEV_MAX_CB_SIZE + 4) * 48)
/* private data structure */
struct bbdev_private {
enum rte_bbdev_op_type type;
} __rte_cache_aligned;
+#ifdef RTE_BBDEV_SDK_AVX2
+static inline char *
+mbuf_append(struct rte_mbuf *m_head, struct rte_mbuf *m, uint16_t len)
+{
+ if (unlikely(len > rte_pktmbuf_tailroom(m)))
+ return NULL;
+
+ char *tail = (char *)m->buf_addr + m->data_off + m->data_len;
+ m->data_len = (uint16_t)(m->data_len + len);
+ m_head->pkt_len = (m_head->pkt_len + len);
+ return tail;
+}
+
/* Calculate index based on Table 5.1.3-3 from TS34.212 */
static inline int32_t
compute_idx(uint16_t k)
{
int32_t result = 0;
- if (k < 40 || k > MAX_CB_SIZE)
+ if (k < RTE_BBDEV_MIN_CB_SIZE || k > RTE_BBDEV_MAX_CB_SIZE)
return -1;
if (k > 2048) {
return result;
}
+#endif
/* Read flag value 0/1 from bitmap */
static inline bool
struct bbdev_private *internals = dev->data->dev_private;
static const struct rte_bbdev_op_cap bbdev_capabilities[] = {
+#ifdef RTE_BBDEV_SDK_AVX2
{
.type = RTE_BBDEV_OP_TURBO_DEC,
.cap.turbo_dec = {
RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN |
RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN |
RTE_BBDEV_TURBO_CRC_TYPE_24B |
+ RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP |
RTE_BBDEV_TURBO_EARLY_TERMINATION,
+ .max_llr_modulus = 16,
.num_buffers_src = RTE_BBDEV_MAX_CODE_BLOCKS,
.num_buffers_hard_out =
RTE_BBDEV_MAX_CODE_BLOCKS,
.num_buffers_dst = RTE_BBDEV_MAX_CODE_BLOCKS,
}
},
+#endif
RTE_BBDEV_END_OF_CAPABILITIES_LIST()
};
.queue_size = RTE_BBDEV_QUEUE_SIZE_LIMIT,
};
+#ifdef RTE_BBDEV_SDK_AVX2
static const enum rte_cpu_flag_t cpu_flag = RTE_CPUFLAG_SSE4_2;
+ dev_info->cpu_flag_reqs = &cpu_flag;
+#else
+ dev_info->cpu_flag_reqs = NULL;
+#endif
default_queue_conf.socket = dev->data->socket_id;
dev_info->max_num_queues = internals->max_nb_queues;
dev_info->queue_size_lim = RTE_BBDEV_QUEUE_SIZE_LIMIT;
dev_info->hardware_accelerated = false;
- dev_info->max_queue_priority = 0;
+ dev_info->max_dl_queue_priority = 0;
+ dev_info->max_ul_queue_priority = 0;
dev_info->default_queue_conf = default_queue_conf;
dev_info->capabilities = bbdev_capabilities;
- dev_info->cpu_flag_reqs = &cpu_flag;
dev_info->min_alignment = 64;
rte_bbdev_log_debug("got device info from %u\n", dev->data->dev_id);
}
/* Allocate memory for encoder output. */
- ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"_enc_out%u:%u",
+ ret = snprintf(name, RTE_RING_NAMESIZE, RTE_STR(DRIVER_NAME)"_enc_o%u:%u",
dev->data->dev_id, q_id);
if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->enc_out = rte_zmalloc_socket(name,
- ((MAX_TB_SIZE >> 3) + 3) * sizeof(*q->enc_out) * 3,
+ ((RTE_BBDEV_MAX_TB_SIZE >> 3) + 3) *
+ sizeof(*q->enc_out) * 3,
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->enc_out == NULL) {
rte_bbdev_log(ERR,
/* Allocate memory for rate matching output. */
ret = snprintf(name, RTE_RING_NAMESIZE,
- RTE_STR(DRIVER_NAME)"_enc_in%u:%u", dev->data->dev_id,
+ RTE_STR(DRIVER_NAME)"_enc_i%u:%u", dev->data->dev_id,
q_id);
if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->enc_in = rte_zmalloc_socket(name,
- (MAX_CB_SIZE >> 3) * sizeof(*q->enc_in),
+ (RTE_BBDEV_MAX_CB_SIZE >> 3) * sizeof(*q->enc_in),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->enc_in == NULL) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->ag = rte_zmalloc_socket(name,
- MAX_CB_SIZE * 10 * sizeof(*q->ag),
+ RTE_BBDEV_MAX_CB_SIZE * 10 * sizeof(*q->ag),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->ag == NULL) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->code_block = rte_zmalloc_socket(name,
- (6144 >> 3) * sizeof(*q->code_block),
+ RTE_BBDEV_MAX_CB_SIZE * sizeof(*q->code_block),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->code_block == NULL) {
rte_bbdev_log(ERR,
/* Allocate memory for Deinterleaver input. */
ret = snprintf(name, RTE_RING_NAMESIZE,
- RTE_STR(DRIVER_NAME)"_deint_input%u:%u",
+ RTE_STR(DRIVER_NAME)"_de_i%u:%u",
dev->data->dev_id, q_id);
if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->deint_input = rte_zmalloc_socket(name,
- MAX_KW * sizeof(*q->deint_input),
+ DEINT_INPUT_BUF_SIZE * sizeof(*q->deint_input),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->deint_input == NULL) {
rte_bbdev_log(ERR,
/* Allocate memory for Deinterleaver output. */
ret = snprintf(name, RTE_RING_NAMESIZE,
- RTE_STR(DRIVER_NAME)"_deint_output%u:%u",
+ RTE_STR(DRIVER_NAME)"_de_o%u:%u",
dev->data->dev_id, q_id);
if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->deint_output = rte_zmalloc_socket(NULL,
- MAX_KW * sizeof(*q->deint_output),
+ DEINT_OUTPUT_BUF_SIZE * sizeof(*q->deint_output),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->deint_output == NULL) {
rte_bbdev_log(ERR,
/* Allocate memory for Adapter output. */
ret = snprintf(name, RTE_RING_NAMESIZE,
- RTE_STR(DRIVER_NAME)"_adapter_output%u:%u",
+ RTE_STR(DRIVER_NAME)"_ada_o%u:%u",
dev->data->dev_id, q_id);
if ((ret < 0) || (ret >= (int)RTE_RING_NAMESIZE)) {
rte_bbdev_log(ERR,
return -ENAMETOOLONG;
}
q->adapter_output = rte_zmalloc_socket(NULL,
- MAX_CB_SIZE * 6 * sizeof(*q->adapter_output),
+ ADAPTER_OUTPUT_BUF_SIZE * sizeof(*q->adapter_output),
RTE_CACHE_LINE_SIZE, queue_conf->socket);
if (q->adapter_output == NULL) {
rte_bbdev_log(ERR,
.queue_release = q_release
};
+#ifdef RTE_BBDEV_SDK_AVX2
/* Checks if the encoder input buffer is correct.
* Returns 0 if it's valid, -1 otherwise.
*/
return -1;
}
- if (k > MAX_CB_SIZE) {
+ if (k > RTE_BBDEV_MAX_CB_SIZE) {
rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
- k, MAX_CB_SIZE);
+ k, RTE_BBDEV_MAX_CB_SIZE);
return -1;
}
return -1;
}
- if (in_length - kw < 0) {
+ if (in_length < kw) {
rte_bbdev_log(ERR,
"Mismatch between input length (%u) and kw (%u)",
in_length, kw);
return -1;
}
- if (kw > MAX_KW) {
+ if (kw > RTE_BBDEV_MAX_KW) {
rte_bbdev_log(ERR, "Input length (%u) is too big, max: %d",
- kw, MAX_KW);
+ kw, RTE_BBDEV_MAX_KW);
return -1;
}
return 0;
}
+#endif
static inline void
process_enc_cb(struct turbo_sw_queue *q, struct rte_bbdev_enc_op *op,
uint8_t r, uint8_t c, uint16_t k, uint16_t ncb,
- uint32_t e, struct rte_mbuf *m_in, struct rte_mbuf *m_out,
- uint16_t in_offset, uint16_t out_offset, uint16_t total_left)
+ uint32_t e, struct rte_mbuf *m_in, struct rte_mbuf *m_out_head,
+ struct rte_mbuf *m_out, uint16_t in_offset, uint16_t out_offset,
+ uint16_t in_length, struct rte_bbdev_stats *q_stats)
{
+#ifdef RTE_BBDEV_SDK_AVX2
int ret;
int16_t k_idx;
uint16_t m;
struct bblib_turbo_encoder_response turbo_resp;
struct bblib_rate_match_dl_request rm_req;
struct bblib_rate_match_dl_response rm_resp;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ uint64_t start_time;
+#else
+ RTE_SET_USED(q_stats);
+#endif
k_idx = compute_idx(k);
in = rte_pktmbuf_mtod_offset(m_in, uint8_t *, in_offset);
/* CRC24A (for TB) */
if ((enc->op_flags & RTE_BBDEV_TURBO_CRC_24A_ATTACH) &&
(enc->code_block_mode == 1)) {
- ret = is_enc_input_valid(k - 24, k_idx, total_left);
+ ret = is_enc_input_valid(k - 24, k_idx, in_length);
if (ret != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
return;
}
crc_req.data = in;
- crc_req.len = (k - 24) >> 3;
- /* Check if there is a room for CRC bits. If not use
+ crc_req.len = k - 24;
+ /* Check if there is a room for CRC bits if not use
* the temporary buffer.
*/
- if (rte_pktmbuf_append(m_in, 3) == NULL) {
+ if (mbuf_append(m_in, m_in, 3) == NULL) {
rte_memcpy(q->enc_in, in, (k - 24) >> 3);
in = q->enc_in;
} else {
}
crc_resp.data = in;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* CRC24A generation */
bblib_lte_crc24a_gen(&crc_req, &crc_resp);
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
} else if (enc->op_flags & RTE_BBDEV_TURBO_CRC_24B_ATTACH) {
/* CRC24B */
- ret = is_enc_input_valid(k - 24, k_idx, total_left);
+ ret = is_enc_input_valid(k - 24, k_idx, in_length);
if (ret != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
return;
}
crc_req.data = in;
- crc_req.len = (k - 24) >> 3;
- /* Check if there is a room for CRC bits. If this is the last
+ crc_req.len = k - 24;
+ /* Check if there is a room for CRC bits if this is the last
* CB in TB. If not use temporary buffer.
*/
- if ((c - r == 1) && (rte_pktmbuf_append(m_in, 3) == NULL)) {
+ if ((c - r == 1) && (mbuf_append(m_in, m_in, 3) == NULL)) {
rte_memcpy(q->enc_in, in, (k - 24) >> 3);
in = q->enc_in;
} else if (c - r > 1) {
}
crc_resp.data = in;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* CRC24B generation */
bblib_lte_crc24b_gen(&crc_req, &crc_resp);
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
} else {
- ret = is_enc_input_valid(k, k_idx, total_left);
+ ret = is_enc_input_valid(k, k_idx, in_length);
if (ret != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
return;
out1 = RTE_PTR_ADD(out0, (k >> 3) + 1);
out2 = RTE_PTR_ADD(out1, (k >> 3) + 1);
} else {
- out0 = (uint8_t *)rte_pktmbuf_append(m_out, (k >> 3) * 3 + 2);
+ out0 = (uint8_t *)mbuf_append(m_out_head, m_out,
+ (k >> 3) * 3 + 2);
if (out0 == NULL) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR,
turbo_resp.output_win_0 = out0;
turbo_resp.output_win_1 = out1;
turbo_resp.output_win_2 = out2;
+
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* Turbo encoding */
if (bblib_turbo_encoder(&turbo_req, &turbo_resp) != 0) {
op->status |= 1 << RTE_BBDEV_DRV_ERROR;
rte_bbdev_log(ERR, "Turbo Encoder failed");
return;
}
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
/* Restore 3 first bytes of next CB if they were overwritten by CRC*/
if (first_3_bytes != 0)
/* Rate-matching */
if (enc->op_flags & RTE_BBDEV_TURBO_RATE_MATCH) {
+ uint8_t mask_id;
+ /* Integer round up division by 8 */
+ uint16_t out_len = (e + 7) >> 3;
+ /* The mask array is indexed using E%8. E is an even number so
+ * there are only 4 possible values.
+ */
+ const uint8_t mask_out[] = {0xFF, 0xC0, 0xF0, 0xFC};
+
/* get output data starting address */
- rm_out = (uint8_t *)rte_pktmbuf_append(m_out, (e >> 3));
+ rm_out = (uint8_t *)mbuf_append(m_out_head, m_out, out_len);
if (rm_out == NULL) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR,
rm_req.tin1 = out1;
rm_req.tin2 = out2;
rm_resp.output = rm_out;
- rm_resp.OutputLen = (e >> 3);
+ rm_resp.OutputLen = out_len;
if (enc->op_flags & RTE_BBDEV_TURBO_RV_INDEX_BYPASS)
rm_req.bypass_rvidx = 1;
else
rm_req.bypass_rvidx = 0;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* Rate-Matching */
if (bblib_rate_match_dl(&rm_req, &rm_resp) != 0) {
op->status |= 1 << RTE_BBDEV_DRV_ERROR;
rte_bbdev_log(ERR, "Rate matching failed");
return;
}
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
+
+ /* SW fills an entire last byte even if E%8 != 0. Clear the
+ * superfluous data bits for consistency with HW device.
+ */
+ mask_id = (e & 7) >> 1;
+ rm_out[out_len - 1] &= mask_out[mask_id];
enc->output.length += rm_resp.OutputLen;
} else {
/* Rate matching is bypassed */
}
*tmp_out = 0;
}
+#else
+ RTE_SET_USED(q);
+ RTE_SET_USED(op);
+ RTE_SET_USED(r);
+ RTE_SET_USED(c);
+ RTE_SET_USED(k);
+ RTE_SET_USED(ncb);
+ RTE_SET_USED(e);
+ RTE_SET_USED(m_in);
+ RTE_SET_USED(m_out_head);
+ RTE_SET_USED(m_out);
+ RTE_SET_USED(in_offset);
+ RTE_SET_USED(out_offset);
+ RTE_SET_USED(in_length);
+ RTE_SET_USED(q_stats);
+#endif
}
static inline void
-enqueue_enc_one_op(struct turbo_sw_queue *q, struct rte_bbdev_enc_op *op)
+enqueue_enc_one_op(struct turbo_sw_queue *q, struct rte_bbdev_enc_op *op,
+ struct rte_bbdev_stats *queue_stats)
{
uint8_t c, r, crc24_bits = 0;
uint16_t k, ncb;
uint16_t out_offset = enc->output.offset;
struct rte_mbuf *m_in = enc->input.data;
struct rte_mbuf *m_out = enc->output.data;
- uint16_t total_left = enc->input.length;
+ struct rte_mbuf *m_out_head = enc->output.data;
+ uint32_t in_length, mbuf_total_left = enc->input.length;
+ uint16_t seg_total_left;
/* Clear op status */
op->status = 0;
- if (total_left > MAX_TB_SIZE >> 3) {
+ if (mbuf_total_left > RTE_BBDEV_MAX_TB_SIZE >> 3) {
rte_bbdev_log(ERR, "TB size (%u) is too big, max: %d",
- total_left, MAX_TB_SIZE);
+ mbuf_total_left, RTE_BBDEV_MAX_TB_SIZE);
op->status = 1 << RTE_BBDEV_DATA_ERROR;
return;
}
r = 0;
}
- while (total_left > 0 && r < c) {
+ while (mbuf_total_left > 0 && r < c) {
+
+ seg_total_left = rte_pktmbuf_data_len(m_in) - in_offset;
+
if (enc->code_block_mode == 0) {
k = (r < enc->tb_params.c_neg) ?
enc->tb_params.k_neg : enc->tb_params.k_pos;
e = enc->cb_params.e;
}
- process_enc_cb(q, op, r, c, k, ncb, e, m_in,
- m_out, in_offset, out_offset, total_left);
+ process_enc_cb(q, op, r, c, k, ncb, e, m_in, m_out_head,
+ m_out, in_offset, out_offset, seg_total_left,
+ queue_stats);
/* Update total_left */
- total_left -= (k - crc24_bits) >> 3;
+ in_length = ((k - crc24_bits) >> 3);
+ mbuf_total_left -= in_length;
/* Update offsets for next CBs (if exist) */
in_offset += (k - crc24_bits) >> 3;
if (enc->op_flags & RTE_BBDEV_TURBO_RATE_MATCH)
out_offset += e >> 3;
else
out_offset += (k >> 3) * 3 + 2;
+
+ /* Update offsets */
+ if (seg_total_left == in_length) {
+ /* Go to the next mbuf */
+ m_in = m_in->next;
+ m_out = m_out->next;
+ in_offset = 0;
+ out_offset = 0;
+ }
r++;
}
/* check if all input data was processed */
- if (total_left != 0) {
+ if (mbuf_total_left != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR,
"Mismatch between mbuf length and included CBs sizes");
static inline uint16_t
enqueue_enc_all_ops(struct turbo_sw_queue *q, struct rte_bbdev_enc_op **ops,
- uint16_t nb_ops)
+ uint16_t nb_ops, struct rte_bbdev_stats *queue_stats)
{
uint16_t i;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ queue_stats->acc_offload_cycles = 0;
+#endif
for (i = 0; i < nb_ops; ++i)
- enqueue_enc_one_op(q, ops[i]);
+ enqueue_enc_one_op(q, ops[i], queue_stats);
return rte_ring_enqueue_burst(q->processed_pkts, (void **)ops, nb_ops,
NULL);
}
-/* Remove the padding bytes from a cyclic buffer.
- * The input buffer is a data stream wk as described in 3GPP TS 36.212 section
- * 5.1.4.1.2 starting from w0 and with length Ncb bytes.
- * The output buffer is a data stream wk with pruned padding bytes. It's length
- * is 3*D bytes and the order of non-padding bytes is preserved.
- */
-static inline void
-remove_nulls_from_circular_buf(const uint8_t *in, uint8_t *out, uint16_t k,
- uint16_t ncb)
-{
- uint32_t in_idx, out_idx, c_idx;
- const uint32_t d = k + 4;
- const uint32_t kw = (ncb / 3);
- const uint32_t nd = kw - d;
- const uint32_t r_subblock = kw / C_SUBBLOCK;
- /* Inter-column permutation pattern */
- const uint32_t P[C_SUBBLOCK] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10,
- 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19,
- 11, 27, 7, 23, 15, 31};
- in_idx = 0;
- out_idx = 0;
-
- /* The padding bytes are at the first Nd positions in the first row. */
- for (c_idx = 0; in_idx < kw; in_idx += r_subblock, ++c_idx) {
- if (P[c_idx] < nd) {
- rte_memcpy(&out[out_idx], &in[in_idx + 1],
- r_subblock - 1);
- out_idx += r_subblock - 1;
- } else {
- rte_memcpy(&out[out_idx], &in[in_idx], r_subblock);
- out_idx += r_subblock;
- }
- }
-
- /* First and second parity bits sub-blocks are interlaced. */
- for (c_idx = 0; in_idx < ncb - 2 * r_subblock;
- in_idx += 2 * r_subblock, ++c_idx) {
- uint32_t second_block_c_idx = P[c_idx];
- uint32_t third_block_c_idx = P[c_idx] + 1;
-
- if (second_block_c_idx < nd && third_block_c_idx < nd) {
- rte_memcpy(&out[out_idx], &in[in_idx + 2],
- 2 * r_subblock - 2);
- out_idx += 2 * r_subblock - 2;
- } else if (second_block_c_idx >= nd &&
- third_block_c_idx >= nd) {
- rte_memcpy(&out[out_idx], &in[in_idx], 2 * r_subblock);
- out_idx += 2 * r_subblock;
- } else if (second_block_c_idx < nd) {
- out[out_idx++] = in[in_idx];
- rte_memcpy(&out[out_idx], &in[in_idx + 2],
- 2 * r_subblock - 2);
- out_idx += 2 * r_subblock - 2;
- } else {
- rte_memcpy(&out[out_idx], &in[in_idx + 1],
- 2 * r_subblock - 1);
- out_idx += 2 * r_subblock - 1;
- }
- }
-
- /* Last interlaced row is different - its last byte is the only padding
- * byte. We can have from 2 up to 26 padding bytes (Nd) per sub-block.
- * After interlacing the 1st and 2nd parity sub-blocks we can have 0, 1
- * or 2 padding bytes each time we make a step of 2 * R_SUBBLOCK bytes
- * (moving to another column). 2nd parity sub-block uses the same
- * inter-column permutation pattern as the systematic and 1st parity
- * sub-blocks but it adds '1' to the resulting index and calculates the
- * modulus of the result and Kw. Last column is mapped to itself (id 31)
- * so the first byte taken from the 2nd parity sub-block will be the
- * 32nd (31+1) byte, then 64th etc. (step is C_SUBBLOCK == 32) and the
- * last byte will be the first byte from the sub-block:
- * (32 + 32 * (R_SUBBLOCK-1)) % Kw == Kw % Kw == 0. Nd can't be smaller
- * than 2 so we know that bytes with ids 0 and 1 must be the padding
- * bytes. The bytes from the 1st parity sub-block are the bytes from the
- * 31st column - Nd can't be greater than 26 so we are sure that there
- * are no padding bytes in 31st column.
- */
- rte_memcpy(&out[out_idx], &in[in_idx], 2 * r_subblock - 1);
-}
-
+#ifdef RTE_BBDEV_SDK_AVX2
static inline void
move_padding_bytes(const uint8_t *in, uint8_t *out, uint16_t k,
uint16_t ncb)
rte_memcpy(&out[nd], in, d);
rte_memcpy(&out[nd + kpi + 64], &in[kpi], d);
- rte_memcpy(&out[nd + 2 * (kpi + 64)], &in[2 * kpi], d);
+ rte_memcpy(&out[(nd - 1) + 2 * (kpi + 64)], &in[2 * kpi], d);
}
+#endif
static inline void
process_dec_cb(struct turbo_sw_queue *q, struct rte_bbdev_dec_op *op,
uint8_t c, uint16_t k, uint16_t kw, struct rte_mbuf *m_in,
- struct rte_mbuf *m_out, uint16_t in_offset, uint16_t out_offset,
- bool check_crc_24b, uint16_t total_left)
+ struct rte_mbuf *m_out_head, struct rte_mbuf *m_out,
+ uint16_t in_offset, uint16_t out_offset, bool check_crc_24b,
+ uint16_t crc24_overlap, uint16_t in_length,
+ struct rte_bbdev_stats *q_stats)
{
+#ifdef RTE_BBDEV_SDK_AVX2
int ret;
int32_t k_idx;
int32_t iter_cnt;
struct bblib_turbo_decoder_request turbo_req;
struct bblib_turbo_decoder_response turbo_resp;
struct rte_bbdev_op_turbo_dec *dec = &op->turbo_dec;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ uint64_t start_time;
+#else
+ RTE_SET_USED(q_stats);
+#endif
k_idx = compute_idx(k);
- ret = is_dec_input_valid(k_idx, kw, total_left);
+ ret = is_dec_input_valid(k_idx, kw, in_length);
if (ret != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
return;
struct bblib_deinterleave_ul_request deint_req;
struct bblib_deinterleave_ul_response deint_resp;
- /* SW decoder accepts only a circular buffer without NULL bytes
- * so the input needs to be converted.
- */
- remove_nulls_from_circular_buf(in, q->deint_input, k, ncb);
-
- deint_req.pharqbuffer = q->deint_input;
- deint_req.ncb = ncb_without_null;
+ deint_req.circ_buffer = BBLIB_FULL_CIRCULAR_BUFFER;
+ deint_req.pharqbuffer = in;
+ deint_req.ncb = ncb;
deint_resp.pinteleavebuffer = q->deint_output;
+
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
bblib_deinterleave_ul(&deint_req, &deint_resp);
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
} else
move_padding_bytes(in, q->deint_output, k, ncb);
adapter_req.ncb = ncb_without_null;
adapter_req.pinteleavebuffer = adapter_input;
adapter_resp.pharqout = q->adapter_output;
+
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* Turbo decode adaptation */
bblib_turbo_adapter_ul(&adapter_req, &adapter_resp);
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
- out = (uint8_t *)rte_pktmbuf_append(m_out, (k >> 3));
+ out = (uint8_t *)mbuf_append(m_out_head, m_out,
+ ((k - crc24_overlap) >> 3));
if (out == NULL) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR, "Too little space in output mbuf");
turbo_req.k = k;
turbo_req.k_idx = k_idx;
turbo_req.max_iter_num = dec->iter_max;
+ turbo_req.early_term_disable = !check_bit(dec->op_flags,
+ RTE_BBDEV_TURBO_EARLY_TERMINATION);
turbo_resp.ag_buf = q->ag;
turbo_resp.cb_buf = q->code_block;
turbo_resp.output = out;
+
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ start_time = rte_rdtsc_precise();
+#endif
+ /* Turbo decode */
iter_cnt = bblib_turbo_decoder(&turbo_req, &turbo_resp);
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ q_stats->acc_offload_cycles += rte_rdtsc_precise() - start_time;
+#endif
dec->hard_output.length += (k >> 3);
if (iter_cnt > 0) {
/* Temporary solution for returned iter_count from SDK */
- iter_cnt = (iter_cnt - 1) / 2;
+ iter_cnt = (iter_cnt - 1) >> 1;
dec->iter_count = RTE_MAX(iter_cnt, dec->iter_count);
} else {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR, "Turbo Decoder failed");
return;
}
+#else
+ RTE_SET_USED(q);
+ RTE_SET_USED(op);
+ RTE_SET_USED(c);
+ RTE_SET_USED(k);
+ RTE_SET_USED(kw);
+ RTE_SET_USED(m_in);
+ RTE_SET_USED(m_out_head);
+ RTE_SET_USED(m_out);
+ RTE_SET_USED(in_offset);
+ RTE_SET_USED(out_offset);
+ RTE_SET_USED(check_crc_24b);
+ RTE_SET_USED(crc24_overlap);
+ RTE_SET_USED(in_length);
+ RTE_SET_USED(q_stats);
+#endif
}
static inline void
-enqueue_dec_one_op(struct turbo_sw_queue *q, struct rte_bbdev_dec_op *op)
+enqueue_dec_one_op(struct turbo_sw_queue *q, struct rte_bbdev_dec_op *op,
+ struct rte_bbdev_stats *queue_stats)
{
uint8_t c, r = 0;
uint16_t kw, k = 0;
+ uint16_t crc24_overlap = 0;
struct rte_bbdev_op_turbo_dec *dec = &op->turbo_dec;
struct rte_mbuf *m_in = dec->input.data;
struct rte_mbuf *m_out = dec->hard_output.data;
+ struct rte_mbuf *m_out_head = dec->hard_output.data;
uint16_t in_offset = dec->input.offset;
- uint16_t total_left = dec->input.length;
uint16_t out_offset = dec->hard_output.offset;
+ uint32_t mbuf_total_left = dec->input.length;
+ uint16_t seg_total_left;
/* Clear op status */
op->status = 0;
c = 1;
}
- while (total_left > 0) {
+ if ((c > 1) && !check_bit(dec->op_flags,
+ RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP))
+ crc24_overlap = 24;
+
+ while (mbuf_total_left > 0) {
if (dec->code_block_mode == 0)
k = (r < dec->tb_params.c_neg) ?
dec->tb_params.k_neg : dec->tb_params.k_pos;
+ seg_total_left = rte_pktmbuf_data_len(m_in) - in_offset;
+
/* Calculates circular buffer size (Kw).
* According to 3gpp 36.212 section 5.1.4.2
* Kw = 3 * Kpi,
* where D is the size of each output from turbo encoder block
* (k + 4).
*/
- kw = RTE_ALIGN_CEIL(k + 4, C_SUBBLOCK) * 3;
-
- process_dec_cb(q, op, c, k, kw, m_in, m_out, in_offset,
- out_offset, check_bit(dec->op_flags,
- RTE_BBDEV_TURBO_CRC_TYPE_24B), total_left);
- /* As a result of decoding we get Code Block with included
- * decoded CRC24 at the end of Code Block. Type of CRC24 is
- * specified by flag.
+ kw = RTE_ALIGN_CEIL(k + 4, RTE_BBDEV_C_SUBBLOCK) * 3;
+
+ process_dec_cb(q, op, c, k, kw, m_in, m_out_head, m_out,
+ in_offset, out_offset, check_bit(dec->op_flags,
+ RTE_BBDEV_TURBO_CRC_TYPE_24B), crc24_overlap,
+ seg_total_left, queue_stats);
+ /* To keep CRC24 attached to end of Code block, use
+ * RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP flag as it
+ * removed by default once verified.
*/
- /* Update total_left */
- total_left -= kw;
- /* Update offsets for next CBs (if exist) */
- in_offset += kw;
- out_offset += (k >> 3);
+ mbuf_total_left -= kw;
+
+ /* Update offsets */
+ if (seg_total_left == kw) {
+ /* Go to the next mbuf */
+ m_in = m_in->next;
+ m_out = m_out->next;
+ in_offset = 0;
+ out_offset = 0;
+ } else {
+ /* Update offsets for next CBs (if exist) */
+ in_offset += kw;
+ out_offset += ((k - crc24_overlap) >> 3);
+ }
r++;
}
- if (total_left != 0) {
+ if (mbuf_total_left != 0) {
op->status |= 1 << RTE_BBDEV_DATA_ERROR;
rte_bbdev_log(ERR,
"Mismatch between mbuf length and included Circular buffer sizes");
static inline uint16_t
enqueue_dec_all_ops(struct turbo_sw_queue *q, struct rte_bbdev_dec_op **ops,
- uint16_t nb_ops)
+ uint16_t nb_ops, struct rte_bbdev_stats *queue_stats)
{
uint16_t i;
+#ifdef RTE_BBDEV_OFFLOAD_COST
+ queue_stats->acc_offload_cycles = 0;
+#endif
for (i = 0; i < nb_ops; ++i)
- enqueue_dec_one_op(q, ops[i]);
+ enqueue_dec_one_op(q, ops[i], queue_stats);
return rte_ring_enqueue_burst(q->processed_pkts, (void **)ops, nb_ops,
NULL);
struct turbo_sw_queue *q = queue;
uint16_t nb_enqueued = 0;
- nb_enqueued = enqueue_enc_all_ops(q, ops, nb_ops);
+ nb_enqueued = enqueue_enc_all_ops(q, ops, nb_ops, &q_data->queue_stats);
q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
q_data->queue_stats.enqueued_count += nb_enqueued;
struct turbo_sw_queue *q = queue;
uint16_t nb_enqueued = 0;
- nb_enqueued = enqueue_dec_all_ops(q, ops, nb_ops);
+ nb_enqueued = enqueue_dec_all_ops(q, ops, nb_ops, &q_data->queue_stats);
q_data->queue_stats.enqueue_err_count += nb_ops - nb_enqueued;
q_data->queue_stats.enqueued_count += nb_enqueued;
RTE_PMD_REGISTER_PARAM_STRING(DRIVER_NAME,
TURBO_SW_MAX_NB_QUEUES_ARG"=<int> "
TURBO_SW_SOCKET_ID_ARG"=<int>");
+RTE_PMD_REGISTER_ALIAS(DRIVER_NAME, turbo_sw);
-RTE_INIT(null_bbdev_init_log);
-static void
-null_bbdev_init_log(void)
+RTE_INIT(turbo_sw_bbdev_init_log)
{
bbdev_turbo_sw_logtype = rte_log_register("pmd.bb.turbo_sw");
if (bbdev_turbo_sw_logtype >= 0)