1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Intel Corporation
7 #include <rte_common.h>
8 #include <rte_bus_vdev.h>
9 #include <rte_malloc.h>
11 #include <rte_kvargs.h>
12 #include <rte_cycles.h>
14 #include <rte_bbdev.h>
15 #include <rte_bbdev_pmd.h>
17 #include <phy_turbo.h>
19 #include <phy_rate_match.h>
22 #define DRIVER_NAME baseband_turbo_sw
24 /* Turbo SW PMD logging ID */
25 static int bbdev_turbo_sw_logtype
;
27 /* Helper macro for logging */
28 #define rte_bbdev_log(level, fmt, ...) \
29 rte_log(RTE_LOG_ ## level, bbdev_turbo_sw_logtype, fmt "\n", \
32 #define rte_bbdev_log_debug(fmt, ...) \
33 rte_bbdev_log(DEBUG, RTE_STR(__LINE__) ":%s() " fmt, __func__, \
36 #define DEINT_INPUT_BUF_SIZE (((RTE_BBDEV_MAX_CB_SIZE >> 3) + 1) * 48)
37 #define DEINT_OUTPUT_BUF_SIZE (DEINT_INPUT_BUF_SIZE * 6)
38 #define ADAPTER_OUTPUT_BUF_SIZE ((RTE_BBDEV_MAX_CB_SIZE + 4) * 48)
40 /* private data structure */
41 struct bbdev_private
{
42 unsigned int max_nb_queues
; /**< Max number of queues */
45 /* Initialisation params structure that can be used by Turbo SW driver */
46 struct turbo_sw_params
{
47 int socket_id
; /*< Turbo SW device socket */
48 uint16_t queues_num
; /*< Turbo SW device queues number */
51 /* Accecptable params for Turbo SW devices */
52 #define TURBO_SW_MAX_NB_QUEUES_ARG "max_nb_queues"
53 #define TURBO_SW_SOCKET_ID_ARG "socket_id"
55 static const char * const turbo_sw_valid_params
[] = {
56 TURBO_SW_MAX_NB_QUEUES_ARG
,
57 TURBO_SW_SOCKET_ID_ARG
61 struct turbo_sw_queue
{
62 /* Ring for processed (encoded/decoded) operations which are ready to
65 struct rte_ring
*processed_pkts
;
66 /* Stores input for turbo encoder (used when CRC attachment is
70 /* Stores output from turbo encoder */
72 /* Alpha gamma buf for bblib_turbo_decoder() function */
74 /* Temp buf for bblib_turbo_decoder() function */
76 /* Input buf for bblib_rate_dematching_lte() function */
78 /* Output buf for bblib_rate_dematching_lte() function */
79 uint8_t *deint_output
;
80 /* Output buf for bblib_turbodec_adapter_lte() function */
81 uint8_t *adapter_output
;
82 /* Operation type of this queue */
83 enum rte_bbdev_op_type type
;
84 } __rte_cache_aligned
;
86 /* Calculate index based on Table 5.1.3-3 from TS34.212 */
88 compute_idx(uint16_t k
)
92 if (k
< RTE_BBDEV_MIN_CB_SIZE
|| k
> RTE_BBDEV_MAX_CB_SIZE
)
96 if ((k
- 2048) % 64 != 0)
99 result
= 124 + (k
- 2048) / 64;
100 } else if (k
<= 512) {
101 if ((k
- 40) % 8 != 0)
104 result
= (k
- 40) / 8 + 1;
105 } else if (k
<= 1024) {
106 if ((k
- 512) % 16 != 0)
109 result
= 60 + (k
- 512) / 16;
110 } else { /* 1024 < k <= 2048 */
111 if ((k
- 1024) % 32 != 0)
114 result
= 92 + (k
- 1024) / 32;
120 /* Read flag value 0/1 from bitmap */
122 check_bit(uint32_t bitmap
, uint32_t bitmask
)
124 return bitmap
& bitmask
;
127 /* Get device info */
129 info_get(struct rte_bbdev
*dev
, struct rte_bbdev_driver_info
*dev_info
)
131 struct bbdev_private
*internals
= dev
->data
->dev_private
;
133 static const struct rte_bbdev_op_cap bbdev_capabilities
[] = {
135 .type
= RTE_BBDEV_OP_TURBO_DEC
,
138 RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE
|
139 RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN
|
140 RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN
|
141 RTE_BBDEV_TURBO_CRC_TYPE_24B
|
142 RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP
|
143 RTE_BBDEV_TURBO_EARLY_TERMINATION
,
144 .max_llr_modulus
= 16,
145 .num_buffers_src
= RTE_BBDEV_MAX_CODE_BLOCKS
,
146 .num_buffers_hard_out
=
147 RTE_BBDEV_MAX_CODE_BLOCKS
,
148 .num_buffers_soft_out
= 0,
152 .type
= RTE_BBDEV_OP_TURBO_ENC
,
155 RTE_BBDEV_TURBO_CRC_24B_ATTACH
|
156 RTE_BBDEV_TURBO_CRC_24A_ATTACH
|
157 RTE_BBDEV_TURBO_RATE_MATCH
|
158 RTE_BBDEV_TURBO_RV_INDEX_BYPASS
,
159 .num_buffers_src
= RTE_BBDEV_MAX_CODE_BLOCKS
,
160 .num_buffers_dst
= RTE_BBDEV_MAX_CODE_BLOCKS
,
163 RTE_BBDEV_END_OF_CAPABILITIES_LIST()
166 static struct rte_bbdev_queue_conf default_queue_conf
= {
167 .queue_size
= RTE_BBDEV_QUEUE_SIZE_LIMIT
,
170 static const enum rte_cpu_flag_t cpu_flag
= RTE_CPUFLAG_SSE4_2
;
172 default_queue_conf
.socket
= dev
->data
->socket_id
;
174 dev_info
->driver_name
= RTE_STR(DRIVER_NAME
);
175 dev_info
->max_num_queues
= internals
->max_nb_queues
;
176 dev_info
->queue_size_lim
= RTE_BBDEV_QUEUE_SIZE_LIMIT
;
177 dev_info
->hardware_accelerated
= false;
178 dev_info
->max_dl_queue_priority
= 0;
179 dev_info
->max_ul_queue_priority
= 0;
180 dev_info
->default_queue_conf
= default_queue_conf
;
181 dev_info
->capabilities
= bbdev_capabilities
;
182 dev_info
->cpu_flag_reqs
= &cpu_flag
;
183 dev_info
->min_alignment
= 64;
185 rte_bbdev_log_debug("got device info from %u\n", dev
->data
->dev_id
);
190 q_release(struct rte_bbdev
*dev
, uint16_t q_id
)
192 struct turbo_sw_queue
*q
= dev
->data
->queues
[q_id
].queue_private
;
195 rte_ring_free(q
->processed_pkts
);
196 rte_free(q
->enc_out
);
199 rte_free(q
->code_block
);
200 rte_free(q
->deint_input
);
201 rte_free(q
->deint_output
);
202 rte_free(q
->adapter_output
);
204 dev
->data
->queues
[q_id
].queue_private
= NULL
;
207 rte_bbdev_log_debug("released device queue %u:%u",
208 dev
->data
->dev_id
, q_id
);
214 q_setup(struct rte_bbdev
*dev
, uint16_t q_id
,
215 const struct rte_bbdev_queue_conf
*queue_conf
)
218 struct turbo_sw_queue
*q
;
219 char name
[RTE_RING_NAMESIZE
];
221 /* Allocate the queue data structure. */
222 q
= rte_zmalloc_socket(RTE_STR(DRIVER_NAME
), sizeof(*q
),
223 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
225 rte_bbdev_log(ERR
, "Failed to allocate queue memory");
229 /* Allocate memory for encoder output. */
230 ret
= snprintf(name
, RTE_RING_NAMESIZE
, RTE_STR(DRIVER_NAME
)"_enc_o%u:%u",
231 dev
->data
->dev_id
, q_id
);
232 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
234 "Creating queue name for device %u queue %u failed",
235 dev
->data
->dev_id
, q_id
);
236 return -ENAMETOOLONG
;
238 q
->enc_out
= rte_zmalloc_socket(name
,
239 ((RTE_BBDEV_MAX_TB_SIZE
>> 3) + 3) *
240 sizeof(*q
->enc_out
) * 3,
241 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
242 if (q
->enc_out
== NULL
) {
244 "Failed to allocate queue memory for %s", name
);
248 /* Allocate memory for rate matching output. */
249 ret
= snprintf(name
, RTE_RING_NAMESIZE
,
250 RTE_STR(DRIVER_NAME
)"_enc_i%u:%u", dev
->data
->dev_id
,
252 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
254 "Creating queue name for device %u queue %u failed",
255 dev
->data
->dev_id
, q_id
);
256 return -ENAMETOOLONG
;
258 q
->enc_in
= rte_zmalloc_socket(name
,
259 (RTE_BBDEV_MAX_CB_SIZE
>> 3) * sizeof(*q
->enc_in
),
260 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
261 if (q
->enc_in
== NULL
) {
263 "Failed to allocate queue memory for %s", name
);
267 /* Allocate memory for Aplha Gamma temp buffer. */
268 ret
= snprintf(name
, RTE_RING_NAMESIZE
, RTE_STR(DRIVER_NAME
)"_ag%u:%u",
269 dev
->data
->dev_id
, q_id
);
270 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
272 "Creating queue name for device %u queue %u failed",
273 dev
->data
->dev_id
, q_id
);
274 return -ENAMETOOLONG
;
276 q
->ag
= rte_zmalloc_socket(name
,
277 RTE_BBDEV_MAX_CB_SIZE
* 10 * sizeof(*q
->ag
),
278 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
281 "Failed to allocate queue memory for %s", name
);
285 /* Allocate memory for code block temp buffer. */
286 ret
= snprintf(name
, RTE_RING_NAMESIZE
, RTE_STR(DRIVER_NAME
)"_cb%u:%u",
287 dev
->data
->dev_id
, q_id
);
288 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
290 "Creating queue name for device %u queue %u failed",
291 dev
->data
->dev_id
, q_id
);
292 return -ENAMETOOLONG
;
294 q
->code_block
= rte_zmalloc_socket(name
,
295 RTE_BBDEV_MAX_CB_SIZE
* sizeof(*q
->code_block
),
296 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
297 if (q
->code_block
== NULL
) {
299 "Failed to allocate queue memory for %s", name
);
303 /* Allocate memory for Deinterleaver input. */
304 ret
= snprintf(name
, RTE_RING_NAMESIZE
,
305 RTE_STR(DRIVER_NAME
)"_de_i%u:%u",
306 dev
->data
->dev_id
, q_id
);
307 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
309 "Creating queue name for device %u queue %u failed",
310 dev
->data
->dev_id
, q_id
);
311 return -ENAMETOOLONG
;
313 q
->deint_input
= rte_zmalloc_socket(name
,
314 DEINT_INPUT_BUF_SIZE
* sizeof(*q
->deint_input
),
315 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
316 if (q
->deint_input
== NULL
) {
318 "Failed to allocate queue memory for %s", name
);
322 /* Allocate memory for Deinterleaver output. */
323 ret
= snprintf(name
, RTE_RING_NAMESIZE
,
324 RTE_STR(DRIVER_NAME
)"_de_o%u:%u",
325 dev
->data
->dev_id
, q_id
);
326 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
328 "Creating queue name for device %u queue %u failed",
329 dev
->data
->dev_id
, q_id
);
330 return -ENAMETOOLONG
;
332 q
->deint_output
= rte_zmalloc_socket(NULL
,
333 DEINT_OUTPUT_BUF_SIZE
* sizeof(*q
->deint_output
),
334 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
335 if (q
->deint_output
== NULL
) {
337 "Failed to allocate queue memory for %s", name
);
341 /* Allocate memory for Adapter output. */
342 ret
= snprintf(name
, RTE_RING_NAMESIZE
,
343 RTE_STR(DRIVER_NAME
)"_ada_o%u:%u",
344 dev
->data
->dev_id
, q_id
);
345 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
347 "Creating queue name for device %u queue %u failed",
348 dev
->data
->dev_id
, q_id
);
349 return -ENAMETOOLONG
;
351 q
->adapter_output
= rte_zmalloc_socket(NULL
,
352 ADAPTER_OUTPUT_BUF_SIZE
* sizeof(*q
->adapter_output
),
353 RTE_CACHE_LINE_SIZE
, queue_conf
->socket
);
354 if (q
->adapter_output
== NULL
) {
356 "Failed to allocate queue memory for %s", name
);
360 /* Create ring for packets awaiting to be dequeued. */
361 ret
= snprintf(name
, RTE_RING_NAMESIZE
, RTE_STR(DRIVER_NAME
)"%u:%u",
362 dev
->data
->dev_id
, q_id
);
363 if ((ret
< 0) || (ret
>= (int)RTE_RING_NAMESIZE
)) {
365 "Creating queue name for device %u queue %u failed",
366 dev
->data
->dev_id
, q_id
);
367 return -ENAMETOOLONG
;
369 q
->processed_pkts
= rte_ring_create(name
, queue_conf
->queue_size
,
370 queue_conf
->socket
, RING_F_SP_ENQ
| RING_F_SC_DEQ
);
371 if (q
->processed_pkts
== NULL
) {
372 rte_bbdev_log(ERR
, "Failed to create ring for %s", name
);
376 q
->type
= queue_conf
->op_type
;
378 dev
->data
->queues
[q_id
].queue_private
= q
;
379 rte_bbdev_log_debug("setup device queue %s", name
);
383 rte_ring_free(q
->processed_pkts
);
384 rte_free(q
->enc_out
);
387 rte_free(q
->code_block
);
388 rte_free(q
->deint_input
);
389 rte_free(q
->deint_output
);
390 rte_free(q
->adapter_output
);
395 static const struct rte_bbdev_ops pmd_ops
= {
396 .info_get
= info_get
,
397 .queue_setup
= q_setup
,
398 .queue_release
= q_release
401 /* Checks if the encoder input buffer is correct.
402 * Returns 0 if it's valid, -1 otherwise.
405 is_enc_input_valid(const uint16_t k
, const int32_t k_idx
,
406 const uint16_t in_length
)
409 rte_bbdev_log(ERR
, "K Index is invalid");
413 if (in_length
- (k
>> 3) < 0) {
415 "Mismatch between input length (%u bytes) and K (%u bits)",
420 if (k
> RTE_BBDEV_MAX_CB_SIZE
) {
421 rte_bbdev_log(ERR
, "CB size (%u) is too big, max: %d",
422 k
, RTE_BBDEV_MAX_CB_SIZE
);
429 /* Checks if the decoder input buffer is correct.
430 * Returns 0 if it's valid, -1 otherwise.
433 is_dec_input_valid(int32_t k_idx
, int16_t kw
, int16_t in_length
)
436 rte_bbdev_log(ERR
, "K index is invalid");
440 if (in_length
- kw
< 0) {
442 "Mismatch between input length (%u) and kw (%u)",
447 if (kw
> RTE_BBDEV_MAX_KW
) {
448 rte_bbdev_log(ERR
, "Input length (%u) is too big, max: %d",
449 kw
, RTE_BBDEV_MAX_KW
);
457 process_enc_cb(struct turbo_sw_queue
*q
, struct rte_bbdev_enc_op
*op
,
458 uint8_t r
, uint8_t c
, uint16_t k
, uint16_t ncb
,
459 uint32_t e
, struct rte_mbuf
*m_in
, struct rte_mbuf
*m_out
,
460 uint16_t in_offset
, uint16_t out_offset
, uint16_t total_left
,
461 struct rte_bbdev_stats
*q_stats
)
466 uint8_t *in
, *out0
, *out1
, *out2
, *tmp_out
, *rm_out
;
467 uint64_t first_3_bytes
= 0;
468 struct rte_bbdev_op_turbo_enc
*enc
= &op
->turbo_enc
;
469 struct bblib_crc_request crc_req
;
470 struct bblib_crc_response crc_resp
;
471 struct bblib_turbo_encoder_request turbo_req
;
472 struct bblib_turbo_encoder_response turbo_resp
;
473 struct bblib_rate_match_dl_request rm_req
;
474 struct bblib_rate_match_dl_response rm_resp
;
475 #ifdef RTE_BBDEV_OFFLOAD_COST
478 RTE_SET_USED(q_stats
);
481 k_idx
= compute_idx(k
);
482 in
= rte_pktmbuf_mtod_offset(m_in
, uint8_t *, in_offset
);
484 /* CRC24A (for TB) */
485 if ((enc
->op_flags
& RTE_BBDEV_TURBO_CRC_24A_ATTACH
) &&
486 (enc
->code_block_mode
== 1)) {
487 ret
= is_enc_input_valid(k
- 24, k_idx
, total_left
);
489 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
493 crc_req
.len
= k
- 24;
494 /* Check if there is a room for CRC bits if not use
495 * the temporary buffer.
497 if (rte_pktmbuf_append(m_in
, 3) == NULL
) {
498 rte_memcpy(q
->enc_in
, in
, (k
- 24) >> 3);
501 /* Store 3 first bytes of next CB as they will be
502 * overwritten by CRC bytes. If it is the last CB then
503 * there is no point to store 3 next bytes and this
504 * if..else branch will be omitted.
506 first_3_bytes
= *((uint64_t *)&in
[(k
- 32) >> 3]);
510 #ifdef RTE_BBDEV_OFFLOAD_COST
511 start_time
= rte_rdtsc_precise();
513 bblib_lte_crc24a_gen(&crc_req
, &crc_resp
);
514 #ifdef RTE_BBDEV_OFFLOAD_COST
515 q_stats
->offload_time
+= rte_rdtsc_precise() - start_time
;
517 } else if (enc
->op_flags
& RTE_BBDEV_TURBO_CRC_24B_ATTACH
) {
519 ret
= is_enc_input_valid(k
- 24, k_idx
, total_left
);
521 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
525 crc_req
.len
= k
- 24;
526 /* Check if there is a room for CRC bits if this is the last
527 * CB in TB. If not use temporary buffer.
529 if ((c
- r
== 1) && (rte_pktmbuf_append(m_in
, 3) == NULL
)) {
530 rte_memcpy(q
->enc_in
, in
, (k
- 24) >> 3);
532 } else if (c
- r
> 1) {
533 /* Store 3 first bytes of next CB as they will be
534 * overwritten by CRC bytes. If it is the last CB then
535 * there is no point to store 3 next bytes and this
536 * if..else branch will be omitted.
538 first_3_bytes
= *((uint64_t *)&in
[(k
- 32) >> 3]);
542 #ifdef RTE_BBDEV_OFFLOAD_COST
543 start_time
= rte_rdtsc_precise();
545 bblib_lte_crc24b_gen(&crc_req
, &crc_resp
);
546 #ifdef RTE_BBDEV_OFFLOAD_COST
547 q_stats
->offload_time
+= rte_rdtsc_precise() - start_time
;
550 ret
= is_enc_input_valid(k
, k_idx
, total_left
);
552 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
559 /* Each bit layer output from turbo encoder is (k+4) bits long, i.e.
560 * input length + 4 tail bits. That's (k/8) + 1 bytes after rounding up.
561 * So dst_data's length should be 3*(k/8) + 3 bytes.
562 * In Rate-matching bypass case outputs pointers passed to encoder
563 * (out0, out1 and out2) can directly point to addresses of output from
566 if (enc
->op_flags
& RTE_BBDEV_TURBO_RATE_MATCH
) {
568 out1
= RTE_PTR_ADD(out0
, (k
>> 3) + 1);
569 out2
= RTE_PTR_ADD(out1
, (k
>> 3) + 1);
571 out0
= (uint8_t *)rte_pktmbuf_append(m_out
, (k
>> 3) * 3 + 2);
573 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
575 "Too little space in output mbuf");
578 enc
->output
.length
+= (k
>> 3) * 3 + 2;
579 /* rte_bbdev_op_data.offset can be different than the
580 * offset of the appended bytes
582 out0
= rte_pktmbuf_mtod_offset(m_out
, uint8_t *, out_offset
);
583 out1
= rte_pktmbuf_mtod_offset(m_out
, uint8_t *,
584 out_offset
+ (k
>> 3) + 1);
585 out2
= rte_pktmbuf_mtod_offset(m_out
, uint8_t *,
586 out_offset
+ 2 * ((k
>> 3) + 1));
589 turbo_req
.case_id
= k_idx
;
590 turbo_req
.input_win
= in
;
591 turbo_req
.length
= k
>> 3;
592 turbo_resp
.output_win_0
= out0
;
593 turbo_resp
.output_win_1
= out1
;
594 turbo_resp
.output_win_2
= out2
;
596 #ifdef RTE_BBDEV_OFFLOAD_COST
597 start_time
= rte_rdtsc_precise();
600 if (bblib_turbo_encoder(&turbo_req
, &turbo_resp
) != 0) {
601 op
->status
|= 1 << RTE_BBDEV_DRV_ERROR
;
602 rte_bbdev_log(ERR
, "Turbo Encoder failed");
606 #ifdef RTE_BBDEV_OFFLOAD_COST
607 q_stats
->offload_time
+= rte_rdtsc_precise() - start_time
;
610 /* Restore 3 first bytes of next CB if they were overwritten by CRC*/
611 if (first_3_bytes
!= 0)
612 *((uint64_t *)&in
[(k
- 32) >> 3]) = first_3_bytes
;
615 if (enc
->op_flags
& RTE_BBDEV_TURBO_RATE_MATCH
) {
617 /* Integer round up division by 8 */
618 uint16_t out_len
= (e
+ 7) >> 3;
619 /* The mask array is indexed using E%8. E is an even number so
620 * there are only 4 possible values.
622 const uint8_t mask_out
[] = {0xFF, 0xC0, 0xF0, 0xFC};
624 /* get output data starting address */
625 rm_out
= (uint8_t *)rte_pktmbuf_append(m_out
, out_len
);
626 if (rm_out
== NULL
) {
627 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
629 "Too little space in output mbuf");
632 /* rte_bbdev_op_data.offset can be different than the offset
633 * of the appended bytes
635 rm_out
= rte_pktmbuf_mtod_offset(m_out
, uint8_t *, out_offset
);
637 /* index of current code block */
639 /* total number of code block */
641 /* For DL - 1, UL - 0 */
642 rm_req
.direction
= 1;
643 /* According to 3ggp 36.212 Spec 5.1.4.1.2 section Nsoft, KMIMO
644 * and MDL_HARQ are used for Ncb calculation. As Ncb is already
645 * known we can adjust those parameters
647 rm_req
.Nsoft
= ncb
* rm_req
.C
;
650 /* According to 3ggp 36.212 Spec 5.1.4.1.2 section Nl, Qm and G
651 * are used for E calculation. As E is already known we can
652 * adjust those parameters
656 rm_req
.G
= rm_req
.NL
* rm_req
.Qm
* rm_req
.C
;
658 rm_req
.rvidx
= enc
->rv_index
;
659 rm_req
.Kidx
= k_idx
- 1;
664 rm_resp
.output
= rm_out
;
665 rm_resp
.OutputLen
= out_len
;
666 if (enc
->op_flags
& RTE_BBDEV_TURBO_RV_INDEX_BYPASS
)
667 rm_req
.bypass_rvidx
= 1;
669 rm_req
.bypass_rvidx
= 0;
671 #ifdef RTE_BBDEV_OFFLOAD_COST
672 start_time
= rte_rdtsc_precise();
675 if (bblib_rate_match_dl(&rm_req
, &rm_resp
) != 0) {
676 op
->status
|= 1 << RTE_BBDEV_DRV_ERROR
;
677 rte_bbdev_log(ERR
, "Rate matching failed");
681 /* SW fills an entire last byte even if E%8 != 0. Clear the
682 * superfluous data bits for consistency with HW device.
684 mask_id
= (e
& 7) >> 1;
685 rm_out
[out_len
- 1] &= mask_out
[mask_id
];
687 #ifdef RTE_BBDEV_OFFLOAD_COST
688 q_stats
->offload_time
+= rte_rdtsc_precise() - start_time
;
691 enc
->output
.length
+= rm_resp
.OutputLen
;
693 /* Rate matching is bypassed */
695 /* Completing last byte of out0 (where 4 tail bits are stored)
696 * by moving first 4 bits from out1
698 tmp_out
= (uint8_t *) --out1
;
699 *tmp_out
= *tmp_out
| ((*(tmp_out
+ 1) & 0xF0) >> 4);
701 /* Shifting out1 data by 4 bits to the left */
702 for (m
= 0; m
< k
>> 3; ++m
) {
703 uint8_t *first
= tmp_out
;
704 uint8_t second
= *(tmp_out
+ 1);
705 *first
= (*first
<< 4) | ((second
& 0xF0) >> 4);
708 /* Shifting out2 data by 8 bits to the left */
709 for (m
= 0; m
< (k
>> 3) + 1; ++m
) {
710 *tmp_out
= *(tmp_out
+ 1);
718 enqueue_enc_one_op(struct turbo_sw_queue
*q
, struct rte_bbdev_enc_op
*op
,
719 struct rte_bbdev_stats
*queue_stats
)
721 uint8_t c
, r
, crc24_bits
= 0;
724 struct rte_bbdev_op_turbo_enc
*enc
= &op
->turbo_enc
;
725 uint16_t in_offset
= enc
->input
.offset
;
726 uint16_t out_offset
= enc
->output
.offset
;
727 struct rte_mbuf
*m_in
= enc
->input
.data
;
728 struct rte_mbuf
*m_out
= enc
->output
.data
;
729 uint16_t total_left
= enc
->input
.length
;
731 /* Clear op status */
734 if (total_left
> RTE_BBDEV_MAX_TB_SIZE
>> 3) {
735 rte_bbdev_log(ERR
, "TB size (%u) is too big, max: %d",
736 total_left
, RTE_BBDEV_MAX_TB_SIZE
);
737 op
->status
= 1 << RTE_BBDEV_DATA_ERROR
;
741 if (m_in
== NULL
|| m_out
== NULL
) {
742 rte_bbdev_log(ERR
, "Invalid mbuf pointer");
743 op
->status
= 1 << RTE_BBDEV_DATA_ERROR
;
747 if ((enc
->op_flags
& RTE_BBDEV_TURBO_CRC_24B_ATTACH
) ||
748 (enc
->op_flags
& RTE_BBDEV_TURBO_CRC_24A_ATTACH
))
751 if (enc
->code_block_mode
== 0) { /* For Transport Block mode */
752 c
= enc
->tb_params
.c
;
753 r
= enc
->tb_params
.r
;
754 } else {/* For Code Block mode */
759 while (total_left
> 0 && r
< c
) {
760 if (enc
->code_block_mode
== 0) {
761 k
= (r
< enc
->tb_params
.c_neg
) ?
762 enc
->tb_params
.k_neg
: enc
->tb_params
.k_pos
;
763 ncb
= (r
< enc
->tb_params
.c_neg
) ?
764 enc
->tb_params
.ncb_neg
: enc
->tb_params
.ncb_pos
;
765 e
= (r
< enc
->tb_params
.cab
) ?
766 enc
->tb_params
.ea
: enc
->tb_params
.eb
;
768 k
= enc
->cb_params
.k
;
769 ncb
= enc
->cb_params
.ncb
;
770 e
= enc
->cb_params
.e
;
773 process_enc_cb(q
, op
, r
, c
, k
, ncb
, e
, m_in
,
774 m_out
, in_offset
, out_offset
, total_left
,
776 /* Update total_left */
777 total_left
-= (k
- crc24_bits
) >> 3;
778 /* Update offsets for next CBs (if exist) */
779 in_offset
+= (k
- crc24_bits
) >> 3;
780 if (enc
->op_flags
& RTE_BBDEV_TURBO_RATE_MATCH
)
781 out_offset
+= e
>> 3;
783 out_offset
+= (k
>> 3) * 3 + 2;
787 /* check if all input data was processed */
788 if (total_left
!= 0) {
789 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
791 "Mismatch between mbuf length and included CBs sizes");
795 static inline uint16_t
796 enqueue_enc_all_ops(struct turbo_sw_queue
*q
, struct rte_bbdev_enc_op
**ops
,
797 uint16_t nb_ops
, struct rte_bbdev_stats
*queue_stats
)
800 #ifdef RTE_BBDEV_OFFLOAD_COST
801 queue_stats
->offload_time
= 0;
804 for (i
= 0; i
< nb_ops
; ++i
)
805 enqueue_enc_one_op(q
, ops
[i
], queue_stats
);
807 return rte_ring_enqueue_burst(q
->processed_pkts
, (void **)ops
, nb_ops
,
811 /* Remove the padding bytes from a cyclic buffer.
812 * The input buffer is a data stream wk as described in 3GPP TS 36.212 section
813 * 5.1.4.1.2 starting from w0 and with length Ncb bytes.
814 * The output buffer is a data stream wk with pruned padding bytes. It's length
815 * is 3*D bytes and the order of non-padding bytes is preserved.
818 remove_nulls_from_circular_buf(const uint8_t *in
, uint8_t *out
, uint16_t k
,
821 uint32_t in_idx
, out_idx
, c_idx
;
822 const uint32_t d
= k
+ 4;
823 const uint32_t kw
= (ncb
/ 3);
824 const uint32_t nd
= kw
- d
;
825 const uint32_t r_subblock
= kw
/ RTE_BBDEV_C_SUBBLOCK
;
826 /* Inter-column permutation pattern */
827 const uint32_t P
[RTE_BBDEV_C_SUBBLOCK
] = {0, 16, 8, 24, 4, 20, 12, 28,
828 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13,
829 29, 3, 19, 11, 27, 7, 23, 15, 31};
833 /* The padding bytes are at the first Nd positions in the first row. */
834 for (c_idx
= 0; in_idx
< kw
; in_idx
+= r_subblock
, ++c_idx
) {
836 rte_memcpy(&out
[out_idx
], &in
[in_idx
+ 1],
838 out_idx
+= r_subblock
- 1;
840 rte_memcpy(&out
[out_idx
], &in
[in_idx
], r_subblock
);
841 out_idx
+= r_subblock
;
845 /* First and second parity bits sub-blocks are interlaced. */
846 for (c_idx
= 0; in_idx
< ncb
- 2 * r_subblock
;
847 in_idx
+= 2 * r_subblock
, ++c_idx
) {
848 uint32_t second_block_c_idx
= P
[c_idx
];
849 uint32_t third_block_c_idx
= P
[c_idx
] + 1;
851 if (second_block_c_idx
< nd
&& third_block_c_idx
< nd
) {
852 rte_memcpy(&out
[out_idx
], &in
[in_idx
+ 2],
854 out_idx
+= 2 * r_subblock
- 2;
855 } else if (second_block_c_idx
>= nd
&&
856 third_block_c_idx
>= nd
) {
857 rte_memcpy(&out
[out_idx
], &in
[in_idx
], 2 * r_subblock
);
858 out_idx
+= 2 * r_subblock
;
859 } else if (second_block_c_idx
< nd
) {
860 out
[out_idx
++] = in
[in_idx
];
861 rte_memcpy(&out
[out_idx
], &in
[in_idx
+ 2],
863 out_idx
+= 2 * r_subblock
- 2;
865 rte_memcpy(&out
[out_idx
], &in
[in_idx
+ 1],
867 out_idx
+= 2 * r_subblock
- 1;
871 /* Last interlaced row is different - its last byte is the only padding
872 * byte. We can have from 4 up to 28 padding bytes (Nd) per sub-block.
873 * After interlacing the 1st and 2nd parity sub-blocks we can have 0, 1
874 * or 2 padding bytes each time we make a step of 2 * R_SUBBLOCK bytes
875 * (moving to another column). 2nd parity sub-block uses the same
876 * inter-column permutation pattern as the systematic and 1st parity
877 * sub-blocks but it adds '1' to the resulting index and calculates the
878 * modulus of the result and Kw. Last column is mapped to itself (id 31)
879 * so the first byte taken from the 2nd parity sub-block will be the
880 * 32nd (31+1) byte, then 64th etc. (step is C_SUBBLOCK == 32) and the
881 * last byte will be the first byte from the sub-block:
882 * (32 + 32 * (R_SUBBLOCK-1)) % Kw == Kw % Kw == 0. Nd can't be smaller
883 * than 4 so we know that bytes with ids 0, 1, 2 and 3 must be the
884 * padding bytes. The bytes from the 1st parity sub-block are the bytes
885 * from the 31st column - Nd can't be greater than 28 so we are sure
886 * that there are no padding bytes in 31st column.
888 rte_memcpy(&out
[out_idx
], &in
[in_idx
], 2 * r_subblock
- 1);
892 move_padding_bytes(const uint8_t *in
, uint8_t *out
, uint16_t k
,
896 uint16_t kpi
= ncb
/ 3;
897 uint16_t nd
= kpi
- d
;
899 rte_memcpy(&out
[nd
], in
, d
);
900 rte_memcpy(&out
[nd
+ kpi
+ 64], &in
[kpi
], d
);
901 rte_memcpy(&out
[(nd
- 1) + 2 * (kpi
+ 64)], &in
[2 * kpi
], d
);
905 process_dec_cb(struct turbo_sw_queue
*q
, struct rte_bbdev_dec_op
*op
,
906 uint8_t c
, uint16_t k
, uint16_t kw
, struct rte_mbuf
*m_in
,
907 struct rte_mbuf
*m_out
, uint16_t in_offset
, uint16_t out_offset
,
908 bool check_crc_24b
, uint16_t crc24_overlap
, uint16_t total_left
)
913 uint8_t *in
, *out
, *adapter_input
;
914 int32_t ncb
, ncb_without_null
;
915 struct bblib_turbo_adapter_ul_response adapter_resp
;
916 struct bblib_turbo_adapter_ul_request adapter_req
;
917 struct bblib_turbo_decoder_request turbo_req
;
918 struct bblib_turbo_decoder_response turbo_resp
;
919 struct rte_bbdev_op_turbo_dec
*dec
= &op
->turbo_dec
;
921 k_idx
= compute_idx(k
);
923 ret
= is_dec_input_valid(k_idx
, kw
, total_left
);
925 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
929 in
= rte_pktmbuf_mtod_offset(m_in
, uint8_t *, in_offset
);
931 ncb_without_null
= (k
+ 4) * 3;
933 if (check_bit(dec
->op_flags
, RTE_BBDEV_TURBO_SUBBLOCK_DEINTERLEAVE
)) {
934 struct bblib_deinterleave_ul_request deint_req
;
935 struct bblib_deinterleave_ul_response deint_resp
;
937 /* SW decoder accepts only a circular buffer without NULL bytes
938 * so the input needs to be converted.
940 remove_nulls_from_circular_buf(in
, q
->deint_input
, k
, ncb
);
942 deint_req
.pharqbuffer
= q
->deint_input
;
943 deint_req
.ncb
= ncb_without_null
;
944 deint_resp
.pinteleavebuffer
= q
->deint_output
;
945 bblib_deinterleave_ul(&deint_req
, &deint_resp
);
947 move_padding_bytes(in
, q
->deint_output
, k
, ncb
);
949 adapter_input
= q
->deint_output
;
951 if (dec
->op_flags
& RTE_BBDEV_TURBO_POS_LLR_1_BIT_IN
)
952 adapter_req
.isinverted
= 1;
953 else if (dec
->op_flags
& RTE_BBDEV_TURBO_NEG_LLR_1_BIT_IN
)
954 adapter_req
.isinverted
= 0;
956 op
->status
|= 1 << RTE_BBDEV_DRV_ERROR
;
957 rte_bbdev_log(ERR
, "LLR format wasn't specified");
961 adapter_req
.ncb
= ncb_without_null
;
962 adapter_req
.pinteleavebuffer
= adapter_input
;
963 adapter_resp
.pharqout
= q
->adapter_output
;
964 bblib_turbo_adapter_ul(&adapter_req
, &adapter_resp
);
966 out
= (uint8_t *)rte_pktmbuf_append(m_out
, ((k
- crc24_overlap
) >> 3));
968 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
969 rte_bbdev_log(ERR
, "Too little space in output mbuf");
972 /* rte_bbdev_op_data.offset can be different than the offset of the
975 out
= rte_pktmbuf_mtod_offset(m_out
, uint8_t *, out_offset
);
980 turbo_req
.input
= (int8_t *)q
->adapter_output
;
982 turbo_req
.k_idx
= k_idx
;
983 turbo_req
.max_iter_num
= dec
->iter_max
;
984 turbo_req
.early_term_disable
= !check_bit(dec
->op_flags
,
985 RTE_BBDEV_TURBO_EARLY_TERMINATION
);
986 turbo_resp
.ag_buf
= q
->ag
;
987 turbo_resp
.cb_buf
= q
->code_block
;
988 turbo_resp
.output
= out
;
989 iter_cnt
= bblib_turbo_decoder(&turbo_req
, &turbo_resp
);
990 dec
->hard_output
.length
+= (k
>> 3);
993 /* Temporary solution for returned iter_count from SDK */
994 iter_cnt
= (iter_cnt
- 1) / 2;
995 dec
->iter_count
= RTE_MAX(iter_cnt
, dec
->iter_count
);
997 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
998 rte_bbdev_log(ERR
, "Turbo Decoder failed");
1004 enqueue_dec_one_op(struct turbo_sw_queue
*q
, struct rte_bbdev_dec_op
*op
)
1008 uint16_t crc24_overlap
= 0;
1009 struct rte_bbdev_op_turbo_dec
*dec
= &op
->turbo_dec
;
1010 struct rte_mbuf
*m_in
= dec
->input
.data
;
1011 struct rte_mbuf
*m_out
= dec
->hard_output
.data
;
1012 uint16_t in_offset
= dec
->input
.offset
;
1013 uint16_t total_left
= dec
->input
.length
;
1014 uint16_t out_offset
= dec
->hard_output
.offset
;
1016 /* Clear op status */
1019 if (m_in
== NULL
|| m_out
== NULL
) {
1020 rte_bbdev_log(ERR
, "Invalid mbuf pointer");
1021 op
->status
= 1 << RTE_BBDEV_DATA_ERROR
;
1025 if (dec
->code_block_mode
== 0) { /* For Transport Block mode */
1026 c
= dec
->tb_params
.c
;
1027 } else { /* For Code Block mode */
1028 k
= dec
->cb_params
.k
;
1032 if ((c
> 1) && !check_bit(dec
->op_flags
,
1033 RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP
))
1036 while (total_left
> 0) {
1037 if (dec
->code_block_mode
== 0)
1038 k
= (r
< dec
->tb_params
.c_neg
) ?
1039 dec
->tb_params
.k_neg
: dec
->tb_params
.k_pos
;
1041 /* Calculates circular buffer size (Kw).
1042 * According to 3gpp 36.212 section 5.1.4.2
1046 * where nCol is 32 and nRow can be calculated from:
1048 * where D is the size of each output from turbo encoder block
1051 kw
= RTE_ALIGN_CEIL(k
+ 4, RTE_BBDEV_C_SUBBLOCK
) * 3;
1053 process_dec_cb(q
, op
, c
, k
, kw
, m_in
, m_out
, in_offset
,
1054 out_offset
, check_bit(dec
->op_flags
,
1055 RTE_BBDEV_TURBO_CRC_TYPE_24B
), crc24_overlap
,
1057 /* To keep CRC24 attached to end of Code block, use
1058 * RTE_BBDEV_TURBO_DEC_TB_CRC_24B_KEEP flag as it
1059 * removed by default once verified.
1062 /* Update total_left */
1064 /* Update offsets for next CBs (if exist) */
1066 out_offset
+= ((k
- crc24_overlap
) >> 3);
1069 if (total_left
!= 0) {
1070 op
->status
|= 1 << RTE_BBDEV_DATA_ERROR
;
1072 "Mismatch between mbuf length and included Circular buffer sizes");
1076 static inline uint16_t
1077 enqueue_dec_all_ops(struct turbo_sw_queue
*q
, struct rte_bbdev_dec_op
**ops
,
1082 for (i
= 0; i
< nb_ops
; ++i
)
1083 enqueue_dec_one_op(q
, ops
[i
]);
1085 return rte_ring_enqueue_burst(q
->processed_pkts
, (void **)ops
, nb_ops
,
1091 enqueue_enc_ops(struct rte_bbdev_queue_data
*q_data
,
1092 struct rte_bbdev_enc_op
**ops
, uint16_t nb_ops
)
1094 void *queue
= q_data
->queue_private
;
1095 struct turbo_sw_queue
*q
= queue
;
1096 uint16_t nb_enqueued
= 0;
1098 nb_enqueued
= enqueue_enc_all_ops(q
, ops
, nb_ops
, &q_data
->queue_stats
);
1100 q_data
->queue_stats
.enqueue_err_count
+= nb_ops
- nb_enqueued
;
1101 q_data
->queue_stats
.enqueued_count
+= nb_enqueued
;
1108 enqueue_dec_ops(struct rte_bbdev_queue_data
*q_data
,
1109 struct rte_bbdev_dec_op
**ops
, uint16_t nb_ops
)
1111 void *queue
= q_data
->queue_private
;
1112 struct turbo_sw_queue
*q
= queue
;
1113 uint16_t nb_enqueued
= 0;
1115 nb_enqueued
= enqueue_dec_all_ops(q
, ops
, nb_ops
);
1117 q_data
->queue_stats
.enqueue_err_count
+= nb_ops
- nb_enqueued
;
1118 q_data
->queue_stats
.enqueued_count
+= nb_enqueued
;
1123 /* Dequeue decode burst */
1125 dequeue_dec_ops(struct rte_bbdev_queue_data
*q_data
,
1126 struct rte_bbdev_dec_op
**ops
, uint16_t nb_ops
)
1128 struct turbo_sw_queue
*q
= q_data
->queue_private
;
1129 uint16_t nb_dequeued
= rte_ring_dequeue_burst(q
->processed_pkts
,
1130 (void **)ops
, nb_ops
, NULL
);
1131 q_data
->queue_stats
.dequeued_count
+= nb_dequeued
;
1136 /* Dequeue encode burst */
1138 dequeue_enc_ops(struct rte_bbdev_queue_data
*q_data
,
1139 struct rte_bbdev_enc_op
**ops
, uint16_t nb_ops
)
1141 struct turbo_sw_queue
*q
= q_data
->queue_private
;
1142 uint16_t nb_dequeued
= rte_ring_dequeue_burst(q
->processed_pkts
,
1143 (void **)ops
, nb_ops
, NULL
);
1144 q_data
->queue_stats
.dequeued_count
+= nb_dequeued
;
1149 /* Parse 16bit integer from string argument */
1151 parse_u16_arg(const char *key
, const char *value
, void *extra_args
)
1153 uint16_t *u16
= extra_args
;
1154 unsigned int long result
;
1156 if ((value
== NULL
) || (extra_args
== NULL
))
1159 result
= strtoul(value
, NULL
, 0);
1160 if ((result
>= (1 << 16)) || (errno
!= 0)) {
1161 rte_bbdev_log(ERR
, "Invalid value %lu for %s", result
, key
);
1164 *u16
= (uint16_t)result
;
1168 /* Parse parameters used to create device */
1170 parse_turbo_sw_params(struct turbo_sw_params
*params
, const char *input_args
)
1172 struct rte_kvargs
*kvlist
= NULL
;
1178 kvlist
= rte_kvargs_parse(input_args
, turbo_sw_valid_params
);
1182 ret
= rte_kvargs_process(kvlist
, turbo_sw_valid_params
[0],
1183 &parse_u16_arg
, ¶ms
->queues_num
);
1187 ret
= rte_kvargs_process(kvlist
, turbo_sw_valid_params
[1],
1188 &parse_u16_arg
, ¶ms
->socket_id
);
1192 if (params
->socket_id
>= RTE_MAX_NUMA_NODES
) {
1193 rte_bbdev_log(ERR
, "Invalid socket, must be < %u",
1194 RTE_MAX_NUMA_NODES
);
1201 rte_kvargs_free(kvlist
);
1207 turbo_sw_bbdev_create(struct rte_vdev_device
*vdev
,
1208 struct turbo_sw_params
*init_params
)
1210 struct rte_bbdev
*bbdev
;
1211 const char *name
= rte_vdev_device_name(vdev
);
1213 bbdev
= rte_bbdev_allocate(name
);
1217 bbdev
->data
->dev_private
= rte_zmalloc_socket(name
,
1218 sizeof(struct bbdev_private
), RTE_CACHE_LINE_SIZE
,
1219 init_params
->socket_id
);
1220 if (bbdev
->data
->dev_private
== NULL
) {
1221 rte_bbdev_release(bbdev
);
1225 bbdev
->dev_ops
= &pmd_ops
;
1226 bbdev
->device
= &vdev
->device
;
1227 bbdev
->data
->socket_id
= init_params
->socket_id
;
1228 bbdev
->intr_handle
= NULL
;
1230 /* register rx/tx burst functions for data path */
1231 bbdev
->dequeue_enc_ops
= dequeue_enc_ops
;
1232 bbdev
->dequeue_dec_ops
= dequeue_dec_ops
;
1233 bbdev
->enqueue_enc_ops
= enqueue_enc_ops
;
1234 bbdev
->enqueue_dec_ops
= enqueue_dec_ops
;
1235 ((struct bbdev_private
*) bbdev
->data
->dev_private
)->max_nb_queues
=
1236 init_params
->queues_num
;
1241 /* Initialise device */
1243 turbo_sw_bbdev_probe(struct rte_vdev_device
*vdev
)
1245 struct turbo_sw_params init_params
= {
1247 RTE_BBDEV_DEFAULT_MAX_NB_QUEUES
1250 const char *input_args
;
1255 name
= rte_vdev_device_name(vdev
);
1258 input_args
= rte_vdev_device_args(vdev
);
1259 parse_turbo_sw_params(&init_params
, input_args
);
1261 rte_bbdev_log_debug(
1262 "Initialising %s on NUMA node %d with max queues: %d\n",
1263 name
, init_params
.socket_id
, init_params
.queues_num
);
1265 return turbo_sw_bbdev_create(vdev
, &init_params
);
1268 /* Uninitialise device */
1270 turbo_sw_bbdev_remove(struct rte_vdev_device
*vdev
)
1272 struct rte_bbdev
*bbdev
;
1278 name
= rte_vdev_device_name(vdev
);
1282 bbdev
= rte_bbdev_get_named_dev(name
);
1286 rte_free(bbdev
->data
->dev_private
);
1288 return rte_bbdev_release(bbdev
);
1291 static struct rte_vdev_driver bbdev_turbo_sw_pmd_drv
= {
1292 .probe
= turbo_sw_bbdev_probe
,
1293 .remove
= turbo_sw_bbdev_remove
1296 RTE_PMD_REGISTER_VDEV(DRIVER_NAME
, bbdev_turbo_sw_pmd_drv
);
1297 RTE_PMD_REGISTER_PARAM_STRING(DRIVER_NAME
,
1298 TURBO_SW_MAX_NB_QUEUES_ARG
"=<int> "
1299 TURBO_SW_SOCKET_ID_ARG
"=<int>");
1300 RTE_PMD_REGISTER_ALIAS(DRIVER_NAME
, turbo_sw
);
1302 RTE_INIT(turbo_sw_bbdev_init_log
)
1304 bbdev_turbo_sw_logtype
= rte_log_register("pmd.bb.turbo_sw");
1305 if (bbdev_turbo_sw_logtype
>= 0)
1306 rte_log_set_level(bbdev_turbo_sw_logtype
, RTE_LOG_NOTICE
);