Merge remote-tracking branch 'origin/ldpc-aal' into integration_2025_w32 (!3344)

LDPC BBDEV/AAL rework

This branch aims to generalize the existing LDPC T2 implementation to support
other DPDK BBDEV accelerators, e.g., Intel ACC100/200.

Differences from the current T2 implementation include:
  1. relax CMakeLists.txt checking for custom dpdk-t2 implementation,
     technically, any DPDK BBDEV should work
  2. BBDEV capability checks during init
  3. llr_scaling to scale the input llr accordingly for better decoding
     performance on the Intel ACC100/200
  4. self-managed harq buffers for the ACC200, as internal harq memory is not
     available

Tested BBDEV devices:
  1. Intel ACC100
  2. Intel ACC200/VRB1
This commit is contained in:
Jaroslava Fiedlerova
2025-08-07 12:17:11 +02:00
16 changed files with 1097 additions and 415 deletions
+13 -13
View File
@@ -28,35 +28,35 @@ shlib_path libldpc.so
`libldpc.so` has its decoder implemented in [nrLDPC_coding_segment_decoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c).\
Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c).
loading `libldpc_t2.so` instead of `libldpc.so`:
loading `libldpc_aal.so` instead of `libldpc.so`:
`make ldpc_t2`
`make ldpc_aal`
This command creates the `libldpc_t2.so` shared library.
This command creates the `libldpc_aal.so` shared library.
```
Building C object CMakeFiles/ldpc_t2.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c.o
Linking C shared module libldpc_t2.so
Building C object CMakeFiles/ldpc_aal.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c.o
Linking C shared module libldpc_aal.so
```
At runtime, to successfully use the T2 board, you need to install vendor specific drivers and tools.\
Please refer to the dedicated documentation at [LDPC_T2_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_T2_OFFLOAD_SETUP.md).
At runtime, to successfully use LDPC accelerators (e.g., Xilinx T2/Intel ACCs), you will need to install the corresponding drivers and tools.
Please refer to the dedicated documentation at [LDPC_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_OFFLOAD_SETUP.md).
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1`
`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 01:00.0 --nrLDPC_coding_aal.dpdk_core_list 0-1`
```
.......................
[CONFIG] loader.ldpc.shlibversion set to default value ""
[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value)
[CONFIG] shlibversion set to _t2 from command line
[CONFIG] shlibversion set to _aal from command line
[CONFIG] loader.ldpc 1 options set from command line
shlib_path libldpc_t2.so
[LOADER] library libldpc_t2.so successfully loaded
shlib_path libldpc_aal.so
[LOADER] library libldpc_aal.so successfully loaded
........................
```
`libldpc_t2.so` has its decoder and its encoder implemented in [nrLDPC_coding_t2.c](file://../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c).
`libldpc_aal.so` has its decoder and its encoder implemented in [nrLDPC_coding_aal.c](file://../nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c).
loading `libldpc_xdma.so` instead of `libldpc.so`:
@@ -103,7 +103,7 @@ Libraries implementing the slotwise LDPC coding must be named `libldpc<_version>
`libldpc.so` is completed.
`libldpc_t2.so` is completed.
`libldpc_aal.so` is completed.
`libldpc_xdma.so` is completed.
@@ -1,3 +1,3 @@
add_subdirectory(nrLDPC_coding_segment)
add_subdirectory(nrLDPC_coding_xdma)
add_subdirectory(nrLDPC_coding_t2)
add_subdirectory(nrLDPC_coding_aal)
@@ -0,0 +1,36 @@
##########################################################
# LDPC offload library - O-RAN AAL/DPDK BBDEV
##########################################################
add_boolean_option(ENABLE_LDPC_AAL OFF "Build support for LDPC Offload using O-RAN AAL library" OFF)
if (ENABLE_LDPC_AAL)
pkg_check_modules(LIBDPDK_AAL REQUIRED libdpdk>=20.11.9)
find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_AAL_LIBRARY_DIRS})
if (PMD_T2)
message(STATUS "found poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)")
else()
if (LIBDPDK_AAL_VERSION VERSION_LESS "22.11")
message(FATAL_ERROR "for non-T2 BBDEV PMDs, we support the Intel ACC100 and ACC200 (VRB1), using DPDK 22.11 or later.")
endif()
endif()
add_library(ldpc_aal MODULE nrLDPC_coding_aal.c)
set_target_properties(ldpc_aal PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API")
set_target_properties(ldpc_aal PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_include_directories(ldpc_aal PRIVATE ${LIBDPDK_AAL_INCLUDE_DIRS})
target_link_libraries(ldpc_aal PRIVATE ldpc_gen_HEADERS ${LIBDPDK_AAL_LDFLAGS})
if (PMD_T2)
target_link_libraries(ldpc_aal PRIVATE ${PMD_T2})
endif()
add_dependencies(nr-softmodem ldpc_aal)
add_dependencies(nr-uesoftmodem ldpc_aal)
add_dependencies(nr_ulsim ldpc_aal)
add_dependencies(nr_ulschsim ldpc_aal)
add_dependencies(nr_dlsim ldpc_aal)
add_dependencies(nr_dlschsim ldpc_aal)
endif()
@@ -0,0 +1,143 @@
This document highlights some of the key aspects of the implementation for O-RAN AAL/DPDK BBDEV; for user documentation, please consult the [setup guide](../../../../../doc/LDPC_OFFLOAD_SETUP.md) instead.
## Overview
The current implementation supports the following BBDEV devices and respective DPDK versions:
- Xilinx T2 on DPDK20.11+
- Intel ACC100* on DPDK22.11+
- Intel ACC200 (VRB1) on DPDK22.11+
> Important notes:
> - For the Intel ACC100, for DPDK22.11 and DPDK23.11, users are required to [patch](https://github.com/DPDK/dpdk/commit/fdde63a1dfc129d0a510a831aa98253b36a2a1cd) the ACC100's driver.
> - If you intend to use this implementation in an FHI7.2 setup, only the F-release and beyond is supported.
## Implementation Details
Below, we highlight some of the important details in this implementation.
### HARQ
To maintain the HARQ buffers in the LDPC decoding process, the BBDEV either uses its internal memory (not visible to DPDK), or using external memory (i.e., DDR) managed by OAI.
For the Xilinx T2 and Intel ACC100, they use the internal memory while the Intel ACC200 uses the DDR memory.
If internal memory is supported by the device, we will set `RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE` and `RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE`.
The following two fields are important for HARQ: `harq_combined_input` and `harq_combined_output`.
For the first transmission, there is no HARQ input.
Thus, the flag `RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE` is not set.
However, there will be a HARQ output, so we set the flag `RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE`.
We also set the corresponding fields for `harq_combined_output`.
For the second transmission (or subsequent retransmissions), we need to provide a HARQ input at the same time, there will also be a HARQ output.
Therefore, both fields, `harq_combined_input` and `harq_combined_output` must be set accordingly.
As HARQ requires the output of the previous transmission/ HARQ round as its input, we need to maintain a separate variable to hold the previous round's information.
To do so, we define `harq_buffers` (which is a pointer to an array of size `num_harq_codeblock` allocated in the heap later) in the `active_device` struct (see the following) in our implementation.
```C
struct active_device {
...
uint32_t num_harq_codeblock;
/* Persistent data structure to keep track of HARQ-related information */
// Note: This is used to store/keep track of the combined output information across iterations
struct rte_bbdev_op_data *harq_buffers;
...
} active_dev;
```
In the following, we elaborate on how the HARQ-related fields are set.
#### Internal Memory
When using the internal memory, we need to specify the *offset* of the hardware's memory where we want to store the HARQ combined output, and read from it accordingly later.
In the current implementation, we use a fixed offset of 32K, i.e., this means that each block is 32K.
An index is derived from a unique HARQ PID assigned by OAI, modulo `active_dev.num_harq_codeblock` (which is configurable by the user through `nrLDPC_coding_t2.num_harq_codeblock`).
Using that index, we then derived the corresponding offset in the memory (i.e., `harq_combined_offset`).
```C
...
// Calculate offset in the HARQ combined buffers
// Unique segment offset
uint32_t segment_offset = (nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) + i;
// Prune to avoid shooting above maximum id
uint32_t pruned_segment_offset = segment_offset % active_dev.num_harq_codeblock;
// Segment offset to byte offset
uint32_t harq_combined_offset = pruned_segment_offset * LDPC_MAX_CB_SIZE;
...
```
This `harq_combined_offset` is then set for `harq_combined_input.offset` and `harq_combined_output.offset` to tell BBDEV where to read/write the HARQ buffers.
Especially for the Intel ACCs, when providing the HARQ input, the `harq_combined_input.length` must be provided.
To do so, we maintain the length of previous round's output using `harq_buffers` by copying it in `retrieve_ldpc_dec_op`.
#### External Memory
Different from the Xilinx T2 and Intel ACC100, the Intel ACC200 uses DDR memory to maintain the HARQ buffers which is managed by OAI.
In short, we use `harq_buffers` from the `active_device` struct, which have been initialzed with corresponding DPDK mempools for BBDEV to read/write the HARQ input/outputs.
For indexing, we use the `pruned_segment_offset`, which is derived from the unique HARQ PID assigned by OAI, modulo `active_dev.num_harq_codeblock` (which is configurable by the user through `nrLDPC_coding_t2.num_harq_codeblock`).
`harq_combined_input.offset` and `harq_combined_output.offset` is always set to 0 in our implementation.
Instead, we provide BBDEV the pointers to our allocated mempool regions through `harq_combined_input.data` and `harq_combined_output.data`.
In `retrieve_ldpc_dec_op`, we perform a `rte_memcpy` to copy the HARQ combined outputs to `harq_buffers`, along with other necessary metadata information to prepare for subsequent HARQ rounds.
Similar to the Intel ACC100, when providing the HARQ input, the `harq_combined_input.length` must be provided.
### LLR Scaling
The LLR output from OAI's demodulation block is in 16 bits.
However, accelerators typically assume that the LLR inputs are scaled down using fixed-point arithmetic, e.g., 8 bits.
For the Xilinx T2, saturation is performed.
However, our tests have shown that this implementation did not work well for the Intel ACCs.
To that end, we perform LLR scaling differently for the Intel ACCs.
Through the function `llr_scaling`, we look at the min and max LLR values, perform scaling and subsequently saturation accordingly.
The fixed-point representations supported by the hardware is defined by the `llr_size` and `llr_decimal`.
For example, if `llr_size=8`, and `llr_decimal=1`, it means that we use a S8.1 representation (1 fractional bit), the min and max values are -64 to 63.5.
> *Limitation:*
> We observe that in certain configurations, such as when using 2 MIMO layers, the LLR (Log-Likelihood Ratio) outputs exhibit a much wider dynamic range (e.g., from -10,000 to 10,000) compared to the typical sub-1,000 range seen in most other cases.
> This suggests potential inconsistencies in the LLR values generated by the demodulator.
> We believe that the decoding performance, when compared to the CPU implementation under the same number of LDPC decoding iterations, could be improved by refining the LLR scaling approach or revisiting the LLR generation process during demodulation.
> This remains an area of active investigation.
>
> *Workaround:*
> As a temporary measure, increasing the number of LDPC decoding iterations—e.g., to 150—has shown to yield a decoding success rate comparable to that of the CPU implementation.
> This comes at a negligible increase in decoding time based on our current evaluation.
### Special Case(s)
#### TB mode
For the T2, only CB mode is supported.
For the Intel ACCs, while we also use CB mode mostly, there is a special case that must be handled properly as specified by the BBDEV documentations:
```
... The case when one CB belongs to TB and is being enqueued individually to BBDEV, this case is considered as a special case of partial TB where its number of CBs is 1. Therefore, it requires to get processed in TB-mode. ...
```
In such a case, we perform a check on whether there is only one TB, AND if the TB has only one CB.
If so, this has to be handled separately by using TB mode.
### Future Work(s)
#### TB mode
The current channel coding interface assumes LDPC encoding and decoding are performed on a per-code block basis.
However, to fully leverage Transport Block (TB) mode as supported in BBDEV, which can improve efficiency, the L1 implementation surrounding channel coding needs to be refactored.
This remains an area for future investigation.
#### CRC24A/CRC16
CRC24A/CRC16 is supported by the BBDEV device (i.e., Intel ACC200).
However, we do not make use of them and rely on OAI's existing CRC functions.
To use of BBDEV's CRC24A/CRC16 capability will be looked into in future MRs.
@@ -2,8 +2,8 @@
* Copyright(c) 2017 Intel Corporation
*/
#ifndef _MAIN_H_
#define _MAIN_H_
#ifndef __NRLDPC_CODING_T2_H__
#define __NRLDPC_CODING_T2_H__
#include <stddef.h>
#include <sys/queue.h>
@@ -17,6 +17,7 @@
enum op_data_type {
DATA_INPUT = 0,
DATA_HARD_OUTPUT,
DATA_HARQ_OUTPUT,
DATA_NUM_TYPES,
};
@@ -1,31 +0,0 @@
##########################################################
# LDPC offload library - AMD T2 Accelerator Card
##########################################################
add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF)
if (ENABLE_LDPC_T2)
pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk>=20.11.9)
find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS})
if (NOT PMD_T2)
message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)")
endif()
message(STATUS "T2 build: use ${PMD_T2}")
add_library(ldpc_t2 MODULE nrLDPC_coding_t2.c)
set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API")
set_target_properties(ldpc_t2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2})
add_dependencies(nr-softmodem ldpc_t2)
add_dependencies(nr-uesoftmodem ldpc_t2)
add_dependencies(nr_ulsim ldpc_t2)
add_dependencies(nr_ulschsim ldpc_t2)
add_dependencies(nr_dlsim ldpc_t2)
add_dependencies(nr_dlschsim ldpc_t2)
endif()