[v2,14/37] baseband/acc100: update validate LDPC enc/dec

Message ID 20220820023157.189047-15-hernan.vargas@intel.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series baseband/acc100: changes for 22.11 |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Hernan Vargas Aug. 20, 2022, 2:31 a.m. UTC
  Update validate functions to check for valid LDPC parameters to avoid
any HW issues.
Adding protection for null corner case and for HARQ inbound size out
of range.
HARQ input size from application may be invalid and causing HW issue.
Add checks to ensure that if HARQ is invalid, set to some valid size to
ensure HW issues do not occur.

Signed-off-by: Hernan Vargas <hernan.vargas@intel.com>
---
 drivers/baseband/acc100/rte_acc100_pmd.c | 297 +++++++++++++++++++++--
 1 file changed, 283 insertions(+), 14 deletions(-)
  

Comments

Maxime Coquelin Sept. 15, 2022, 7:43 a.m. UTC | #1
On 8/20/22 04:31, Hernan Vargas wrote:
> Update validate functions to check for valid LDPC parameters to avoid
> any HW issues.
> Adding protection for null corner case and for HARQ inbound size out
> of range.
> HARQ input size from application may be invalid and causing HW issue.
> Add checks to ensure that if HARQ is invalid, set to some valid size to
> ensure HW issues do not occur.
> 
> Signed-off-by: Hernan Vargas <hernan.vargas@intel.com>
> ---
>   drivers/baseband/acc100/rte_acc100_pmd.c | 297 +++++++++++++++++++++--
>   1 file changed, 283 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/baseband/acc100/rte_acc100_pmd.c b/drivers/baseband/acc100/rte_acc100_pmd.c
> index e47f7d68c2..1504acfadd 100644
> --- a/drivers/baseband/acc100/rte_acc100_pmd.c
> +++ b/drivers/baseband/acc100/rte_acc100_pmd.c
> @@ -2404,10 +2404,6 @@ validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
>   	if (!validate_op_required(q))
>   		return 0;
>   
> -	if (op->mempool == NULL) {
> -		rte_bbdev_log(ERR, "Invalid mempool pointer");
> -		return -1;
> -	}
>   	if (ldpc_enc->input.data == NULL) {
>   		rte_bbdev_log(ERR, "Invalid input pointer");
>   		return -1;
> @@ -2416,11 +2412,9 @@ validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
>   		rte_bbdev_log(ERR, "Invalid output pointer");
>   		return -1;
>   	}
> -	if (ldpc_enc->input.length >
> -			RTE_BBDEV_LDPC_MAX_CB_SIZE >> 3) {
> -		rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
> -				ldpc_enc->input.length,
> -				RTE_BBDEV_LDPC_MAX_CB_SIZE);
> +	if (ldpc_enc->input.length == 0) {
> +		rte_bbdev_log(ERR, "CB size (%u) is null",
> +				ldpc_enc->input.length);
>   		return -1;
>   	}
>   	if ((ldpc_enc->basegraph > 2) || (ldpc_enc->basegraph == 0)) {
> @@ -2441,13 +2435,107 @@ validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
>   				ldpc_enc->code_block_mode);
>   		return -1;
>   	}
> +	if (ldpc_enc->z_c > 384) {

Please use defines instead of raw values here and elsewhere in the
patch.

> +		rte_bbdev_log(ERR,
> +				"Zc (%u) is out of range",
> +				ldpc_enc->z_c);
> +		return -1;
> +	}
>   	int K = (ldpc_enc->basegraph == 1 ? 22 : 10) * ldpc_enc->z_c;
> -	if (ldpc_enc->n_filler >= K) {
> +	int N = (ldpc_enc->basegraph == 1 ? ACC100_N_ZC_1 : ACC100_N_ZC_2)
> +			* ldpc_enc->z_c;
> +	int q_m = ldpc_enc->q_m;
> +	int crc24 = 0;
> +
> +	if (check_bit(op->ldpc_enc.op_flags,
> +			RTE_BBDEV_LDPC_CRC_24A_ATTACH) ||
> +			check_bit(op->ldpc_enc.op_flags,
> +			RTE_BBDEV_LDPC_CRC_24B_ATTACH))
> +		crc24 = 24;
> +	if ((K - ldpc_enc->n_filler) % 8 > 0) {
>   		rte_bbdev_log(ERR,
> -				"K and F are not compatible %u %u",
> +				"K - F not byte aligned %u",
> +				K - ldpc_enc->n_filler);
> +		return -1;
> +	}
> +	if (ldpc_enc->n_filler > (K - 2 * ldpc_enc->z_c)) {
> +		rte_bbdev_log(ERR,
> +				"K - F invalid %u %u",
>   				K, ldpc_enc->n_filler);
>   		return -1;
>   	}
> +	if ((ldpc_enc->n_cb > N) || (ldpc_enc->n_cb <= K)) {
> +		rte_bbdev_log(ERR,
> +				"Ncb (%u) is out of range K  %d N %d",
> +				ldpc_enc->n_cb, K, N);
> +		return -1;
> +	}
> +	if (!check_bit(op->ldpc_enc.op_flags,
> +			RTE_BBDEV_LDPC_INTERLEAVER_BYPASS) &&
> +			((q_m == 0) || ((q_m > 2) && ((q_m % 2) == 1))
> +			|| (q_m > 8))) {
> +		rte_bbdev_log(ERR,
> +				"Qm (%u) is out of range",
> +				ldpc_enc->q_m);
> +		return -1;
> +	}
> +	if (ldpc_enc->code_block_mode == RTE_BBDEV_CODE_BLOCK) {
> +		if (ldpc_enc->cb_params.e == 0) {
> +			rte_bbdev_log(ERR,
> +					"E is null");
> +			return -1;
> +		}
> +		if (q_m > 0) {
> +			if (ldpc_enc->cb_params.e % q_m > 0) {
> +				rte_bbdev_log(ERR,
> +						"E not multiple of qm %d", q_m);
> +				return -1;
> +			}
> +		}
> +		if ((ldpc_enc->z_c <= 11) && (ldpc_enc->cb_params.e > 3456)) {
> +			rte_bbdev_log(ERR,
> +					"E too large for small block");
> +			return -1;
> +		}
> +		if (ldpc_enc->input.length >
> +			RTE_BBDEV_LDPC_MAX_CB_SIZE >> 3) {
> +			rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
> +					ldpc_enc->input.length,
> +					RTE_BBDEV_LDPC_MAX_CB_SIZE);
> +		return -1;
> +		}
> +		if (K < (int) (ldpc_enc->input.length * 8
> +				+ ldpc_enc->n_filler) + crc24) {
> +			rte_bbdev_log(ERR,
> +					"K and F not matching input size %u %u %u",
> +					K, ldpc_enc->n_filler,
> +					ldpc_enc->input.length);
> +			return -1;
> +		}
> +	} else {
> +		if ((ldpc_enc->tb_params.c == 0) ||
> +				(ldpc_enc->tb_params.ea == 0) ||
> +				(ldpc_enc->tb_params.eb == 0)) {
> +			rte_bbdev_log(ERR,
> +					"TB parameter is null");
> +			return -1;
> +		}
> +		if (q_m > 0) {
> +			if ((ldpc_enc->tb_params.ea % q_m > 0) ||
> +					(ldpc_enc->tb_params.eb % q_m > 0)) {
> +				rte_bbdev_log(ERR,
> +						"E not multiple of qm %d",
> +						q_m);
> +				return -1;
> +			}
> +		}
> +		if ((ldpc_enc->z_c <= 11) && (RTE_MAX(ldpc_enc->tb_params.ea,
> +				ldpc_enc->tb_params.eb) > 3456)) {
> +			rte_bbdev_log(ERR,
> +					"E too large for small block");
> +			return -1;
> +		}
> +	}
>   	return 0;
>   }
>   
> @@ -2460,8 +2548,16 @@ validate_ldpc_dec_op(struct rte_bbdev_dec_op *op, struct acc100_queue *q)
>   	if (!validate_op_required(q))
>   		return 0;
>   
> -	if (op->mempool == NULL) {
> -		rte_bbdev_log(ERR, "Invalid mempool pointer");
> +	if (ldpc_dec->input.data == NULL) {
> +		rte_bbdev_log(ERR, "Invalid input pointer");
> +		return -1;
> +	}
> +	if (ldpc_dec->hard_output.data == NULL) {
> +		rte_bbdev_log(ERR, "Invalid output pointer");
> +		return -1;
> +	}
> +	if (ldpc_dec->input.length == 0) {
> +		rte_bbdev_log(ERR, "input is null");
>   		return -1;
>   	}
>   	if ((ldpc_dec->basegraph > 2) || (ldpc_dec->basegraph == 0)) {
> @@ -2488,13 +2584,186 @@ validate_ldpc_dec_op(struct rte_bbdev_dec_op *op, struct acc100_queue *q)
>   				ldpc_dec->code_block_mode);
>   		return -1;
>   	}
> +	/* Check Zc is valid value */
> +	if ((ldpc_dec->z_c > 384) || (ldpc_dec->z_c < 2)) {
> +		rte_bbdev_log(ERR,
> +				"Zc (%u) is out of range",
> +				ldpc_dec->z_c);
> +		return -1;
> +	}
> +	if (ldpc_dec->z_c > 256) {
> +		if ((ldpc_dec->z_c % 32) != 0) {
> +			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
> +			return -1;
> +		}
> +	} else if (ldpc_dec->z_c > 128) {
> +		if ((ldpc_dec->z_c % 16) != 0) {
> +			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
> +			return -1;
> +		}
> +	} else if (ldpc_dec->z_c > 64) {
> +		if ((ldpc_dec->z_c % 8) != 0) {
> +			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
> +			return -1;
> +		}
> +	} else if (ldpc_dec->z_c > 32) {
> +		if ((ldpc_dec->z_c % 4) != 0) {
> +			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
> +			return -1;
> +		}
> +	} else if (ldpc_dec->z_c > 16) {
> +		if ((ldpc_dec->z_c % 2) != 0) {
> +			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
> +			return -1;
> +		}
> +	}
>   	int K = (ldpc_dec->basegraph == 1 ? 22 : 10) * ldpc_dec->z_c;
> -	if (ldpc_dec->n_filler >= K) {
> +	int N = (ldpc_dec->basegraph == 1 ? ACC100_N_ZC_1 : ACC100_N_ZC_2)
> +			* ldpc_dec->z_c;
> +	int q_m = ldpc_dec->q_m;
> +	if (ldpc_dec->n_filler >= K - 2 * ldpc_dec->z_c) {
>   		rte_bbdev_log(ERR,
>   				"K and F are not compatible %u %u",
>   				K, ldpc_dec->n_filler);
>   		return -1;
>   	}
> +	if ((ldpc_dec->n_cb > N) || (ldpc_dec->n_cb <= K)) {
> +		rte_bbdev_log(ERR,
> +				"Ncb (%u) is out of range K  %d N %d",
> +				ldpc_dec->n_cb, K, N);
> +		return -1;
> +	}
> +
> +	if (((q_m == 0) || ((q_m > 2) && ((q_m % 2) == 1))
> +			|| (q_m > 8))) {
> +		rte_bbdev_log(ERR,
> +				"Qm (%u) is out of range",
> +				ldpc_dec->q_m);
> +		return -1;
> +	}
> +	if (ldpc_dec->code_block_mode == RTE_BBDEV_CODE_BLOCK) {
> +		if (ldpc_dec->cb_params.e == 0) {
> +			rte_bbdev_log(ERR,
> +					"E is null");
> +			return -1;
> +		}
> +		if (ldpc_dec->cb_params.e % q_m > 0) {
> +			rte_bbdev_log(ERR,
> +					"E not multiple of qm %d", q_m);
> +			return -1;
> +		}
> +		if (ldpc_dec->cb_params.e > 512 * ldpc_dec->z_c) {
> +			rte_bbdev_log(ERR,
> +					"E too high");
> +			return -1;
> +		}
> +	} else {
> +		if ((ldpc_dec->tb_params.c == 0) ||
> +				(ldpc_dec->tb_params.ea == 0) ||
> +				(ldpc_dec->tb_params.eb == 0)) {
> +			rte_bbdev_log(ERR,
> +					"TB parameter is null");
> +			return -1;
> +		}
> +		if ((ldpc_dec->tb_params.ea % q_m > 0) ||
> +				(ldpc_dec->tb_params.eb % q_m > 0)) {
> +			rte_bbdev_log(ERR,
> +					"E not multiple of qm %d", q_m);
> +			return -1;
> +		}
> +		if ((ldpc_dec->tb_params.ea > 512 * ldpc_dec->z_c) ||
> +				(ldpc_dec->tb_params.eb > 512 * ldpc_dec->z_c)) {
> +			rte_bbdev_log(ERR,
> +					"E too high");
> +			return -1;
> +		}
> +	}
> +	if (check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_DECODE_BYPASS)) {
> +		rte_bbdev_log(ERR, "Avoid LDPC Decode bypass");
> +		return -1;
> +	}
> +
> +	/* Avoid HARQ compression for small block size */
> +	if ((check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION))
> +			&& (K < 2048)) {
> +		op->ldpc_dec.op_flags ^= RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION;
> +	}
> +	uint32_t min_harq_input = check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION) ? 256 : 64;
> +	if (check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE) &&
> +			ldpc_dec->harq_combined_input.length <
> +			min_harq_input) {
> +		rte_bbdev_log(ERR, "HARQ input size is too small %d < %d",
> +			ldpc_dec->harq_combined_input.length,
> +			min_harq_input);
> +		return -1;
> +	}
> +
> +	/* Enforce in-range HARQ input size */
> +	if (check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
> +		uint32_t max_harq_input = RTE_ALIGN_CEIL(ldpc_dec->n_cb -
> +				ldpc_dec->n_filler, 64);
> +		if (check_bit(op->ldpc_dec.op_flags,
> +				RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION))
> +			max_harq_input = max_harq_input * 3 / 4;
> +		if (ldpc_dec->harq_combined_input.length > max_harq_input) {
> +			rte_bbdev_log(ERR,
> +					"HARQ input size out of range %d > %d, Ncb %d F %d K %d N %d",
> +					ldpc_dec->harq_combined_input.length,
> +					max_harq_input, ldpc_dec->n_cb,
> +					ldpc_dec->n_filler, K, N);
> +			/* Fallback to flush HARQ combine */
> +			ldpc_dec->harq_combined_input.length = 0;
> +			if (check_bit(op->ldpc_dec.op_flags,
> +					RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
> +				op->ldpc_dec.op_flags ^=
> +					RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE;
> +			}
> +		}
> +	}
> +
> +#ifdef ACC100_EXT_MEM
> +	/* Enforce in-range HARQ offset */
> +	if (check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
> +		if ((op->ldpc_dec.harq_combined_input.offset >> 10)
> +				>= q->d->ddr_size) {
> +			rte_bbdev_log(ERR,
> +				"HARQin offset out of range %d > %d",
> +				op->ldpc_dec.harq_combined_input.offset,
> +				q->d->ddr_size);
> +			return -1;
> +		}
> +		if ((op->ldpc_dec.harq_combined_input.offset & 0x3FF) > 0) {
> +			rte_bbdev_log(ERR,
> +				"HARQin offset not aligned on 1kB %d",
> +				op->ldpc_dec.harq_combined_input.offset);
> +			return -1;
> +		}
> +	}
> +	if (check_bit(op->ldpc_dec.op_flags,
> +			RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE)) {
> +		if ((op->ldpc_dec.harq_combined_output.offset >> 10)
> +				>= q->d->ddr_size) {
> +			rte_bbdev_log(ERR,
> +				"HARQout offset out of range %d > %d",
> +				op->ldpc_dec.harq_combined_output.offset,
> +				q->d->ddr_size);
> +			return -1;
> +		}
> +		if ((op->ldpc_dec.harq_combined_output.offset & 0x3FF) > 0) {
> +			rte_bbdev_log(ERR,
> +				"HARQout offset not aligned on 1kB %d",
> +				op->ldpc_dec.harq_combined_output.offset);
> +			return -1;
> +		}
> +	}
> +#endif
> +
>   	return 0;
>   }
>   #endif
  

Patch

diff --git a/drivers/baseband/acc100/rte_acc100_pmd.c b/drivers/baseband/acc100/rte_acc100_pmd.c
index e47f7d68c2..1504acfadd 100644
--- a/drivers/baseband/acc100/rte_acc100_pmd.c
+++ b/drivers/baseband/acc100/rte_acc100_pmd.c
@@ -2404,10 +2404,6 @@  validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
 	if (!validate_op_required(q))
 		return 0;
 
-	if (op->mempool == NULL) {
-		rte_bbdev_log(ERR, "Invalid mempool pointer");
-		return -1;
-	}
 	if (ldpc_enc->input.data == NULL) {
 		rte_bbdev_log(ERR, "Invalid input pointer");
 		return -1;
@@ -2416,11 +2412,9 @@  validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
 		rte_bbdev_log(ERR, "Invalid output pointer");
 		return -1;
 	}
-	if (ldpc_enc->input.length >
-			RTE_BBDEV_LDPC_MAX_CB_SIZE >> 3) {
-		rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
-				ldpc_enc->input.length,
-				RTE_BBDEV_LDPC_MAX_CB_SIZE);
+	if (ldpc_enc->input.length == 0) {
+		rte_bbdev_log(ERR, "CB size (%u) is null",
+				ldpc_enc->input.length);
 		return -1;
 	}
 	if ((ldpc_enc->basegraph > 2) || (ldpc_enc->basegraph == 0)) {
@@ -2441,13 +2435,107 @@  validate_ldpc_enc_op(struct rte_bbdev_enc_op *op, struct acc100_queue *q)
 				ldpc_enc->code_block_mode);
 		return -1;
 	}
+	if (ldpc_enc->z_c > 384) {
+		rte_bbdev_log(ERR,
+				"Zc (%u) is out of range",
+				ldpc_enc->z_c);
+		return -1;
+	}
 	int K = (ldpc_enc->basegraph == 1 ? 22 : 10) * ldpc_enc->z_c;
-	if (ldpc_enc->n_filler >= K) {
+	int N = (ldpc_enc->basegraph == 1 ? ACC100_N_ZC_1 : ACC100_N_ZC_2)
+			* ldpc_enc->z_c;
+	int q_m = ldpc_enc->q_m;
+	int crc24 = 0;
+
+	if (check_bit(op->ldpc_enc.op_flags,
+			RTE_BBDEV_LDPC_CRC_24A_ATTACH) ||
+			check_bit(op->ldpc_enc.op_flags,
+			RTE_BBDEV_LDPC_CRC_24B_ATTACH))
+		crc24 = 24;
+	if ((K - ldpc_enc->n_filler) % 8 > 0) {
 		rte_bbdev_log(ERR,
-				"K and F are not compatible %u %u",
+				"K - F not byte aligned %u",
+				K - ldpc_enc->n_filler);
+		return -1;
+	}
+	if (ldpc_enc->n_filler > (K - 2 * ldpc_enc->z_c)) {
+		rte_bbdev_log(ERR,
+				"K - F invalid %u %u",
 				K, ldpc_enc->n_filler);
 		return -1;
 	}
+	if ((ldpc_enc->n_cb > N) || (ldpc_enc->n_cb <= K)) {
+		rte_bbdev_log(ERR,
+				"Ncb (%u) is out of range K  %d N %d",
+				ldpc_enc->n_cb, K, N);
+		return -1;
+	}
+	if (!check_bit(op->ldpc_enc.op_flags,
+			RTE_BBDEV_LDPC_INTERLEAVER_BYPASS) &&
+			((q_m == 0) || ((q_m > 2) && ((q_m % 2) == 1))
+			|| (q_m > 8))) {
+		rte_bbdev_log(ERR,
+				"Qm (%u) is out of range",
+				ldpc_enc->q_m);
+		return -1;
+	}
+	if (ldpc_enc->code_block_mode == RTE_BBDEV_CODE_BLOCK) {
+		if (ldpc_enc->cb_params.e == 0) {
+			rte_bbdev_log(ERR,
+					"E is null");
+			return -1;
+		}
+		if (q_m > 0) {
+			if (ldpc_enc->cb_params.e % q_m > 0) {
+				rte_bbdev_log(ERR,
+						"E not multiple of qm %d", q_m);
+				return -1;
+			}
+		}
+		if ((ldpc_enc->z_c <= 11) && (ldpc_enc->cb_params.e > 3456)) {
+			rte_bbdev_log(ERR,
+					"E too large for small block");
+			return -1;
+		}
+		if (ldpc_enc->input.length >
+			RTE_BBDEV_LDPC_MAX_CB_SIZE >> 3) {
+			rte_bbdev_log(ERR, "CB size (%u) is too big, max: %d",
+					ldpc_enc->input.length,
+					RTE_BBDEV_LDPC_MAX_CB_SIZE);
+		return -1;
+		}
+		if (K < (int) (ldpc_enc->input.length * 8
+				+ ldpc_enc->n_filler) + crc24) {
+			rte_bbdev_log(ERR,
+					"K and F not matching input size %u %u %u",
+					K, ldpc_enc->n_filler,
+					ldpc_enc->input.length);
+			return -1;
+		}
+	} else {
+		if ((ldpc_enc->tb_params.c == 0) ||
+				(ldpc_enc->tb_params.ea == 0) ||
+				(ldpc_enc->tb_params.eb == 0)) {
+			rte_bbdev_log(ERR,
+					"TB parameter is null");
+			return -1;
+		}
+		if (q_m > 0) {
+			if ((ldpc_enc->tb_params.ea % q_m > 0) ||
+					(ldpc_enc->tb_params.eb % q_m > 0)) {
+				rte_bbdev_log(ERR,
+						"E not multiple of qm %d",
+						q_m);
+				return -1;
+			}
+		}
+		if ((ldpc_enc->z_c <= 11) && (RTE_MAX(ldpc_enc->tb_params.ea,
+				ldpc_enc->tb_params.eb) > 3456)) {
+			rte_bbdev_log(ERR,
+					"E too large for small block");
+			return -1;
+		}
+	}
 	return 0;
 }
 
@@ -2460,8 +2548,16 @@  validate_ldpc_dec_op(struct rte_bbdev_dec_op *op, struct acc100_queue *q)
 	if (!validate_op_required(q))
 		return 0;
 
-	if (op->mempool == NULL) {
-		rte_bbdev_log(ERR, "Invalid mempool pointer");
+	if (ldpc_dec->input.data == NULL) {
+		rte_bbdev_log(ERR, "Invalid input pointer");
+		return -1;
+	}
+	if (ldpc_dec->hard_output.data == NULL) {
+		rte_bbdev_log(ERR, "Invalid output pointer");
+		return -1;
+	}
+	if (ldpc_dec->input.length == 0) {
+		rte_bbdev_log(ERR, "input is null");
 		return -1;
 	}
 	if ((ldpc_dec->basegraph > 2) || (ldpc_dec->basegraph == 0)) {
@@ -2488,13 +2584,186 @@  validate_ldpc_dec_op(struct rte_bbdev_dec_op *op, struct acc100_queue *q)
 				ldpc_dec->code_block_mode);
 		return -1;
 	}
+	/* Check Zc is valid value */
+	if ((ldpc_dec->z_c > 384) || (ldpc_dec->z_c < 2)) {
+		rte_bbdev_log(ERR,
+				"Zc (%u) is out of range",
+				ldpc_dec->z_c);
+		return -1;
+	}
+	if (ldpc_dec->z_c > 256) {
+		if ((ldpc_dec->z_c % 32) != 0) {
+			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
+			return -1;
+		}
+	} else if (ldpc_dec->z_c > 128) {
+		if ((ldpc_dec->z_c % 16) != 0) {
+			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
+			return -1;
+		}
+	} else if (ldpc_dec->z_c > 64) {
+		if ((ldpc_dec->z_c % 8) != 0) {
+			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
+			return -1;
+		}
+	} else if (ldpc_dec->z_c > 32) {
+		if ((ldpc_dec->z_c % 4) != 0) {
+			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
+			return -1;
+		}
+	} else if (ldpc_dec->z_c > 16) {
+		if ((ldpc_dec->z_c % 2) != 0) {
+			rte_bbdev_log(ERR, "Invalid Zc %d", ldpc_dec->z_c);
+			return -1;
+		}
+	}
 	int K = (ldpc_dec->basegraph == 1 ? 22 : 10) * ldpc_dec->z_c;
-	if (ldpc_dec->n_filler >= K) {
+	int N = (ldpc_dec->basegraph == 1 ? ACC100_N_ZC_1 : ACC100_N_ZC_2)
+			* ldpc_dec->z_c;
+	int q_m = ldpc_dec->q_m;
+	if (ldpc_dec->n_filler >= K - 2 * ldpc_dec->z_c) {
 		rte_bbdev_log(ERR,
 				"K and F are not compatible %u %u",
 				K, ldpc_dec->n_filler);
 		return -1;
 	}
+	if ((ldpc_dec->n_cb > N) || (ldpc_dec->n_cb <= K)) {
+		rte_bbdev_log(ERR,
+				"Ncb (%u) is out of range K  %d N %d",
+				ldpc_dec->n_cb, K, N);
+		return -1;
+	}
+
+	if (((q_m == 0) || ((q_m > 2) && ((q_m % 2) == 1))
+			|| (q_m > 8))) {
+		rte_bbdev_log(ERR,
+				"Qm (%u) is out of range",
+				ldpc_dec->q_m);
+		return -1;
+	}
+	if (ldpc_dec->code_block_mode == RTE_BBDEV_CODE_BLOCK) {
+		if (ldpc_dec->cb_params.e == 0) {
+			rte_bbdev_log(ERR,
+					"E is null");
+			return -1;
+		}
+		if (ldpc_dec->cb_params.e % q_m > 0) {
+			rte_bbdev_log(ERR,
+					"E not multiple of qm %d", q_m);
+			return -1;
+		}
+		if (ldpc_dec->cb_params.e > 512 * ldpc_dec->z_c) {
+			rte_bbdev_log(ERR,
+					"E too high");
+			return -1;
+		}
+	} else {
+		if ((ldpc_dec->tb_params.c == 0) ||
+				(ldpc_dec->tb_params.ea == 0) ||
+				(ldpc_dec->tb_params.eb == 0)) {
+			rte_bbdev_log(ERR,
+					"TB parameter is null");
+			return -1;
+		}
+		if ((ldpc_dec->tb_params.ea % q_m > 0) ||
+				(ldpc_dec->tb_params.eb % q_m > 0)) {
+			rte_bbdev_log(ERR,
+					"E not multiple of qm %d", q_m);
+			return -1;
+		}
+		if ((ldpc_dec->tb_params.ea > 512 * ldpc_dec->z_c) ||
+				(ldpc_dec->tb_params.eb > 512 * ldpc_dec->z_c)) {
+			rte_bbdev_log(ERR,
+					"E too high");
+			return -1;
+		}
+	}
+	if (check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_DECODE_BYPASS)) {
+		rte_bbdev_log(ERR, "Avoid LDPC Decode bypass");
+		return -1;
+	}
+
+	/* Avoid HARQ compression for small block size */
+	if ((check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION))
+			&& (K < 2048)) {
+		op->ldpc_dec.op_flags ^= RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION;
+	}
+	uint32_t min_harq_input = check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION) ? 256 : 64;
+	if (check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE) &&
+			ldpc_dec->harq_combined_input.length <
+			min_harq_input) {
+		rte_bbdev_log(ERR, "HARQ input size is too small %d < %d",
+			ldpc_dec->harq_combined_input.length,
+			min_harq_input);
+		return -1;
+	}
+
+	/* Enforce in-range HARQ input size */
+	if (check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
+		uint32_t max_harq_input = RTE_ALIGN_CEIL(ldpc_dec->n_cb -
+				ldpc_dec->n_filler, 64);
+		if (check_bit(op->ldpc_dec.op_flags,
+				RTE_BBDEV_LDPC_HARQ_6BIT_COMPRESSION))
+			max_harq_input = max_harq_input * 3 / 4;
+		if (ldpc_dec->harq_combined_input.length > max_harq_input) {
+			rte_bbdev_log(ERR,
+					"HARQ input size out of range %d > %d, Ncb %d F %d K %d N %d",
+					ldpc_dec->harq_combined_input.length,
+					max_harq_input, ldpc_dec->n_cb,
+					ldpc_dec->n_filler, K, N);
+			/* Fallback to flush HARQ combine */
+			ldpc_dec->harq_combined_input.length = 0;
+			if (check_bit(op->ldpc_dec.op_flags,
+					RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
+				op->ldpc_dec.op_flags ^=
+					RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE;
+			}
+		}
+	}
+
+#ifdef ACC100_EXT_MEM
+	/* Enforce in-range HARQ offset */
+	if (check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE)) {
+		if ((op->ldpc_dec.harq_combined_input.offset >> 10)
+				>= q->d->ddr_size) {
+			rte_bbdev_log(ERR,
+				"HARQin offset out of range %d > %d",
+				op->ldpc_dec.harq_combined_input.offset,
+				q->d->ddr_size);
+			return -1;
+		}
+		if ((op->ldpc_dec.harq_combined_input.offset & 0x3FF) > 0) {
+			rte_bbdev_log(ERR,
+				"HARQin offset not aligned on 1kB %d",
+				op->ldpc_dec.harq_combined_input.offset);
+			return -1;
+		}
+	}
+	if (check_bit(op->ldpc_dec.op_flags,
+			RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE)) {
+		if ((op->ldpc_dec.harq_combined_output.offset >> 10)
+				>= q->d->ddr_size) {
+			rte_bbdev_log(ERR,
+				"HARQout offset out of range %d > %d",
+				op->ldpc_dec.harq_combined_output.offset,
+				q->d->ddr_size);
+			return -1;
+		}
+		if ((op->ldpc_dec.harq_combined_output.offset & 0x3FF) > 0) {
+			rte_bbdev_log(ERR,
+				"HARQout offset not aligned on 1kB %d",
+				op->ldpc_dec.harq_combined_output.offset);
+			return -1;
+		}
+	}
+#endif
+
 	return 0;
 }
 #endif